ESP-IDF 是乐鑫的开发框架,组织工具链、组件、驱动、RTOS、网络和系统服务。ESP32 是一组相关芯片的名称,具体核心、无线能力、外设和引脚有差异。本页固定使用 ESP-IDF v5.3.2、目标 esp32 解释工程,不把这一组合当成所有芯片的通用配置。
工程中哪些东西需要保存
根 CMakeLists.txt 引入 IDF 的构建入口;组件通过各自的 CMakeLists.txt 声明源文件与依赖;menuconfig 生成 sdkconfig。保存源码、目标、sdkconfig 或可重建的 defaults、分区表、依赖锁定和实际工具版本,才能解释别的电脑为什么得到不同固件。
工具链应通过所选 IDF 版本配套安装,使用对应终端导出环境。先运行官方 hello_world,再尝试 GPIO 和联网,能把环境问题与应用问题分开。
一个两任务采集骨架
附件包含 根 CMakeLists.txt、组件 CMakeLists.txt 和 node.c,下载时保留 main 目录。生产者每秒构造一条合成毫伏值,消费者打印队列记录;数值不来自传感器。
idf-node/
CMakeLists.txt
main/
CMakeLists.txt
node.c
在 ESP-IDF v5.3.2 环境、该工程目录执行:
idf.py set-target esp32
idf.py build
上板时再用 idf.py -p PORT flash monitor,PORT 替换为本机实际串口。连接前核对板卡、供电、启动脚与接口。本页没有在 IDF 工具链编译或实物运行这些附件;它们提供结构清楚的移植起点,构建和串口日志需要在上述环境验证。
应用的关键交接如下:
sample_t value = {.seq = seq++, .millivolts = 1200};
if (xQueueSend(samples, &value, 0) != pdPASS) {
/* 记录丢弃,不能无限等待拖住采集。 */
}
结构体按值入队,避免生产者复用局部变量使消费者读到已经改变的数据。示例队列深度为四,仅用于演示容量边界,真实容量应按生产速率、停顿与突发计算。
与单核 FreeRTOS 的差异
所选 IDF 在相关双核目标上使用改造过的 SMP 调度。未绑定任务可能在核心间迁移;本地关中断不能保护另一核心。任务栈大小参数在该 IDF API 中按字节计,而常规 FreeRTOS API 通常按 StackType_t 单位计。移植时不能只复制数字。
绑定核心可能便于隔离负载,也可能让一个核心过载、另一个空闲。先测量 CPU、阻塞、栈和堆,再决定是否固定核心。不要为了“更快”先给所有任务最高优先级。
外设、配置与持久化
GPIO 引脚要避开启动配置或板上已占用功能,并检查具体芯片限制。ADC 结果应按目标支持的校准接口处理,不能直接假定参考电压固定。NVS 适合少量配置,必须考虑初始化失败、空间不足与写入频率;高频传感器样本不宜逐条写 NVS。
练习:给消费者加入三秒停顿,预测并记录丢弃数量;把每条记录改成指向同一缓冲区的指针,解释为什么会出现内容被覆盖,再恢复为按值或缓冲池交接。
面试自查:sdkconfig 为什么属于可复现输入?双核能否消除互斥?同一个“4096 栈”参数为什么可能含义不同?网络协议任务与业务采集任务为什么需要避免互相长时间阻塞?