ESP32 FreeRTOS中char指针线程参数读取异常问题求助
ESP32 FreeRTOS线程参数读取异常问题求助
在ESP32的FreeRTOS环境下开发时遇到线程参数相关问题,遍寻各类论坛未找到解决方案。代码需要在LED点阵中打印变量,但出现异常:尝试以char指针读取线程参数时,值为0,但直接读取该char值时却能得到正确结果。希望获得该问题的解决方案。
//Librerias #include <Arduino.h> #include "Wire.h" #include "RTClib.h" #include <MD_MAX72xx.h> #include <SPI.h> //Blinking rate in milliseconds const portTickType TIMESTOP=1; const portTickType TIMETAX=1; const portTickType TIMERTC=1; const portTickType TIMEREFREHS=1; //Defines #define HARDWARE_TYPE MD_MAX72XX::FC16_HW #define MAX_DEVICES 4 #define CHAR_SPACING 1 //Pines #define CLK_PIN 18 #define DATA_PIN 23 #define CS_PIN 5 MD_MAX72XX mx=MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); RTC_DS1307 DS1307_RTC; //Variables externas char mess[4]; char Week_days[7][12]={"Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado"}; char numbers[10]={48, 49, 50, 51, 52, 53, 54, 55, 56, 57}; bool flagDorN; bool flagTorD; bool banner; int time_24s; int distance=0; int unitsNT=28; int priceNT=2912; int unitsT=52; int priceT=5408; int timeSeconds=0; int cent; int dec; int unit; int DMALHMS[7]; String dayT; String hourT; void setup(){ Serial.begin(9600); mx.begin(); if(!DS1307_RTC.begin()){ while(1); } DS1307_RTC.adjust(DateTime(F(__DATE__), F(__TIME__))); //Variables internas banner=1; flagTorD=0; //Hilos xTaskCreate(Time24s, "Time24s", 1024, NULL, 1, NULL); xTaskCreate(Taximeter, "Taximeter", 1024, NULL, 1, NULL); xTaskCreate(Fun_DMALHMS, "Fun_DMALHMS", 2048, NULL, 1, NULL); xTaskCreate(printTextUnitsT, "printTextUnitsT", 2048, (void*)&mess, 1, NULL); } void loop(){ delay(1); } void Time24s(void* args){ while(true){ if(flagTorD==0){ time_24s=time_24s+1; } vTaskDelay(TIMESTOP); } } void Taximeter(void* args){ while(true){ if(banner==1){ if(DMALHMS[3]==0 || 20<=DMALHMS[4] || DMALHMS[4]<=5){ cent=unitsT/100; dec=(unitsT-(cent*100))/10; unit=(unitsT-(cent*100+dec*10)); for(int i=0; i<=9; i++){ if(i==cent){ mess[0]=char(numbers[i]); } if(i==dec){ mess[1]=char(numbers[i]); } if(i==unit){ mess[2]=char(numbers[i]); } mess[3]='\0'; } } } if(time_24s==24000){ time_24s=0; Serial.println(dayT); Serial.println(hourT); } vTaskDelay(TIMETAX); } } void Fun_DMALHMS(void* args){ while(true){ DateTime now=DS1307_RTC.now(); DMALHMS[0]=now.day(); DMALHMS[1]=now.month(); DMALHMS[2]=now.year(); DMALHMS[3]=now.dayOfTheWeek(); DMALHMS[4]=now.hour(); DMALHMS[5]=now.minute(); DMALHMS[6]=now.second(); dayT=String(DMALHMS[0])+"/"+String(DMALHMS[1])+"/"+String(DMALHMS[2]); hourT=String(DMALHMS[4])+":"+String(DMALHMS[5])+":"+String(DMALHMS[6]); vTaskDelay(TIMERTC); } } void printTextUnitsT(void *args){ while(true){ char *vars=(char*)args; Serial.print("(char*)args "); Serial.println((char*)args); Serial.print("*(char*)args "); Serial.println(*(char*)args); uint8_t state=0; uint8_t curLen; uint16_t showLen; uint8_t cBuf[8]; int16_t col=(((uint8_t(MAX_DEVICES-1) + 1) * COL_SIZE)-1)-7; mx.control(uint8_t(0), uint8_t(MAX_DEVICES-1), MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); do{ switch(state){ case 0: if((*vars)=='\0'){ showLen=col-(uint8_t(MAX_DEVICES-1)*COL_SIZE); state=2; break; } showLen=mx.getChar((*vars), sizeof(cBuf)/sizeof(cBuf[0]), cBuf); curLen=0; state++; case 1: mx.setColumn(col--, cBuf[curLen++]); if (curLen==showLen){ showLen=CHAR_SPACING; state=2; } break; case 2: curLen=0; state++; case 3: mx.setColumn(col--, 0); curLen++; if(curLen==showLen) state=0; break; default: col=-1; } }while(col>=(uint8_t(0)*COL_SIZE)); mx.control(uint8_t(0), uint8_t(MAX_DEVICES-1), MD_MAX72XX::UPDATE, MD_MAX72XX::ON); vTaskDelay(TIMEREFREHS); } }
串口输出显示:
(char*)args输出为空(值为0),*(char*)args能输出正确的字符值。
尝试过以下错误转换写法,未解决问题:
char vars=malloc(sizeof(char *args))
问题分析与解决方案
核心问题
创建printTextUnitsT任务时,传递的参数是&mess,这是一个指向长度为4的char数组的指针(类型为char (*)[4]),但在任务函数里错误地将其转换为char*(指向单个char的指针),导致指针类型不匹配,读取到错误的内存地址。
解决方法1:修正参数传递方式
创建任务时直接传递数组名mess,数组名会自动退化为指向数组首元素的char*指针,类型匹配:
// 修改setup中的任务创建代码 xTaskCreate(printTextUnitsT, "printTextUnitsT", 2048, mess, 1, NULL);
任务函数内的char *vars=(char*)args;无需修改,此时vars正确指向mess数组的首元素。
解决方法2:正确转换数组指针类型
如果坚持传递&mess,需要在任务函数里将void*转换为对应的数组指针类型:
void printTextUnitsT(void *args){ while(true){ // 转换为指向长度为4的char数组的指针 char (*vars)[4] = (char (*)[4])args; // 访问数组元素时使用(*vars)[index] Serial.print("数组首元素:"); Serial.println((*vars)[0]); // 后续处理代码中,将原有的*vars替换为(*vars)[0],依次访问其他元素 // ... } }
额外注意:线程安全
mess是全局变量,Taximeter任务负责修改它,printTextUnitsT任务负责读取它,多线程同时访问会存在竞争条件,可能导致数据错乱。需要添加互斥锁保护:
- 定义全局互斥锁:
SemaphoreHandle_t messMutex;
- 在
setup中初始化互斥锁:
void setup(){ // ... 其他初始化代码 messMutex = xSemaphoreCreateMutex(); }
- 在
Taximeter任务中修改mess前加锁:
void Taximeter(void* args){ while(true){ if(banner==1){ if(DMALHMS[3]==0 || 20<=DMALHMS[4] || DMALHMS[4]<=5){ // 获取互斥锁,等待直到获取成功 if(xSemaphoreTake(messMutex, portMAX_DELAY) == pdTRUE){ cent=unitsT/100; dec=(unitsT-(cent*100))/10; unit=(unitsT-(cent*100+dec*10)); for(int i=0; i<=9; i++){ if(i==cent){ mess[0]=char(numbers[i]); } if(i==dec){ mess[1]=char(numbers[i]); } if(i==unit){ mess[2]=char(numbers[i]); } mess[3]='\0'; } // 释放互斥锁 xSemaphoreGive(messMutex); } } } // ... 其他代码 } }
- 在
printTextUnitsT任务中读取mess前加锁:
void printTextUnitsT(void *args){ while(true){ char *vars=(char*)args; // 获取互斥锁 if(xSemaphoreTake(messMutex, portMAX_DELAY) == pdTRUE){ Serial.print("(char*)args "); Serial.println(vars); Serial.print("*(char*)args "); Serial.println(*vars); // 后续LED点阵打印代码 uint8_t state=0; uint8_t curLen; uint16_t showLen; uint8_t cBuf[8]; int16_t col=(((uint8_t(MAX_DEVICES-1) + 1) * COL_SIZE)-1)-7; mx.control(uint8_t(0), uint8_t(MAX_DEVICES-1), MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); do{ switch(state){ case 0: if((*vars)=='\0'){ showLen=col-(uint8_t(MAX_DEVICES-1)*COL_SIZE); state=2; break; } showLen=mx.getChar((*vars), sizeof(cBuf)/sizeof(cBuf[0]), cBuf); curLen=0; state++; case 1: mx.setColumn(col--, cBuf[curLen++]); if (curLen==showLen){ showLen=CHAR_SPACING; state=2; } break; case 2: curLen=0; state++; case 3: mx.setColumn(col--, 0); curLen++; if(curLen==showLen) state=0; break; default: col=-1; } }while(col>=(uint8_t(0)*COL_SIZE)); mx.control(uint8_t(0), uint8_t(MAX_DEVICES-1), MD_MAX72XX::UPDATE, MD_MAX72XX::ON); // 释放互斥锁 xSemaphoreGive(messMutex); } vTaskDelay(TIMEREFREHS); } }
内容的提问来源于stack exchange,提问作者AngelNicolas
相关产品推荐
相关产品推荐

