You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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任务负责读取它,多线程同时访问会存在竞争条件,可能导致数据错乱。需要添加互斥锁保护:

  1. 定义全局互斥锁:
SemaphoreHandle_t messMutex;
  1. 在setup中初始化互斥锁:
void setup(){
  // ... 其他初始化代码
  messMutex = xSemaphoreCreateMutex();
}
  1. 在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);
        }
      }
    }
    // ... 其他代码
  }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 16:28:07