Arduino如何将串口输入存入char数组并提取指定字符间内容?
嗨,我来帮你搞定这个串口适配的问题!你的原代码能正确提取静态字符串里的目标内容,但要适配串口输入,核心是要先解决串口流式数据的缓存问题——毕竟串口是逐字节接收的,不能直接像处理静态char*那样直接用strstr。另外先提一句原代码里的内存管理小bug,避免后续运行出问题。
先修复原代码的内存错误
你原代码里的target = ""; free(target);是有问题的:把target指向了常量字符串后再free,会触发未定义行为。正确的内存释放逻辑应该是:
if (target != NULL) { free(target); target = NULL; // 释放后置空,避免野指针 }
串口适配的核心思路
串口是逐字节接收数据,我们需要先把接收到的字节缓存到一个缓冲区里,直到确认收到了完整的数据包(比如可以通过超时判断、或者指定结束符,比如你示例里的#,或者约定数据包长度),再对缓冲区的完整字符串执行提取逻辑。
完整的适配代码示例
下面是适配串口的完整代码,我加了详细注释:
// 定义串口缓冲区,大小根据你的需求调整,这里设256字节 #define SERIAL_BUFFER_SIZE 256 char serialBuffer[SERIAL_BUFFER_SIZE]; int bufferIndex = 0; const char *CHAR1 = "!"; const char *CHAR2 = "#"; char *target = NULL; void setup() { Serial.begin(9600); // 初始化缓冲区 memset(serialBuffer, 0, SERIAL_BUFFER_SIZE); } void loop() { // 读取串口数据,直到缓冲区满或者没有数据 while (Serial.available() > 0 && bufferIndex < SERIAL_BUFFER_SIZE - 1) { char receivedChar = Serial.read(); serialBuffer[bufferIndex++] = receivedChar; // 可选:如果我们知道数据包以某个字符结尾(比如#),可以在这里判断提前结束接收 if (receivedChar == '#') { break; } } // 只有当缓冲区有数据时,才执行提取逻辑 if (bufferIndex > 0) { // 给缓冲区加上字符串终止符,变成合法的C字符串 serialBuffer[bufferIndex] = '\0'; char *start, *end; if ((start = strstr(serialBuffer, CHAR1)) != NULL) { start += strlen(CHAR1); if ((end = strstr(start, CHAR2)) != NULL) { // 分配内存存储目标内容 if (target != NULL) { free(target); // 先释放之前的内存,避免泄漏 target = NULL; } target = (char*)malloc(end - start + 1); if (target != NULL) { // 检查malloc是否成功 memcpy(target, start, end - start); target[end - start] = '\0'; // 输出目标内容 Serial.print("提取到的内容:"); Serial.println(target); } } } // 重置缓冲区,准备接收下一包数据 bufferIndex = 0; memset(serialBuffer, 0, SERIAL_BUFFER_SIZE); } // 程序空闲时的延迟,避免占用过多资源 delay(10); }
代码说明
- 串口缓存:用
serialBuffer存储接收到的所有字节,bufferIndex记录当前存储的位置,确保不会溢出缓冲区。 - 结束判断:我加了一个判断,如果收到
#就停止接收,这样能更快处理完整数据包;如果你的数据包没有固定结束符,可以改成超时判断(比如超过100ms没收到新数据就认为是完整数据包)。 - 内存管理:每次提取前先释放之前的
target内存,避免内存泄漏;并且检查malloc是否成功,防止内存分配失败导致的问题。 - 兼容性:这个代码既可以处理串口输入,也可以轻松改回处理静态
char*(只需要把serialBuffer换成你的静态字符串即可)。
内容的提问来源于stack exchange,提问作者ReduX Completedy
相关产品推荐
相关产品推荐

