目录
[2.1 user组件下的CMakeLists.txt](#2.1 user组件下的CMakeLists.txt)
[2.2 user.h](#2.2 user.h)
[2.3 user.c](#2.3 user.c)
[2.4 main](#2.4 main)
前言
本文基于第一章创建好的工程,来写一个控制台终端交互的工程。开发板芯片是ESP32-P4、ESP-IDF版本是5.5.3。
控制台终端交互这是一个非常有用的功能,我们可以在终端输入一些命令来查询芯片的某种状态或者是执行某种操作。在ESP-IDF中其实很容易开启终端交互,但是官方手册写的不太友好,很难让人看懂它的目的。这部分功能也可以添加进工程模板中。
一、完善工程
打开工程模板

点解左下角的齿轮图标(SDK配置编辑器),搜索console,改为如下设置

Channel for console output(控制台输出通道)
UART0:默认,通过硬件串口 UART0 输出日志和控制台信息。USB Serial/JTAG Controller:通过芯片内置的 USB Serial/JTAG 控制器输出(ESP32-C3/S3/P4 等支持),无需额外 USB 转串口芯片,直接用 USB 线连接电脑即可。Custom:自定义 UART 端口和引脚。None:关闭 UART 控制台输出。
Channel for console secondary output(控制台次要输出通道)
- 当主通道(比如 UART0)未连接时,可额外指定一个备用输出通道(如 USB_SERIAL_JTAG),仅支持非阻塞模式,不支持 REPL 交互式输入。也就是说该通道只能作为备用输出并且不能输入
Line ending for console output(输出换行符格式)
CRLF:\n→\r\n(Windows 风格,适配大部分串口工具)。LF:保持\n不变(Linux/macOS 风格)。CR:\n→\r(老式设备风格,极少用)。
推荐 CRLF :绝大多数串口终端(如串口助手、PuTTY、minicom)默认识别 \r\n 为换行。
Line ending for console input(输入换行符格式)
CRLF:将输入的\r\n转换为\n。LF:保持输入的\n不变。CR:将输入的\r转换为\n。
将键盘回车(\r)转换为 \n,完全适配 USB Serial/JTAG 控制台,能正常识别回车提交命令。
添加一个自定义组件,比如我这是user
接着在user文件夹下新建文件idf_component.yml,并在该文件中添加以下内容,显示效果如下。
cpp
dependencies:
cmd_system:
path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system

前面我们通俗的理解CMakeLists.txt负责头文件路径添加,但是有个限制,只能添加依赖 IDF 自带的驱动(uart、gpio、esp_console)的头文件。如果我们需要添加第三方组件,就必须使用idf_component.yml。两者核心区别如下
CMakeLists.txt (REQUIRES)
- 编译时要链接这个组件,告诉编译器我需要用它里面的函数
idf_component.yml
- 管理从哪里找到这个组件 ,要不要下载 ,版本 / 路径是什么 ,但不参与编译,只负责定位组件
我这的含义是我需要使用组件cmd_system,它的位置在{IDF_PATH}/examples/system/console/advanced/components/cmd_system,这里所用的是绝对路径,第一章已经说明了{IDF_PATH}的含义,在我这代表C:\esp\v5.5.3\esp-idf。
cmd_system是官方的系统命令组件, 已经在我们的IDF 组件仓库中,找到路径位置添加就行,至于为什么要添加,见2.3 user.c
做完这些可以编写控制台终端交互的程序了。
二、代码编写
2.1 user组件下的CMakeLists.txt
cpp
idf_component_register(SRCS "user.c"
INCLUDE_DIRS "include"
REQUIRES console)
不用说,按要求添加依赖:console
2.2 user.h
cpp
#ifndef USER_H
#define USER_H
#include <stdio.h> // 输入输出函数
#include <string.h> // 字符串处理函数
#include "esp_console.h" // ESP32控制台函数
#include "cmd_system.h" // 系统命令相关函数
#include "linenoise/linenoise.h" // 行编辑库
void CONSOLE_REPL_INIT(void); // REPL环境初始化函数声明
#endif // USER_H
2.3 user.c
cpp
#include "user.h"
void CONSOLE_REPL_INIT(void)
{
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); // 使用默认REPL配置
esp_console_repl_t *repl = NULL;
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
esp_console_dev_usb_serial_jtag_config_t usb_serial_jtag_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT(); // 使用默认USB串行JTAG配置
ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usb_serial_jtag_config, &repl_config, &repl)); // 创建USB串行JTAG REPL环境
#else
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); // 使用默认UART配置
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); // 创建UART REPL环境
#endif
ESP_ERROR_CHECK(esp_console_start_repl(repl)); // 启动REPL环境
esp_console_register_help_command(); // 注册帮助命令
register_system_common(); // 注册系统常用命令
linenoiseSetDumbMode(1); // 设置linenoise为简单模式,适用于串行终端
}
在官方文档中《控制台终端》提供了很多esp_console_xxx、linenoisexxx的函数,我们大多不需要去使用,因为初始化 REPL 环境有三个一体化函数,这些函数已经调用了很多console初始化函数。重复使用会报错,当然你也可以用这些基础函数自定义REPL 环境。
初始化 REPL 环境一体化函数共有三个,分别是通过UART、USB CDC、USB-SERIAL-JTAG来建立一个控制台REPL环境。在SDK配置编辑器------console设置中需要确定**Channel for console output**,从而确定初始化什么环境,这样就比较麻烦。
我这用预编译指令对UART和USB-SERIAL-JTAG都做了初始化,只需要SDK配置编辑器------console设置就行,无需改动代码,不过只支持默认UART0,有其他串口需求自行更改。
我调用了函数register_system_common();,用来注册系统常用命令,这样控制台的交互就能使用这些命令。包括free、heap等。如果不叫这一句,控制台虽然能交互,但没有任何一条命令能使用。而该函数的声明在组件cmd_sysytem中,这就是为什么我前面要添加这个组件。
使用函数linenoiseSetDumbMode(1);可以避免输入命令时光标跳动、闪烁等异常。
其他函数官方文档有讲解,这里不再重复了。
2.4 main
cpp
#include <stdio.h>
#include "user.h"
static int cmd_add(int argc, char **argv)
{
// 检查参数数量
if (argc != 3)
{
printf("Usage: add <num1> <num2>\n");
return -1;
}
// 字符串转数字
int a = atoi(argv[1]);
int b = atoi(argv[2]);
// 计算并输出
printf("Result: %d\n", a + b);
return 0;
}
void app_main(void)
{
esp_console_cmd_t cmd = {
.command = "add",
.help = "Add two numbers",
.func = cmd_add,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); // 注册自定义命令
CONSOLE_REPL_INIT(); // 初始化REPL环境
}
这里我注册了一个加和任务,用来测试。
三、结果展示

工程下载: