Zephyr Shell 是一个强大的命令行接口,用于调试、配置和控制系统。
┌─────────────────────────────────────┐
│ User Input │
│ (UART/RTT/USB) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Shell Core │
│ ┌─────────────────────────────┐ │
│ │ Command Parser │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ Command Dispatcher │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ Output Formatter │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Shell Backends │
│ UART | RTT | USB | Telnet │
└─────────────────────────────────────┘
prj.conf 基本配置:
# 启用 Shell
CONFIG_SHELL=y
# 启用 UART 后端
CONFIG_SHELL_BACKEND_SERIAL=y
# 启用 RTT 后端 (调试用)
CONFIG_SHELL_BACKEND_RTT=y
# 启用日志
CONFIG_LOG=y
CONFIG_SHELL_LOG_BACKEND=y
# 命令历史
CONFIG_SHELL_HISTORY=y
# Tab 补全
CONFIG_SHELL_TAB=y
CONFIG_SHELL_TAB_AUTOCOMPLETION=y
# 参数自动补全
CONFIG_SHELL_CMDS_SELECT=y
# 颜色输出
CONFIG_SHELL_VT100_COLORS=y
#include <zephyr/shell/shell.h>
/* 简单命令 */
static int cmd_hello(const struct shell *sh, size_t argc, char **argv)
{
shell_print(sh, "Hello, Zephyr Shell!");
return 0;
}
/* 注册命令 */
SHELL_CMD_REGISTER(hello, NULL, "Say hello", cmd_hello);
static int cmd_echo(const struct shell *sh, size_t argc, char **argv)
{
for (size_t i = 1; i < argc; i++) {
shell_print(sh, "argv[%d]: %s", i, argv[i]);
}
return 0;
}
SHELL_CMD_REGISTER(echo, NULL, "Echo arguments", cmd_echo);
/* LED 控制子命令 */
static int cmd_led_on(const struct shell *sh, size_t argc, char **argv)
{
shell_print(sh, "LED ON");
return 0;
}
static int cmd_led_off(const struct shell *sh, size_t argc, char **argv)
{
shell_print(sh, "LED OFF");
return 0;
}
/* 子命令数组 */
SHELL_STATIC_SUBCMD_SET_CREATE(sub_led,
SHELL_CMD(on, NULL, "Turn LED on", cmd_led_on),
SHELL_CMD(off, NULL, "Turn LED off", cmd_led_off),
SHELL_SUBCMD_SET_END
);
/* 注册主命令 */
SHELL_CMD_REGISTER(led, &sub_led, "LED control commands", NULL);
static int cmd_config(const struct shell *sh, size_t argc, char **argv)
{
/* 获取选项值 */
char *value = strchr(argv[1], '=');
if (value) {
value++; /* 跳过 '=' */
shell_print(sh, "Config value: %s", value);
}
return 0;
}
SHELL_CMD_REGISTER(config, NULL, "Set configuration", cmd_config);
/* 打印普通信息 */
shell_print(sh, "Normal message");
/* 打印警告 */
shell_warn(sh, "Warning message");
/* 打印错误 */
shell_error(sh, "Error message");
/* 打印十六进制数据 */
shell_hexdump(sh, data, sizeof(data));
/* 打印信息提示 */
shell_info(sh, "Info message");
/* 打印普通文本(无前缀) */
shell_fprintf(sh, SHELL_NORMAL, "Raw output\n");
/* 支持 printf 格式 */
shell_print(sh, "Temperature: %d.%d C", temp_int, temp_frac);
shell_print(sh, "Device: %s, Address: 0x%08X", name, addr);
/* 默认串口后端一般由控制台 / chosen 节点决定 */
#define SHELL_UART_DEV DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart))
/* 自定义 UART 设备 */
static const struct shell_uart_cfg shell_uart_cfg = {
.dev = SHELL_UART_DEV,
};
SHELL_UART_DEFINE(shell_uart, shell_uart_cfg);
# prj.conf
CONFIG_USE_SEGGER_RTT=y
CONFIG_SHELL_BACKEND_RTT=y
CONFIG_RTT_CONSOLE=y
# prj.conf
# legacy USB device stack 常见写法
# CONFIG_USB_DEVICE_STACK=y
# CONFIG_USB_CDC_ACM=y
# current USB device stack 参考当前 sample / 文档
CONFIG_USB_DEVICE_STACK_NEXT=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_UART_LINE_CTRL=y
# prj.conf
CONFIG_NET_IPV4=y
CONFIG_NET_TCP=y
CONFIG_SHELL_BACKEND_TELNET=y
CONFIG_SHELL_TELNET_INIT_LOG_LEVEL_DBG=y
static int cmd_set_value(const struct shell *sh, size_t argc, char **argv)
{
if (argc < 2) {
shell_error(sh, "Missing argument");
shell_help(sh);
return -EINVAL;
}
int value = atoi(argv[1]);
if (value < 0 || value > 100) {
shell_error(sh, "Value must be 0-100");
return -EINVAL;
}
return 0;
}
SHELL_CMD_REGISTER(set, NULL, "Set value (0-100)", cmd_set_value);
/* 动态子命令生成 */
static void sensor_name_get(size_t idx, struct shell_static_entry *entry)
{
static const char *sensors[] = {"temp", "humi", "press"};
if (idx < ARRAY_SIZE(sensors)) {
entry->syntax = sensors[idx];
entry->handler = NULL;
entry->subcmd = NULL;
entry->help = "Sensor name";
} else {
entry->syntax = NULL;
}
}
SHELL_DYNAMIC_CMD_CREATE(dsub_sensor, sensor_name_get);
/* 命令执行前回调 */
static int shell_cmd_pre_exec(const struct shell *sh)
{
shell_print(sh, "Executing command...");
return 0;
}
/* 命令执行后回调 */
static void shell_cmd_post_exec(const struct shell *sh)
{
shell_print(sh, "Command completed");
}
/* 保存 Shell 状态 */
static void save_shell_state(const struct shell *sh)
{
/* 可以保存到 Settings 或 NVS */
}
/* 恢复 Shell 状态 */
static void restore_shell_state(const struct shell *sh)
{
/* 从 Settings 或 NVS 恢复 */
}
# 查看内核信息
uart:~$ kernel version
# 查看线程
uart:~$ kernel threads
# 查看设备列表
uart:~$ device list
# 查看日志
uart:~$ log show
# 设置日志级别
uart:~$ log level set 3
# 启用模块日志
uart:~$ log enable app
# 查看内存状态
uart:~$ kernel memmap
# 内存池状态
uart:~$ kernel mem_pool
# Flash 操作(需启用)
uart:~$ flash read <addr> <size>
uart:~$ flash write <addr> <data>
uart:~$ flash erase <addr> <size>
#include <zephyr/kernel.h>
#include <zephyr/shell/shell.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
/* LED ON 命令 */
static int cmd_led_on(const struct shell *sh, size_t argc, char **argv)
{
gpio_pin_set_dt(&led, 1);
shell_print(sh, "LED is ON");
return 0;
}
/* LED OFF 命令 */
static int cmd_led_off(const struct shell *sh, size_t argc, char **argv)
{
gpio_pin_set_dt(&led, 0);
shell_print(sh, "LED is OFF");
return 0;
}
/* LED 闪烁命令 */
static int cmd_led_blink(const struct shell *sh, size_t argc, char **argv)
{
if (argc < 2) {
shell_error(sh, "Usage: led blink <interval_ms>");
return -EINVAL;
}
int interval = atoi(argv[1]);
shell_print(sh, "LED blinking at %d ms interval", interval);
for (int i = 0; i < 10; i++) {
gpio_pin_set_dt(&led, 1);
k_msleep(interval);
gpio_pin_set_dt(&led, 0);
k_msleep(interval);
}
shell_print(sh, "Blink complete");
return 0;
}
/* LED 状态命令 */
static int cmd_led_status(const struct shell *sh, size_t argc, char **argv)
{
int state = gpio_pin_get_dt(&led);
shell_print(sh, "LED is %s", state ? "ON" : "OFF");
return 0;
}
/* LED 子命令 */
SHELL_STATIC_SUBCMD_SET_CREATE(sub_led,
SHELL_CMD(on, NULL, "Turn LED on", cmd_led_on),
SHELL_CMD(off, NULL, "Turn LED off", cmd_led_off),
SHELL_CMD(blink, NULL, "Blink LED", cmd_led_blink),
SHELL_CMD(status, NULL, "Show LED status", cmd_led_status),
SHELL_SUBCMD_SET_END
);
SHELL_CMD_REGISTER(led, &sub_led, "LED control commands", NULL);
/* 设备信息命令 */
static int cmd_dev_info(const struct shell *sh, size_t argc, char **argv)
{
shell_print(sh, "Device: nRF54L15 DK");
shell_print(sh, "Board: %s", CONFIG_BOARD);
shell_print(sh, "Kernel: %s", KERNEL_VERSION_STRING);
return 0;
}
SHELL_CMD_REGISTER(dev, NULL, "Show device info", cmd_dev_info);
/* 主函数 */
int main(void)
{
/* 初始化 LED */
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
printk("Shell demo started\n");
printk("Type 'help' for available commands\n");
return 0;
}
# prj.conf
CONFIG_NRF_SHELL=y
CONFIG_NRF_SHELL_BLE=y
# BLE 命令
uart:~$ ble addr
uart:~$ ble advertise start
uart:~$ ble scan start
# DFU 命令
uart:~$ dfu dm.list
uart:~$ dfu mcumgr
# 启用 Shell 调试日志
CONFIG_SHELL_LOG_LEVEL_DBG=y
/* 启用命令追踪 */
SHELL_CMD_DEFINE(traced_cmd, NULL, "Traced command", cmd_handler);
static int cmd_safe(const struct shell *sh, size_t argc, char **argv)
{
int ret = do_something();
if (ret < 0) {
shell_error(sh, "Operation failed: %d", ret);
return ret;
}
shell_print(sh, "Success");
return 0;
}
static int cmd_help(const struct shell *sh, size_t argc, char **argv)
{
shell_print(sh, "Usage: mycommand <option> [value]");
shell_print(sh, "Options:");
shell_print(sh, " -a: Option A");
shell_print(sh, " -b: Option B");
return 0;
}
学习日期: 2026-03-21 笔记编号: #51 作者: 小白 🤖