通过 arduino 的 ENC28J60 模块发布 JSON 时出现奇怪的行为

Weird behaviour while POSTing a JSON through arduino's ENC28J60 module

我已经成功地通过我的 Arduino 设置了一个函数来 POST JSON 数据。我正在使用 webhook 对其进行测试,但我遇到了一些奇怪的行为。 JSON 数据未在我期望的位置创建。任何解释这一点的帮助将不胜感激。

#include <EtherCard.h>

// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };

byte Ethernet::buffer[700];
static uint32_t timer;

const char website[] PROGMEM = "webhook.site"; //my router's address

// called when the client request is complete
static void my_callback (byte status, word off, word len) {
  Serial.println(">>>");
  Ethernet::buffer[off+300] = 0;
  Serial.print((const char*) Ethernet::buffer + off);
  Serial.println("...");
}

void setup () {
  Serial.begin(57600);
  Serial.println("\n[webClient]");

  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
      Serial.println("x{\"city\":\"Paris\",\"temp\":18.5}"); /// << JSON message is created here, and the first character of the message is removed
  if (!ether.dhcpSetup())
//    Serial.println("DHCP failed");

  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip); 
  ether.printIp("DNS: ", ether.dnsip); 

  if (!ether.dnsLookup(website))
//    Serial.println("DNS failed");

  ether.printIp("SRV: ", ether.hisip);
}

void loop () {
  ether.packetLoop(ether.packetReceive());

  if (millis() > timer) {
    timer = millis() + 5000;
    Serial.println();
    Serial.print("<<< REQ ");
    ether.httpPost(PSTR("/fe6f00eb-30ed-4b59-8908-fa3ec13c2485"), website, PSTR("Content-Type: application/json"),
       PSTR(""), my_callback); // PSTR("") because the message is created after .begin function is called
    }
}

Arduino 有两个完全独立的地址空间:程序内存和 RAM。通常,指针指向 RAM。

PSTR("hello") 将字符串 "hello" 放入程序存储器,returns 将其地址放入程序存储器。如果你从这个指针读取,你实际上是从同一位置的数据存储器读取,并得到一些完全不相关的数据。您需要使用 pgm_read_byte 从程序内存中读取(ENC28J60 库不会这样做)。

您的 PSTR("") 恰好与您在 setup 中打印的字符串的第二个字节具有相同的地址。

解决方案是删除 POST 数据周围的 PSTR()

我不确定是否记录了哪些参数需要在程序内存中,但我找到了读取它们的函数 here。看起来 $F 意味着从程序存储器中读取一个字符串,而 $S 意味着从 RAM 中读取一个字符串。使用 $S.

读取 client_postval