我正在建立一个系统,通过SoftwareSerial从Arduino Uno读取传感器值,并通过MQTT发布。但是,我认为我面临的问题更为笼统,我必须承认我是新手。
我……
从您的代码:
char* data; ... *data = strtok(receivedChars, s);
strtok的 回来一个 char* 但你做了 *data = strtok(...) 而 数据 本身是一个(未初始化) char * ,这是不一致的,你有第一次“机会”发生崩溃,因为你在随机地址写。
char*
*data = strtok(...)
char *
如果您没有崩溃,您的程序可以继续 数据 不会自行修改并保持未初始化状态。
在
strcpy( publishText, data ); ... Serial.print(data);
当你使用 数据 作为一个 char* 干 Serial.print(data); 和 strcpy( publishText, data ); 你从一个随机(当然也是无效的)地址读取,导致你的崩溃。
Serial.print(data);
strcpy( publishText, data );
纠正只是更换 *data = strtok(receivedChars, s); 通过 data = strtok(receivedChars, s);
*data = strtok(receivedChars, s);
data = strtok(receivedChars, s);
修好了作业 strtok 的结果是 data 如布鲁诺的回答所示,还有另一个可能导致崩溃的错误。
strtok
data
你的功能 loop() 电话 recvWithStartEndMarkers() 首先,然后 publishReceived() 。
loop()
recvWithStartEndMarkers()
publishReceived()
void loop() { client.loop(); recvWithStartEndMarkers(); showNewData(); publishReceived(); }
在功能上 recvWithStartEndMarkers 您将一些数据读入本地数组 receivedChars 把它喂进去 strtok 并写一个从中返回的指针 strtok 到全局变量 data 。
recvWithStartEndMarkers
receivedChars
void recvWithStartEndMarkers() { int numChars = 32; char receivedChars[numChars]; /* this is a local variable with automatic storage */ /* ... */ while (Serial.available() > 0 && newData == false) { /* ... */ receivedChars[ndx] = rc; ndx++; if (ndx >= numChars) { ndx = numChars - 1; } /* ... */ receivedChars[ndx] = '\0'; // terminate the string /* Now there is a terminated string in the local variable */ /* ... */ //Split the string /* ... */ const char s[2] = ":"; data = strtok(receivedChars, s); /* strtok modifies the input in receivedChars and returns a pointer to parts of this array. */ /* ... */ }
离开功能后的内存 receivedChars 不再有效。这意味着 data 将指向堆栈上的此无效内存。
稍后您想要访问全局变量 data 在一个功能 publishReceived() 。访问此内存是未指定的行为。你可能仍然得到数据,你可能得到别的东西或你的程序可能会崩溃。
void publishReceived() { /* ... */ char publishText[30]; //TODO: make it JSON strcpy( publishText, data ); /* This will try to copy whatever is now in the memory that was part of receivedChars inside recvWithStartEndMarkers() but may now contain something else, e.g. local data of function publishReceived(). */ /* ... */
要解决此问题,您可以使用 strdup 在 recvWithStartEndMarkers() :
strdup
data = strtok(receivedChars, s); if(data != NULL) data = strdup(data);
然后你必须 free(data) 当你不再需要数据或在调用之前的某个地方 recvWithStartEndMarkers() 再次。
free(data)
或者做 data 一个数组和使用 strncpy 在 recvWithStartEndMarkers() 。
strncpy