跑通 Hello World 之后,我是怎么第一次真正用上 ESP32 的 menuconfig 和日志系统的
hello_world 跑通那天,我其实挺开心的。
程序能烧进去,串口能正常打印,一切看起来都很顺利。
但也正是在这一步之后,我开始意识到一个问题:
串口里的信息,好像有点多了。
一开始我以为,这是我代码写得“太啰嗦”。
但后来我才发现,这件事根本不只是代码层面的。
我最早遇到的问题,其实只是:日志太多了
刚开始学习 ESP32 的时候,串口日志对我来说是“安全感来源”。
能看到打印,就说明程序在跑。
但当工程慢慢从hello_world变成我自己的最小工程后,日志开始变得:
- 信息很多
- 启动阶段刷一大堆
- 有些内容我完全看不懂
我当时的第一反应很新手:
那我少打点
printf不就好了?
结果发现,没什么用。
因为即使我代码里什么都不打印,启动时串口里还是会冒出一堆系统日志。
这时候我才意识到:ESP32 的日志,不完全由代码决定
真正让我意识到问题不在代码里的,是这件事:
我把自己写的日志全删了,串口还是很热闹。
后来我才知道,在 ESP-IDF 里,日志是一个完整的系统机制:
- 有统一的日志接口
- 有日志等级
- 有默认输出策略
- 还有和 menuconfig 强绑定的配置项
也正是从这里开始,我第一次认真点开了:
idf.py menuconfig第一次打开 menuconfig,我的真实心态:不是看不懂,是不敢动
menuconfig 的界面第一次打开时,给人的感觉很“底层”。
蓝色背景,一行一行配置,看起来就像是:
一不小心改错,整个系统都会出问题。
所以我当时并没有“系统性研究”,而是只盯着一个目标:
我能不能控制日志?
操作方式
看似很复杂,但是只要了解一下这个窗口的操作方式就简单了:
方向键(↑ ↓ ): ↑ 和 ↓:在菜单项之间上下移动。 如果是window环境,方向按键可能是j、k或者↑、↓ Enter(回车): 进入子菜单或打开选项的配置界面。 Space(空格): 开启或关闭某个配置,[]为未选择,[*]为选择。 Esc: 返回上一级菜单。 多次按Esc可以退出菜单。退出时,如果你有修改了相关配置,会提示你是否保持配置,如果你不想修改,记得选N。
接着,我们可以添加一点自己的配置,我们先按Esc按键退出,如果你已经修改了配置,这里会提问你是否保存,记得点击按键N即可。
menuconfig 改的东西,最终都体现在 sdkconfig 里
这是我后来慢慢理解的一点。
当你在 menuconfig 里改完配置、保存退出后,ESP-IDF 实际做的是:
把你的选择,写进
sdkconfig文件。
这个文件本质上是一堆宏定义,比如:
CONFIG_LOG_DEFAULT_LEVEL_INFO=y CONFIG_LOG_DEFAULT_LEVEL_DEBUG=n也就是说:
- menuconfig 是“操作界面”
- sdkconfig 才是真正参与编译的配置来源
从这以后,我基本形成了一个习惯:
只要 menuconfig 改了东西,就去看一眼 sdkconfig。
添加自己的菜单
其实,换句话说,这里只是idf提供了一个可视化的配置,方便我们配置sdkconfig文件而已,我们修改后重新执行idf.py build编译。
我想能不能在menuconfig中添加我自己的定制的菜单,应该如何添加呢?后面通过学习我发现,也很简单,我在自己工程中添加了一个main/Kconfig.projbuild文件,注意:是main文件夹下方
Kconfig.projbuild
#puthere your custom config valuemenu"Example Configuration"config ESP_WIFI_SSID string"WiFi SSID"default"myssid"helpSSID(network name)forthe example to connect to.config ESP_WIFI_PASSWORD string"WiFi Password"default"mypassword"help WiFipassword(WPA or WPA2)forthe example to use.endmenu解释
#puthere your custom config value--》注释menu"Example Configuration"--》菜单名 config ESP_WIFI_SSID-》参数名 string"WiFi SSID"-》参数类型 显示名称,参数类型支持boolintstringdefault"myssid"-》默认值 help-》帮助信息SSID(network name)forthe example to connect to.endmenu-》菜单结束标志这时候,我运行了idf.py menuconfig后,可以看到窗口中多了Example Configuration的配置。
接着操作选择并修改,按Enter回车键可以进入下一层。
这个窗口中的配置,保存下来后,会影响的其实就是工程的sdkconfig文件:
然后我添加了对这几个打印行,看看他到底是怎么样的
#include<stdio.h>// 引入标准输入输出库,用于使用 printf 函数#include"freertos/FreeRTOS.h"// 引入 FreeRTOS 的核心头文件,提供 FreeRTOS 的基本功能#include"freertos/task.h"// 引入 FreeRTOS 的任务管理头文件,提供任务相关的函数(如 vTaskDelay)#include"sdkconfig.h"voidapp_main(void)// ESP-IDF 程序的入口函数,类似于 main 函数{inti=0;// 定义一个整数变量 i,并初始化为 0,用于计数while(1){// 无限循环,确保程序持续运行printf("%s %s\n",CONFIG_ESP_WIFI_SSID,CONFIG_ESP_WIFI_PASSWORD);printf("[%d] Hello world!\n",i);// 打印带计数的 "Hello world!" 消息,%d 会被变量 i 的值替换i++;// 计数器 i 自增 1vTaskDelay(5000/portTICK_PERIOD_MS);// 延时 5000 毫秒(5 秒)// portTICK_PERIOD_MS 是 FreeRTOS 的时钟节拍周期(系统计时器的"心跳间隔" 通常为 1 毫秒)}}idf.py build进行编译,idf.py flash monitor烧录运行后,可以看到:
我第一次真正“理解”日志系统,是从日志等级开始的
在 menuconfig 里,我最早动的地方是:
Component config → Log → Log Level
这里有一个选项,叫:
Default log verbosity
当时我对它的理解非常朴素:
它决定了,系统默认“愿不愿意”把日志打出来。
ESP-IDF 里常见的日志等级有:
- Error
- Warn
- Info
- Debug
- Verbose
我一开始保持在Info,这是一个非常适合入门阶段的选择。
后来我试过切到Debug,然后立刻体会到了什么叫:
串口被日志淹没。
这时候我才真正理解,日志等级不是“随便选的”,而是系统运行策略的一部分。
日志不是 printf,而是一套统一机制
在真正看了一点日志相关文档后,我才意识到一件事:
ESP-IDF 并不推荐你长期用
printf打日志。
而是提供了一整套日志接口,比如:
ESP_LOGE(TAG,"this is esp log");//错误日志,用于记录系统中发生的严重错误,这些错误通常会导致程序无法正常运行或产生严重的异常情况。ESP_LOGW(TAG,"this is esp log");//警告日志,用于记录可能会影响程序正常运行,但不会导致程序崩溃的潜在问题或异常情况。ESP_LOGI(TAG,"this is esp log");//信息日志,用于记录程序的正常运行状态和重要事件,帮助开发者了解程序的执行流程和关键操作的结果。ESP_LOGD(TAG,"this is esp log");//调试日志,用于记录程序的详细执行过程和中间结果,主要用于开发和调试阶段,帮助开发者排查问题。ESP_LOGV(TAG,"this is esp log");//详细日志,用于记录最详细的程序执行信息,输出的日志信息最多,会带来较大的系统开销,通常只在开发和调试阶段使用。并且当在menuconfig中配置为保存后,也可以看到在sdkconfig文件中看到内容:
再经过编译下载烧录,运行后:
这些日志宏背后,都会受到:
- menuconfig 中日志等级配置
- 组件级别日志开关
- 系统默认输出策略
的共同影响。
这也是为什么:
你代码里写了日志,但它不一定会被打印出来。
更加快捷的menuconfig搜索
前面我手动一个个设置寻找然后选择,效率还是太低了,那有没有直接搜索设置名称的方式呢?
我后面发现,可以在执行idf.py menuconfig时:
按/,搜索LOG_DEFAULT_LEVEL,注意,这里没有CONFIG
就可以看到日志级别的菜单,然后点击Enter回车,就可以直接进入到最终的设置页面。
方便了不少。
我踩过一次日志相关的坑
有一次,我为了“让系统干净一点”,误关了某个日志输出相关配置。
结果是:
- 程序能烧
- 板子在跑
- 串口一片安静
那一刻我真的怀疑过人生:
程序是不是没跑?
串口是不是坏了?
最后对比sdkconfig才发现,是我自己把日志系统“关死”了。
从那之后,我给自己立了两个规则:
- 日志相关配置,一次只改一个
- 改完马上验证串口输出
menuconfig + 日志系统,其实是在帮你“管理复杂度”
回头看,我现在反而挺感谢 ESP-IDF 把日志这件事做得这么“重”。
因为它提前告诉你一件事:
当系统变复杂时,日志本身就是工程的一部分。
你不能指望靠几句printf,就撑起一个复杂系统的调试需求。
写在最后
如果你现在也处在这个阶段:
- hello_world 刚跑通
- 开始写自己的最小工程
- 串口日志越来越多
- 开始意识到“不太对劲”
那我想说一句很实在的话:
menuconfig 和日志系统,不是高级内容,而是入门必经之路。
你现在不需要完全掌握它们,只需要知道:
- 日志不是随便打的
- 行为不是只由代码决定的
- menuconfig 是工程的一部分