Zephyr 使用方式与典型场景:两个可运行示例
使用方式与典型场景:两个可运行示例
第一个示例用 GPIO 驱动板载 LED 翻转,同时用日志替代 printk,这是最小但最完整的 Zephyr 应用骨架:
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(blink, LOG_LEVEL_INF);
/* 设备树里 led0 别名对应的节点,编译期解析,无运行期查找 */
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
int main(void)
{
if (!gpio_is_ready_dt(&led)) {
LOG_ERR("led device not ready");
return -1;
}
int ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("configure failed: %d", ret);
return ret;
}
LOG_INF("blink start, sysclk %d Hz", sys_clock_hw_cycles_per_sec());
while (1) {
gpio_pin_toggle_dt(&led);
k_msleep(500);
}
}
对应的 prj.conf 只需要 CONFIG_GPIO=y 与 CONFIG_LOG=y。编译烧录:
west build -b nrf52840dk/nrf52840 .
west flash --runner jlink
第二个示例给应用加一条自定义 shell 命令,这是量产前调试阶段最有价值的一步——可以在不动固件的情况下读写寄存器、切换状态、触发自检:
#include <zephyr/shell/shell.h>
#include <zephyr/kernel.h>
static int cmd_led_on(const struct shell *sh, size_t argc, char **argv)
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
/* 这里调用实际的 GPIO 或业务接口 */
shell_print(sh, "led on, uptime %u ms", (unsigned)k_uptime_get_32());
return 0;
}
static int cmd_led_off(const struct shell *sh, size_t argc, char **argv)
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
shell_print(sh, "led off");
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(led_cmds,
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, &led_cmds, "LED control commands", NULL);
开启 CONFIG_SHELL=y 与 CONFIG_SHELL_BACKEND_SERIAL=y 后,用串口终端连上板子敲 led on 即可执行,help 列出全部命令,kernel threads、kernel stacks、device list 这类内置命令对排查现场问题非常实用。
适合的场景:MCU 级别的实时控制、需要成熟 BLE / 802.15.4 / 网络协议栈的产品、长期维护要求高(需要 LTS、安全更新、供应商中立)的项目、以及同代码多硬件型号复用的产品线。
不适合的场景:需要完整 Linux 用户态生态、需要 MMU 做进程隔离、需要跑重型 Python / 容器 / 设备节点复杂驱动的设备,这些场景应该直接选 Linux;只需要几百字节极小调度器、对代码体积极端敏感且团队已有成熟私有框架的项目,继续用 FreeRTOS 更划算。另外,Zephyr 的抽象层较厚,纯寄存器级调试的直觉在这里不完全适用,团队需要接受「先读文档再动手」的节奏。

