4. 串口回显

任务目标

在Contiki-NG中实现串口回显功能:MCU通过UART接收上位机发送的字节,并将每个字节原样发送回去。通过该案例理解Contiki串口驱动的注册机制、事件驱动的字节流接收方式,以及回调函数的使用方法。

环境与依赖

  • 硬件:任意支持Contiki-NG的平台(如Zolertia RE-Mote、CC2538DK、Native模拟平台)
  • 工具链:arm-none-eabi-gcc(嵌入式平台)或gcc(Native平台)
  • 操作系统:Contiki-NG release 4.x

核心实现

Contiki-NG的串口驱动基于事件机制:当串口收到字节时,驱动层将字节放入缓冲区并触发一个回调函数。本案例通过serial_line_input注册回调,在回调中直接将收到的字节写回串口,实现回显。

#include "contiki.h"
#include "dev/serial-line.h"
#include "dev/uart1.h"
#include <stdio.h>

/* 串口接收回调函数:收到一行后原样回显 */
static int
echo_line_handler(const char *line, int len)
{
  uart1_write_bytes((const uint8_t *)line, len);
  uart1_writeb('\n');
  return 0;
}

/* 串口驱动初始化 */
static void
init_uart(void)
{
  uart1_init();
  uart1_set_input(serial_line_input_byte);
  serial_line_init();
  serial_line_set_input(echo_line_handler);
}

/* 自动启动进程 */
AUTOSTART_PROCESSES(&echo_process);

PROCESS(echo_process, "Serial echo demo");

PROCESS_THREAD(echo_process, ev, data)
{
  PROCESS_BEGIN();

  init_uart();
  printf("Serial echo ready. Type a line and press Enter.\n");

  while(1) {
    PROCESS_WAIT_EVENT();
  }

  PROCESS_END();
}

代码说明

  • uart1_init():初始化UART1外设,默认波特率115200(可在平台配置中修改)。
  • uart1_set_input():将串口接收到的每个字节送入serial_line模块进行行缓冲。
  • serial_line_set_input():注册行接收完成后的回调函数,当收到换行符时触发。
  • 回调函数echo_line_handler将整行数据通过uart1_write_bytes()原样返回,并追加一个换行符便于观察。

构建与运行

以Native平台(模拟器)为例,在Contiki-NG源码根目录执行:

make TARGET=native examples/serial-echo/serial-echo
./examples/serial-echo/serial-echo.native

嵌入式平台(如CC2538DK)则使用:

make TARGET=cc2538dk BOARD=dk examples/serial-echo/serial-echo.upload

验证方法

  1. 运行程序后,终端显示Serial echo ready提示。
  2. 在终端输入任意文本(如hello)并回车。
  3. 预期输出:终端立即显示hello(即输入内容原样返回)。
  4. 连续输入多行,每行均能正确回显,说明串口收发与字节流处理正常。

通过判定标准:所有输入行均能完整、无乱码地回显,且程序不崩溃、不卡死。

常见问题

  • 无回显:检查串口波特率是否匹配(默认115200),确认uart1_set_input已正确注册。
  • 回显乱码:多为波特率不匹配或时钟配置错误,检查平台conf文件中UART时钟源设置。
  • Native平台无输出:Native模拟器的串口映射到终端stdin/stdout,需在终端中直接输入。