ESP32双核Core0执行程序时串口设置的频率变量被复位为0问题求助
问题根因
- 非法栈访问篡改全局变量:你当前的逻辑是每次loop循环无论是否收到新串口数据,都会执行变长数组
charBuf的创建、字符串转换和报文判断。当无新报文时incomSting为空,栈上分配的charBuf内存残留旧脏数据,大概率会误触发if(charBuf[0]=='S')的判断。后续strtok返回空指针时sscanf触发未定义行为,直接把频率变量、flag变量改写为0,严重时栈溢出直接覆盖全局变量内存。 - 串口接收逻辑错误:
while(Serial.available() > 1)的判断多余且不合理,Serial.readStringUntil('?')本身会读取直到遇到终止符或超时,你没有判断读取到的报文是否有效。 - 变量修饰缺失:全局变量
StepNr在Core0中持续修改,但未加volatile修饰,可能被编译器错误优化导致逻辑异常。 - 无容错机制:未处理报文格式错误、
strtok返回空的异常场景,一旦收到非法报文就会写坏变量。
修复方案
- 把报文解析逻辑完全移到串口读取成功的分支内,仅当收到有效报文时才执行解析,避免无意义的栈操作。
- 给
StepNr添加volatile修饰,保证跨核访问的正确性。 - 增加报文合法性校验,确认
strtok返回值非空再执行sscanf。 - 可选优化:使用FreeRTOS互斥锁保护共享变量,或者用队列传递参数,彻底避免跨核直接读写全局变量的风险。
修复后代码示例
// STEPPER int delaytime = 100; volatile int StepNr = 0; // 加volatile修饰 String incomSting = ""; int Stepper1Pin = 12; int Stepper2Pin = 14; int Stepper3Pin = 27; volatile int percentStp1 = 0; volatile int percentStp2 = 0; volatile int percentStp3 = 0; volatile int flag = 0; TaskHandle_t Task1; void Task1code(void * parameter) { for(;;) { while (flag == 1){ //Run Steppers if(percentStp1 > StepNr) { digitalWrite(Stepper1Pin, HIGH); } if(percentStp2 > StepNr) { digitalWrite(Stepper2Pin, HIGH); } if(percentStp3 > StepNr) { digitalWrite(Stepper3Pin, HIGH); } StepNr++; delayMicroseconds(delaytime); digitalWrite(Stepper1Pin, LOW); digitalWrite(Stepper2Pin, LOW); digitalWrite(Stepper3Pin, LOW); delayMicroseconds(delaytime); Serial.println(percentStp1); if(StepNr > 100) { StepNr = 0; } } // 空转加延时避免Core0占用过高 delay(1); } } void setup() { Serial.begin(9600); Serial.println("Start"); //STEPPER xTaskCreatePinnedToCore(Task1code, "Task1", 10000, NULL, 0 , &Task1, 0); pinMode(Stepper1Pin, OUTPUT); pinMode(Stepper2Pin, OUTPUT); pinMode(Stepper3Pin, OUTPUT); } void loop() { // 仅当有串口数据时才读取 if(Serial.available()) { incomSting = Serial.readStringUntil('?'); // 校验报文有效性 if(incomSting.length() > 0 && incomSting[0] == 'S') { char charBuf[incomSting.length() + 1]; incomSting.toCharArray(charBuf, incomSting.length() + 1); charBuf[0]='0'; Serial.println("Stepper"); char *pch = strtok(charBuf,";"); if(pch != NULL) sscanf(pch, "%d", &percentStp1); pch = strtok (NULL, ";"); if(pch != NULL) sscanf(pch, "%d", &percentStp2); pch = strtok (NULL, ";"); if(pch != NULL) sscanf(pch, "%d", &percentStp3); Serial.print("S1:"); Serial.println(percentStp1); Serial.print("S2:"); Serial.println(percentStp2); Serial.print("S3:"); Serial.println(percentStp3); incomSting = ""; flag = 1; } } }
内容的提问来源于stack exchange,提问作者user16705270
相关产品推荐
相关产品推荐

