ESP-IDF / STM32 开发环境与调试组件备忘(WSL 串口 · EasyLogger · Console 控制台)
这篇把三份「环境与调试组件」的备忘合在一起:WSL 里共享 USB 串口、STM32F1 上接 EasyLogger 日志、ESP-IDF 里加可交互控制台。都是开箱即用的最小步骤,需要的时候翻到对应小节即可。
一、WSL 里把 USB 串口共享给 ESP-IDF(usbipd)
相关命令必须在管理员权限打开的终端里运行,否则会失败。
- 先列出 USB 设备:
usbipd list
可以看到类似输出(要记下 BusID,例如 3-2):
3-2 303a:1001 USB 串行设备 (COM8), USB JTAG/serial debug unit Shared (forced)
- 绑定设备:
usbipd bind --busid 3-2
- 挂载设备到 WSL:
usbipd attach --wsl --busid 3-2


之后在 WSL 里的 ESP-IDF 工程就能直接看到并烧录设备了。
二、STM32F1 上接入 EasyLogger(基于 USB 虚拟串口)
1. 资源下载
EasyLogger 的精简版(对我来说够用的那份),直接加入工程即可使用。
2. 配置打印函数
在 USB 虚拟串口实现中已经有 printf 了,把 EasyLogger 的输出接到它上面:
/**
* output log port interface
*
* @param log output of log
* @param size log size
*/
void elog_port_output(const char *log, size_t size) {
/* add your code here */
usb_printf("%.*s", size, log); //elog 的输出
}如果是普通串口重定向,只要把 usb_printf 替换成自己的实现:
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE {
HAL_UART_Transmit(&huart5, (uint8_t *) &ch, 1, HAL_MAX_DELAY);
return ch;
}3. 初始化并使用
#include "elog.h"
/* USER CODE BEGIN 2 */
easylogger_init(); // 初始化EasyLogger
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
elog_info("main","Hello World!");
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */下载运行,串口里就能看到日志了。
三、ESP-IDF:用 console_simple_init 加一个可交互控制台
调 ESP32 项目时常遇到这些场景:想临时执行一个命令看状态、想在线触发某个动作(比如开关某个外设)、又不想每次都改代码—烧录—看日志。这时候一个可交互 Console 就很有价值。这里记录一个通用做法:在任何 ESP-IDF 项目里用 espressif/console_simple_init 快速接入命令行控制台。
1. 为什么用它
原生 esp_console 功能很完整,但初始化流程相对分散。console_simple_init 的价值在于把常用步骤封装成了 4 个 API:
console_cmd_init():初始化控制台console_cmd_user_register():注册用户命令console_cmd_all_register():自动注册插件命令console_cmd_start():启动 REPL
一句话:快速可用,适合先跑通再扩展。
2. 接入步骤
2.1 添加组件依赖
idf.py add-dependency "espressif/console_simple_init^1.1.0"或者在 idf_component.yml 里手动添加:
dependencies:
idf: ">=5.0"
espressif/console_simple_init: ^1.1.02.2 在 CMake 里声明依赖
在你的组件 CMakeLists.txt(例如 main/CMakeLists.txt)里:
idf_component_register(
SRCS "main.c"
INCLUDE_DIRS "."
REQUIRES console_simple_init console
)这里建议把 console 显式写上,能避免一类常见的 include/IntelliSense 问题(后文会讲)。
2.3 在代码里初始化并注册命令
#include <stdio.h>
#include "esp_check.h"
#include "console_simple_init.h"
static int cmd_hello(int argc, char **argv)
{
(void)argc;
(void)argv;
printf("hello from console\n");
return 0;
}
void app_main(void)
{
// 你的项目里需确保 NVS 和默认事件循环已初始化
ESP_ERROR_CHECK(console_cmd_init());
ESP_ERROR_CHECK(console_cmd_user_register("hello", cmd_hello));
ESP_ERROR_CHECK(console_cmd_all_register()); // 可选
ESP_ERROR_CHECK(console_cmd_start());
}2.4 烧录后验证
idf.py flash monitor在 esp> 提示符输入 help、hello,如果能看到输出,说明接入成功。
3. 一个很常见的坑:include 报错
现象:#include "console_simple_init.h" 报 include 错,或提示找不到 esp_console.h。
本质:console_simple_init.h 会依赖 esp_console.h,如果你的组件没有显式依赖 console,编辑器索引有时会解析不到。
解决:
- CMake 增加
REQUIRES console - 执行:
idf.py reconfigure
idf.py build- 在 VS Code 刷新索引(Reset IntelliSense Database + Reload Window)
4. 另一个常见坑:串口写入超时
现象:Monitor 日志里反复出现 Writing to serial is timing out...
本质:Console 所用的通道(UART / USB CDC / USB Serial/JTAG)和你当前 monitor 连接的端口不一致。
解决:在 menuconfig 里把 console 输出通道配置成和实际连接一致:
Component config -> ESP System Settings -> Channel for console output
改完后重新 build + flash。
5. 为什么它适合做「运维入口」
当项目复杂起来后,你会很自然地需要这些命令:
status:看系统状态sensor:看传感器实时值pump on/off:控制执行器wifi status:看联网状态
有了 console,这些能力都能在不改 UI 的情况下快速加上。
6. 我建议的演进路线
- 先做 1~2 个命令跑通链路
- 加参数解析和错误提示
- 按模块分组命令(sensor/io/net)
- 给危险动作加确认机制
7. 小结
console_simple_init 的优势不是「功能比 esp_console 更多」,而是把接入门槛降得很低:依赖加上、几个 API 调用,很快就能得到可交互的调试入口。对于早期开发和现场调试,它能显著减少反复烧录的成本。

微光录