基于小智派-LZ3863星闪开发版:OpenHarmony UART 外设开发 — UART2 串口通信

📅 2026/7/22 2:23:19
基于小智派-LZ3863星闪开发版:OpenHarmony UART 外设开发 — UART2 串口通信
1、实验简介参考网址https://gitee.com/Lockzhiner-Electronics/lz3863/tree/master/apps/b6_uart21.1、实验目的本实验旨在帮助学习者掌握 OpenHarmony 轻量系统中UARTUniversal Asynchronous Receiver/Transmitter通用异步收发器外设的基本使用方法。通过本实验你将学会理解 UART 串口通信的工作原理及帧格式使用 IoT Hardware 接口配置 GPIO 引脚复用为 UART2 的 TXD/RXD掌握 UART 中断回调接收模式实现非阻塞数据接收实现串口回声Echo功能完成数据的接收与回发完成案例代码的编译、烧录与串口现象观察。1.2、实验内容本案例在 LZ3863-星闪开发板上通过UART2接口实现与外部设备如 PC 端 USB 转串口模块的双向通信。开发板接收外部发送的数据后自动将数据以[Echo]前缀回发并在串口输出接收与发送日志。项目说明UART 端口UART2UART_ID 2RXD 引脚GPIO7IOT_IO_FUNC_GPIO_7_UART2_RXDTXD 引脚GPIO8IOT_IO_FUNC_GPIO_8_UART2_TXD波特率115200数据格式8 位数据位、1 位停止位、无校验8N1接收模式非阻塞 中断回调发送模式阻塞发送接收缓冲区64 字节RECV_BUF_SIZE初始化入口uart2_callback_only_init程序在系统启动时通过APP_FEATURE_INIT自动完成 UART2 初始化注册接收中断回调后进入待命状态当外部设备发送数据时回调函数自动处理接收、日志打印与回声回发无需主线程轮询。1.3、实验环境项目说明硬件LZ3863-星闪开发板、USB 数据线、USB 转串口模块或杜邦线连接 PC 串口软件OpenHarmony v5.1.0 源码、hb 编译工具、串口调试助手调试工具串口助手波特率 1152008N1案例路径applications/sample/wifi-iot/app/b6_uart2/2、基础知识2.1、什么是 UARTUART通用异步收发器是一种常用的异步串行通信接口仅需TXD发送和RXD接收两根信号线外加 GND 地线即可实现设备间的点对点数据传输。UART 通信的核心特点概念说明异步通信无需共享时钟线收发双方通过约定的波特率同步全双工TXD 与 RXD 独立可同时发送和接收帧格式通常包含起始位、数据位、可选校验位、停止位点对点两设备间直接连接不支持多设备总线挂载本实验采用8N1格式8 位数据位、无校验位None、1 位停止位波特率 115200 bps。2.2、UART 硬件连接UART 通信采用交叉连接方式外部设备 TXD ──→ 开发板 RXDGPIO7 / UART2_RXD 外部设备 RXD ←── 开发板 TXDGPIO8 / UART2_TXD 外部设备 GND ──→ 开发板 GND注意UART 为 TTL 电平通常 3.3 V请勿直接与 RS-232 电平设备连接需使用电平转换模块。2.3、引脚复用MuxWS63 芯片的 GPIO7、GPIO8 可复用为 UART2 的 RXD 和 TXD。使用前必须通过IoSetFunc()将引脚功能设置为 UART 模式IoSetFunc(IOT_IO_NAME_GPIO_7,IOT_IO_FUNC_GPIO_7_UART2_RXD);// GPIO7 - UART2_RXDIoSetFunc(IOT_IO_NAME_GPIO_8,IOT_IO_FUNC_GPIO_8_UART2_TXD);// GPIO8 - UART2_TXD2.4、中断回调接收模式本案例采用中断回调模式接收数据相比轮询方式具有以下优势对比项轮询模式中断回调模式CPU 占用需持续查询接收缓冲区有数据时才触发处理实时性取决于轮询间隔数据到达即响应代码结构主循环中反复调用IoTUartRead()注册回调函数事件驱动工作流程外部设备发送数据 → UART 硬件接收 → 触发接收中断 → 调用 uart2_rx_callback() → 拷贝数据 → 打印日志 → 回声回发2.5、软件调用层次本案例的软件调用层次如下应用层uart2_example.c ├── IoSetFunc() ← 引脚复用为 UART2 ├── IoTUartInit() ← 初始化 UART 通信参数 ├── uapi_uart_register_rx_callback() ← 注册接收中断回调 ├── uapi_uart_write() ← 发送数据 └── uart2_rx_callback() ← 接收中断回调处理 └── uart2_log() ← 格式化日志输出 └── IoT Hardware / HAL 层2.6、核心 API 介绍2.6.1、头文件#includestdio.h#includestring.h#includestdarg.h#includestdbool.h#includeohos_init.h#includecmsis_os2.h#includeiot_gpio.h#includeiot_gpio_ex.h#includeiot_uart.h#includeiot_errno.h#includeuart.h2.6.2、UART 常用 APIAPI 名称功能说明IoSetFunc设置引脚复用功能UART TXD/RXDIoTUartInit初始化 UART 端口配置波特率、数据位等参数IoTUartRead主动读取 UART 接收缓冲区数据轮询模式IoTUartWrite向 UART 发送数据IoT Hardware 层uapi_uart_write向 UART 发送数据驱动层支持超时控制uapi_uart_register_rx_callback注册 UART 接收中断回调函数2.6.3、IoTUartInit — 初始化 UARTunsignedintIoTUartInit(unsignedintid,constIotUartAttribute*param);参数说明idUART 端口号本案例为2UART2param指向IotUartAttribute结构体配置通信参数IotUartAttribute结构体主要字段字段说明baudRate波特率如115200dataBits数据位如IOT_UART_DATA_BIT_8stopBits停止位如IOT_UART_STOP_BIT_1parity校验位如IOT_UART_PARITY_NONErxBlock接收阻塞模式IOT_UART_BLOCK_STATE_NONE_BLOCK表示非阻塞txBlock发送阻塞模式IOT_UART_BLOCK_STATE_BLOCK表示阻塞发送2.6.4、uapi_uart_register_rx_callback — 注册接收回调errcode_tuapi_uart_register_rx_callback(uart_bus_tbus,uart_rx_condition_tcondition,uint16_tthreshold,UartRxCallbackFunc callback);参数说明busUART 总线编号本案例为2condition触发条件本案例为UART_RX_CONDITION_FULL_OR_IDLE缓冲区满或空闲时触发threshold触发阈值字节数本案例为1收到 1 字节即触发callback接收回调函数指针2.6.5、uapi_uart_write — 发送数据intuapi_uart_write(uart_bus_tport,constuint8_t*data,uint32_tlen,uint32_ttimeout);参数说明portUART 端口号data待发送数据缓冲区指针len发送数据长度字节timeout超时时间本案例使用1表示阻塞等待发送完成2.6.6、APP_FEATURE_INIT — 应用入口注册APP_FEATURE_INIT(uart2_callback_only_init);该宏将uart2_callback_only_init注册为应用特性初始化函数系统启动完成后自动调用无需手动修改main()函数。3、程序设计3.1、程序架构本案例目录结构b6_uart2/ ├── uart2_example.c # 主程序源码 ├── BUILD.gn # GN 编译配置 ├── README_zh.md # 案例简要说明 └── 实验手册.md # 本实验手册本案例采用事件驱动 中断回调结构系统启动 │ ▼ uart2_callback_only_init() ← APP_FEATURE_INIT 注册系统启动时自动执行 │ ▼ uart2_init() ← UART2 初始化 ├── IoSetFunc() ← GPIO7/8 复用为 UART2 RXD/TXD ├── IoTUartInit() ← 配置 115200 8N1 ├── uapi_uart_register_rx_callback() ← 注册接收回调 └── 输出启动信息 hello uart2 │ ▼外部设备发送数据时触发 uart2_rx_callback() ← 接收中断回调 ├── 防重入保护 数据拷贝 ├── uart2_log() 打印接收日志 ├── 构建 [Echo] xxx 回发数据 └── uapi_uart_write() 发送回声3.2、源文件说明文件说明uart2_example.c主程序源码包含 UART2 初始化、接收回调与回声逻辑BUILD.gnGN 编译配置文件定义静态库uart2_example3.3、关键代码分析1宏定义 — UART 核心配置#defineUART_ID2// 目标 UART 端口号UART2#defineBAUDRATE115200// 通信波特率#defineRECV_BUF_SIZE64// 接收数据缓冲区大小#defineRX_TRIGGER_THRESHOLD1// 接收中断触发阈值1 字节触发#defineLOG_BUF_SIZE128// 日志格式化缓冲区大小2全局变量 — 状态与缓冲区staticunsignedcharg_recv_buf[RECV_BUF_SIZE]{0};// 接收数据缓冲区staticvolatilebool g_is_rx_processingfalse;// 接收处理状态标记防中断重入staticvolatilebool g_uart2_initedfalse;// UART2 初始化完成标记g_is_rx_processing用于防止回调函数重入若上一次接收尚未处理完毕新的中断将被忽略。3UART2 初始化 — uart2_inituart2_init完成引脚复用、UART 参数配置、接收回调注册并在成功后输出启动信息staticintuart2_init(void){// 配置 GPIO 引脚功能复用为 UART2 的 RXD 和 TXDIoSetFunc(IOT_IO_NAME_GPIO_7,IOT_IO_FUNC_GPIO_7_UART2_RXD);IoSetFunc(IOT_IO_NAME_GPIO_8,IOT_IO_FUNC_GPIO_8_UART2_TXD);// 配置 UART 通信参数8 位数据位1 位停止位无校验位IotUartAttribute uart_attr{.baudRateBAUDRATE,.dataBitsIOT_UART_DATA_BIT_8,.stopBitsIOT_UART_STOP_BIT_1,.parityIOT_UART_PARITY_NONE,.rxBlockIOT_UART_BLOCK_STATE_NONE_BLOCK,// 接收非阻塞中断模式.txBlockIOT_UART_BLOCK_STATE_BLOCK,// 发送阻塞.pad0};if(IoTUartInit(UART_ID,uart_attr)!IOT_SUCCESS){return-1;}// 注册接收中断回调函数errcode_tretuapi_uart_register_rx_callback(UART_ID,UART_RX_CONDITION_FULL_OR_IDLE,RX_TRIGGER_THRESHOLD,uart2_rx_callback);if(ret!ERRCODE_SUCC){return-1;}g_uart2_initedtrue;uart2_log(UART2 Init Success! Baudrate: %d\n,BAUDRATE);uapi_uart_write(UART_ID,(uint8_t*)hello uart2\n,12,1);return0;}4接收中断回调 — uart2_rx_callback当 UART2 接收到数据时驱动自动调用此回调函数完成数据拷贝、日志打印与回声回发staticvoiduart2_rx_callback(constvoid*buffer,uint16_tlength,bool error){unused(error);// 防重入保护 有效性校验if(g_is_rx_processing||bufferNULL||length0||lengthRECV_BUF_SIZE){return;}g_is_rx_processingtrue;// 拷贝接收数据到本地缓冲区memcpy(g_recv_buf,buffer,length);g_recv_buf[length]\0;// 打印接收日志uart2_log(Recv: Len%d, Data%s\n,length,g_recv_buf);// 构建回发数据charsend_back_buf[RECV_BUF_SIZE20]{0};snprintf(send_back_buf,sizeof(send_back_buf),[Echo] %s\n,g_recv_buf);// 发送回声数据intsend_lenuapi_uart_write(UART_ID,(uint8_t*)send_back_buf,strlen(send_back_buf),1);if(send_len0){uart2_log(Echo Send: Len%d, Data%s,send_len,send_back_buf);}else{uart2_log(Echo Send Failed! Len: %d\n,send_len);}g_is_rx_processingfalse;}5日志打印 — uart2_loguart2_log是 UART2 专用日志函数仅在初始化完成后生效通过vsnprintf格式化后发送到 UART2staticvoiduart2_log(constchar*format,...){if(!g_uart2_inited)return;va_list args;va_start(args,format);charlog_buf[LOG_BUF_SIZE]{0};vsnprintf(log_buf,LOG_BUF_SIZE-1,format,args);va_end(args);uapi_uart_write(UART_ID,(uint8_t*)log_buf,strlen(log_buf),1);}6应用启动入口 — uart2_callback_only_init系统启动后通过APP_FEATURE_INIT宏自动调用此函数完成 UART2 初始化staticvoiduart2_callback_only_init(void){if(uart2_init()!0){uapi_uart_write(UART_ID,(uint8_t*)UART2 Init Failed!\n,18,1);}}APP_FEATURE_INIT(uart2_callback_only_init);3.4、程序执行流程外部设备(PC)uart2_rx_callbackUART2 硬件uart2_callback_only_init系统启动外部设备(PC)uart2_rx_callbackUART2 硬件uart2_callback_only_init系统启动APP_FEATURE_INIT 触发IoSetFunc(GPIO7/8) IoTUartInit()uapi_uart_register_rx_callback()hello uart2 初始化成功日志发送数据 OpenHarmony触发接收中断回调拷贝数据 打印 Recv 日志uapi_uart_write([Echo] OpenHarmony)回发回声数据打印 Echo Send 日志4、编译步骤4.1、确认案例目录确认案例已位于 OpenHarmony 源码目录下applications/sample/wifi-iot/app/b6_uart2/ ├── uart2_example.c ├── BUILD.gn ├── README_zh.md └── 实验手册.md若从外部复制请将b6_uart2目录放到上述app/路径下。4.2、修改 BUILD.gn注册编译组件编辑applications/sample/wifi-iot/app/BUILD.gn在features列表中添加本案例lite_component(app) { features [ startup, b6_uart2:uart2_example, // 添加此行 ] }4.3、修改 SDK 配置文件步骤 1编辑device/soc/hisilicon/ws63v100/sdk/build/config/target_config/ws63/config.py找到ws63-liteos-app配置段在其ram_component列表中添加uart2_example步骤 2编辑device/soc/hisilicon/ws63v100/sdk/libs_url/ws63/cmake/ohos.cmake找到ws63-liteos-app对应的set(COMPONENT_LIST部分添加uart2_example4.4、执行编译在 OpenHarmony 源码根目录下执行rm-rfout hbset-root.# 通过上下方向键选择 ws63 对应的编译分支如 nearlink_dk_3863 / ws63-liteos-apphb build-f编译成功后固件输出路径通常在out/ws63/目录下。4.5、烧录固件使用开发板配套的烧录工具将编译生成的固件烧写到 LZ3863-星闪开发板。具体烧录步骤请参考开发板用户手册。5、运行结果5.1、硬件连接将 USB 转串口模块与开发板 UART2 引脚连接USB 转串口模块开发板引脚说明TXDGPIO7UART2_RXD模块发送 → 开发板接收RXDGPIO8UART2_TXD开发板发送 → 模块接收GNDGND共地5.2、串口配置打开 PC 端串口调试助手配置参数如下参数值波特率115200数据位8停止位1校验位无流控无5.3、预期现象烧录并复位开发板后串口助手可观察到1上电初始化输出hello uart2 UART2 Init Success! Baudrate: 1152002发送数据后的回声响应在串口助手发送区输入OpenHarmony并发送接收区将显示Recv: Len12, DataOpenHarmony [Echo] OpenHarmony Echo Send: Len20, Data[Echo] OpenHarmony其中Recv行为开发板接收日志显示接收字节数与内容[Echo] OpenHarmony为开发板回发的回声数据Echo Send行为回发日志显示发送字节数与内容。5.4、结果分析现象说明输出hello uart2UART2 初始化成功发送通道正常输出UART2 Init Success!uart2_log()日志函数工作正常收到[Echo] xxx接收中断回调触发成功回声逻辑正常无任何输出可能引脚连接错误或波特率不匹配输出乱码波特率或数据格式配置不一致输出UART2 Init Failed!GPIO 复用或 UART 初始化失败输出Register UART RX Callback Failed!接收回调注册失败5.5、常见问题排查问题可能原因解决方法完全无串口输出案例未加入编译或烧录了错误固件核对 4.2、4.3 节三处配置重新编译烧录有初始化信息但发送无响应TXD/RXD 接反或未共地确认交叉连接模块 TXD → 开发板 RXDGPIO7接收数据乱码波特率不一致确认双方均为 115200 8N1只能收不能发或反之单根信号线接触不良检查杜邦线连接测量引脚电压快速连续发送丢数据接收缓冲区仅 64 字节降低发送频率或增大RECV_BUF_SIZE编译报错找不到uart2_exampleBUILD.gn 或 config.py 未正确修改逐步核对 4.2、4.3 节的配置项6、实验扩展完成基本实验后可尝试以下扩展练习修改波特率将BAUDRATE改为9600或921600观察通信是否正常理解波特率匹配的重要性轮询接收对比去掉中断回调改用osThreadNew创建线程循环调用IoTUartRead()对比 CPU 占用与响应延迟协议解析在回调中解析固定格式的命令如LED ON\r\n结合b1_led_gpio案例控制 LED 亮灭数据透传将 UART2 接收的数据转发到 UART0调试串口实现双串口透传网关超时组帧利用UART_RX_CONDITION_FULL_OR_IDLE的空闲触发特性实现按帧接收不定长数据包增大缓冲区修改RECV_BUF_SIZE为 256 或 512测试长数据包的接收与回声能力结合传感器实验配合其他外设案例将传感器读数通过 UART2 定时上报给上位机。