返回首页

UART echo_bot 学习笔记

概述

这是一个使用中断驱动模式的 UART 回显示例。通过串口接收用户输入,收到换行符后原样回显。


1. 设备树配置

#define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart)
static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);

关键点:

问题:波特率在哪设置?

在设备树或板级 overlay 中配置。实际节点和默认波特率应以当前板卡配置为准。


2. 消息队列机制

#define MSG_SIZE 32
K_MSGQ_DEFINE(uart_msgq, MSG_SIZE, 10, 4);

关键参数:

参数含义
消息大小32字节每条消息最大长度

工作机制:


3. 中断处理流程

3.1 注册回调

uart_irq_callback_user_data_set(uart_dev, serial_cb, NULL);

3.2 启用接收中断

uart_irq_rx_enable(uart_dev);

3.3 中断回调函数

void serial_cb(const struct device *dev, void *user_data)
{
    // 1. 检查是否有中断需要处理
    if (!uart_irq_update(uart_dev)) return;
    
    // 2. 检查是否是 RX 就绪中断
    if (!uart_irq_rx_ready(uart_dev)) return;
    
    // 3. 读取 FIFO 直到为空
    while (uart_fifo_read(uart_dev, &c, 1) == 1) {
        // 处理字符...
    }
}

关键 API:


4. 数据流分析

用户输入字符
      ↓
[UART 硬件] 接收字符 → 存入 RX FIFO
      ↓
RX FIFO 非空 → 触发 RX 中断
      ↓
[ISR: serial_cb] 读取 FIFO 到 rx_buf
      ↓
检测到 \n 或 \r → k_msgq_put() 入队
      ↓
[Main 线程] k_msgq_get() 取出消息
      ↓
print_uart() 回显
      ↓
UART 发送

5. 发送逻辑

void print_uart(char *buf)
{
    for (int i = 0; i < strlen(buf); i++) {
        uart_poll_out(uart_dev, buf[i]);
    }
}

关键点:


6. 主循环逻辑

while (k_msgq_get(&uart_msgq, &tx_buf, K_FOREVER) == 0) {
    print_uart("Echo: ");
    print_uart(tx_buf);
    print_uart("\r\n");
}

关键:


7. 错误处理

int ret = uart_irq_callback_user_data_set(uart_dev, serial_cb, NULL);
if (ret < 0) {
    if (ret == -ENOTSUP) {
        printk("Interrupt-driven UART API support not enabled\n");
    } else if (ret == -ENOSYS) {
        printk("UART device does not support interrupt-driven API\n");
    }
}

错误码含义:


8. 配置选项 (prj.conf)

CONFIG_SERIAL=y              # 启用串口支持
CONFIG_UART_INTERRUPT_DRIVEN=y  # 启用中断驱动模式

波特率配置: 例如可在设备树 overlay 文件中设置:

&uart0 {
    current-speed = <115200>;
};

9. 关键问题总结

问题答案
波特率在哪设置?设备树 overlay 中的 current-speed

10. 学习心得

  1. 中断 vs 轮询:接收用中断(不丢数据),发送用轮询(简单场景够用)
  2. 队列解耦:ISR 只负责接收,主线程处理业务,避免 ISR 执行时间过长
  3. Zephyr 设备模型:通过设备树获取设备,支持跨平台移植

下一步:继续分析 BLE peripheral_uart,理解 BLE 协议栈初始化流程!


小白 🤖 2026-03-14