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

ESP32 Wrover模块FreeRTOS队列发送两次消息触发LoadProhibited Guru Meditation Error求助

问题根源分析

你的问题核心出在任务参数的内存生命周期上!

看你的setup函数里,sensorTaskDescriptor是一个栈上的局部变量:

const ReadSensorsParameters sensorTaskDescriptor{ &debugMsgQueue,&sensorDataBufQueue,&sensorTaskWatchdog,rtc};

setup函数执行完毕后,这个局部变量所在的栈空间会被系统回收。而你把这个结构体的地址传给了ReadSensors任务,当任务开始运行(尤其是第二次发送队列时),原来的栈内存已经被覆盖或释放,pvParameters指向的是失效的内存区域,导致handlers变成野指针,后续访问*handlers->debugQueue时就触发了空指针访问(对应错误日志里的EXCVADDR: 0x00000000)。

第一次发送时可能只是侥幸内存还没被改写,第二次操作时内存被破坏,就触发了LoadProhibited异常。

解决方案

有几种简单的修复方式,选哪种都可以:

方案1:把结构体改成静态局部变量

在setup里定义结构体时加上static,这样它的内存会分配在静态存储区,不会随setup函数结束而释放:

static const ReadSensorsParameters sensorTaskDescriptor{ &debugMsgQueue,&sensorDataBufQueue,&sensorTaskWatchdog,rtc};

方案2:用动态内存分配(堆)

在setup里用malloc分配结构体内存,任务结束后记得释放(不过你任务最后用了vTaskDelete(NULL),可以在删除前释放,规范起见最好处理):

ReadSensorsParameters* sensorTaskDescriptor = (ReadSensorsParameters*)malloc(sizeof(ReadSensorsParameters));
if(sensorTaskDescriptor != NULL){
    *sensorTaskDescriptor = { &debugMsgQueue,&sensorDataBufQueue,&sensorTaskWatchdog,rtc};
    xReturned = xTaskCreate(ReadSensors, "GETDATA", 4096, (void*)sensorTaskDescriptor, 1, &sensorTaskHandle);
}

然后在ReadSensors任务末尾添加释放代码:

free(pvParameters); // 在vTaskDelete之前执行
vTaskDelete(NULL);

方案3:改用全局结构体

把sensorTaskDescriptor定义成全局变量,这样内存生命周期和程序一致:

// 放在setup函数外面
ReadSensorsParameters sensorTaskDescriptor;

void setup(){
    // ...其他初始化代码
    sensorTaskDescriptor = { &debugMsgQueue,&sensorDataBufQueue,&sensorTaskWatchdog,rtc};
    xReturned = xTaskCreate(ReadSensors, "GETDATA", 4096, (void*)&sensorTaskDescriptor, 1, &sensorTaskHandle);
    // ...
}
额外建议
  • 以后传递任务参数时,一定要确保参数的内存生命周期覆盖任务的运行周期,栈上的局部变量绝对不能用来做任务参数(除非任务在setup执行期间就完成并删除,但这种场景很少)。
  • 你可以在ReadSensors任务开头加个检查,确认pvParameters和handlers都不为NULL,进一步避免异常:
void ReadSensors(void* pvParameters) {
    if(pvParameters == NULL){
        vTaskDelete(NULL);
        return;
    }
    ReadSensorsParameters* handlers = (ReadSensorsParameters*) pvParameters;
    if(handlers->debugQueue == NULL || *handlers->debugQueue == NULL){
        vTaskDelete(NULL);
        return;
    }
    // ...后续业务代码
}

内容的提问来源于stack exchange,提问作者Vrabély Csaba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 13:02:42