在线时间2288 小时
UID3253523
注册时间2016-3-21
NXP金币2486
该用户从未签到
超级版主
 
- 积分
- 28578
- 最后登录
- 2026-8-25
|
本帖最后由 小恩GG 于 2026-7-13 18:08 编辑
概述
在串口通信应用中,我们经常会遇到 不定长数据接收 的需求,例如上位机发送一条 AT 命令,或者传感器输出一帧可变长度的数据。传统的定长接收方式(如接收固定 16 字节)显然无法满足需求,因此需要一种机制来自动识别一帧数据的结束位置。
目前SDK中的例子都为lpuart 定长接收。
本文基于 NXP MCXA156 MCU,介绍一种常用的 不定长接收实现方法:
硬件环境:
开发板:FRDM-MCXA156
软件环境:
IDE:MCUXpresso IDE v11.9.0
SDK:SDK Builder | MCUXpresso SDKBuilder (nxp.com)
基础工程: frdmmcxa156_lpuart_edma_transfer
1. 设计思路
本方案的设计目标是:支持 UART 不定长接收,同时尽量减少 CPU 负担。整体思路如下:
a. DMA 自动接收
使用 eDMA 将 UART 接收数据直接搬运到内存缓冲区,避免逐字节触发中断,提高效率。
b. 空闲中断识别帧结束
当一帧数据接收完成后,UART 硬件会检测到总线空闲并触发 Idle Line 中断。该信号可作为数据帧结束的标志。
c. 计算接收长度
在中断中查询 eDMA 的剩余传输字节数,从而计算实际接收的数据长度。
d. 数据交付处理
将接收到的数据交给应用层进行解析、存储或回显。
e. 重新启动接收
在处理完成后,重新启动 eDMA 接收,为下一帧数据做好准备。
2. 使用限制与注意事项
需要注意的是,本方案基于 UART Idle Line 中断判断一帧数据结束,在实际应用中需满足以下使用条件和约束:
a. Idle 时间与波特率相关
UART 的 Idle 判定时间通常约为 1 个字符时间(Character Time),该时间随波特率变化而变化。例如在 115200bps 下,约为 86μs。
因此,Idle 中断并不等价于严格的帧结束标志,仅适用于帧与帧之间存在明显空闲间隔的场景。
b. 需要保证帧间最小间隔
应用层需保证相邻数据帧之间存在足够的空闲间隔,例如:
Frame1 → Idle → Frame2
若帧间隔过小,可能导致:
- Idle 中断未能及时触发或处理
- DMA 仍处于当前传输状态
- 下一帧数据已开始写入缓冲区
从而引发数据粘包或帧截断问题。
c. 受系统处理能力限制
该方案依赖 “Idle 中断 + DMA 重启” 机制,因此系统需满足一定实时性要求:
- UART 波特率不能过高
- CPU 能够及时响应 Idle 中断
- DMA 重启时间小于帧间间隔
否则可能导致数据丢失或帧边界识别错误。
3. 实现方法
3.1 数据处理函数
- void ProcessReceivedData(uint8_t *data, size_t length)
- {
- // 回显数据
- LPUART_WriteBlocking(DEMO_LPUART, data, length);
- PRINTF("length=%d.\r\n", length);
- }
复制代码 3.2 UART 中断回调函数
- void DEMO_LPUART_IRQHandler(void)
- {
- uint32_t flags = LPUART_GetStatusFlags(DEMO_LPUART);
- if (flags & kLPUART_IdleLineFlag)
- {
- // 清除空闲中断标志
- LPUART_ClearStatusFlags(DEMO_LPUART, kLPUART_IdleLineFlag);
- if (g_lpuartEdmaHandle.rxState == kLPUART_RxBusy)
- {
- // 计算已接收的数据长度
- size_t remaining = EDMA_GetRemainingMajorLoopCount(
- g_lpuartEdmaHandle.rxEdmaHandle->base,
- g_lpuartEdmaHandle.rxEdmaHandle->channel);
-
- LPUART_TransferAbortReceiveEDMA(DEMO_LPUART, &g_lpuartEdmaHandle);
- size_t receivedLength = RX_DMA_BUFFER_SIZE - remaining;
- // 数据交给上层处理
- ProcessReceivedData(g_rxBuffer, receivedLength);
- // 重启 DMA 接收
- lpuart_transfer_t receiveXfer;
- receiveXfer.data = g_rxBuffer;
- receiveXfer.dataSize = RX_DMA_BUFFER_SIZE;
- LPUART_ReceiveEDMA(DEMO_LPUART, &g_lpuartEdmaHandle, &receiveXfer);
- }
- }
- }/
复制代码 3.3 主函数初始化
- int main(void)
- {
- BOARD_InitHardware();
- // UART 初始化
- // eDMA 初始化和绑定
- // ... 省略配置 ...
- // 开启空闲中断
- LPUART_EnableInterrupts(DEMO_LPUART, kLPUART_IdleLineInterruptEnable);
- EnableIRQ(DEMO_LPUART_IRQn);
- // 启动首次接收
- lpuart_transfer_t receiveXfer;
- receiveXfer.data = g_rxBuffer;
- receiveXfer.dataSize = RX_DMA_BUFFER_SIZE;
- LPUART_ReceiveEDMA(DEMO_LPUART, &g_lpuartEdmaHandle, &receiveXfer);
- while (1)
- {
- // 主循环空转
- }
- }
复制代码
4. 系统流程图
5. 测试结果
在实验中,MCXA156 LPUART 被配置为 115200bps,接收来自上位机的变长数据。测试结果如下:
当上位机发送 14 字节数据时,系统正确接收到长度为 14 的数据,并回显。
6. 结语
本文基于 MCXA156 MCU,利用 UART Idle Line 中断 + eDMA 实现了 不定长串口接收。该方案具有以下优点:
灵活性:支持任意长度数据帧,无需固定长度缓冲区;
高效性:DMA 自动搬运数据,CPU 仅在帧结束时介入;
可靠性:利用 UART 硬件的 Idle Line 信号,避免了基于定时器的软件超时判定。
该方法特别适用于 变长协议通信、AT 命令解析、传感器数据采集、工业协议(如 Modbus) 等场景,能够显著提高系统的实时性与可靠性。
|
|