ESP32双核任务并行异常:vTaskCreatePinnedToCore未达预期
问题分析与解答
本质原因:任务逻辑的GPIO竞争 + 无阻塞死循环的调度特性
你看到的LED闪烁并非任务串行执行,而是两个并行任务在高频修改相同GPIO引脚,同时无阻塞死循环导致调度异常,具体分解如下:
1. 任务逻辑的GPIO竞争问题
你的两个任务同时操作相同的两个GPIO引脚:
sensorsTask循环将引脚2置1、引脚4置0storageTask循环将引脚4置1、引脚2置0
当两个任务在双核上并行运行时,两个核心会同时对这两个引脚进行写操作:
- 引脚2会被核心0快速置1,紧接着被核心1置0,如此反复
- 引脚4会被核心1快速置1,紧接着被核心0置0,如此反复
这种高频电平切换远超过人眼的分辨能力,最终呈现为LED闪烁,而非你预期的稳定点亮。
2. 无阻塞死循环对调度的影响
你的任务是没有任何阻塞点的死循环,这会导致:
- 每个核心的FreeRTOS调度器无法切换到其他系统任务(比如ESP-IDF的后台服务、定时器任务等),长期运行会触发看门狗复位
- 任务会持续占用核心CPU时间,没有任何机会让其他任务(包括系统任务)执行
3. 添加vTaskDelay(1)后正常的原因
加入vTaskDelay(1)后,任务会主动放弃CPU控制权,进入阻塞状态:
- 调度器可以正常调度其他系统任务,保证系统稳定运行
- 更关键的是,任务的GPIO操作频率被降低到每1ms执行一次,此时引脚电平的切换速度变慢,人眼可以看到稳定的电平状态;同时,在延迟期间,另一个任务设置的电平会保持足够长的时间,不会被立刻覆盖。
正确的任务设计方式
如果要让两个LED稳定点亮,应该让每个任务只负责自己的LED,避免GPIO竞争:
void storageTask(void *arg){ for(;;){ gpio_set_level(4, 1); // 仅控制引脚4的LED vTaskDelay(pdMS_TO_TICKS(10)); // 使用标准延迟宏适配不同时钟 } } void sensorsTask(void *arg){ for(;;){ gpio_set_level(2, 1); // 仅控制引脚2的LED vTaskDelay(pdMS_TO_TICKS(10)); } }
这种情况下,即使去掉延迟,LED也会稳定点亮——因为任务只是重复设置相同的电平,不会互相干扰;而保留延迟则是为了给系统任务留出执行时间,避免系统异常。
内容的提问来源于stack exchange,提问作者Muhammad Hammad Umer
相关产品推荐
相关产品推荐

