STM32串口DMA高效接收不丢包

您所在的位置:网站首页 stm32DMA串口接收缺少第一字节 STM32串口DMA高效接收不丢包

STM32串口DMA高效接收不丢包

2024-06-21 13:37| 来源: 网络整理| 查看: 265

文章目录 前言实现方法总结 前言

本文介绍使用STM32串口的DMA通道进行数据的接收,在常见的使用中,大多数人通常使用DMA一次性接收多个字节,该种用法最为简单粗暴,但是同时存在着很大的不稳定性,因为主机和从机之间上电的时间差会导致数据交互不同步,这样导致的一个结果就是从机DMA收到的数据为某一不确定时刻截取的一帧数据,这帧数据可能为两帧数据拆分合并而成的一帧数据,因此本文介绍一种DMA串口数据接收方法,每次DMA只传输一个字节数据,通过数据转存并判断等操作,进行串口数据的接收,可大大提高数据传输的稳定性。本文使用CubeMx进行配置。

实现方法

1.cubemx配置

 配置串口的DMA接收,不使能循环接收(可在软件重新使能接收,提高灵活性),一次数据传输大小选择Byte,cubemx配置DMA时自动使能DMA传输中断,在DMA触发传输中断时,会调用串口接收中断回调,因此无需使能串口接收中断。

2.实现过程

        一般完整的一帧串口数据通常包括:帧头+功能字+数据+帧尾,帧头和帧尾通常分别由2Byte组成,功能字由1Byte组成。那么具体的实现思路如下:

1、由于DMA配置为每次只0传输1Byte,传输完成后触发中断,因此我们需要每次在中断里都将该数据进行转存

2、当DMA传输完2Byte数据后,判断帧头是否正确,若帧头错误,不再接收后面的数据,并清空接收缓存数组,若帧头正确,继续接收后面的数据,直到接收到帧尾数据后,一帧数据接收完成,并返回一个状态值,表示一帧数据接收完成。

具体实现代码如下:

/* * 版本:1.0 * 修改日期:2023.3.30 * 作者:PFA SWS * 说明:此文件存放串口数据收发处理函数 * * 通信协议: * 完整数据包: 帧头+功能字+数据+帧尾 * * 帧头: 0x0b 0x0c * 帧尾: 0x0d 0x0a * * 功率功能字: 0x0a * 换挡功能字: 0x0b * 等级功能字: 0x0c */ #include "comm.h" #include /*串口数据接收初始化*/ void USART_Data_Rx_Init(USART_RX_TypeDef* p) { p->rx_temp = 0; p->rxCnt = 0; memset(p->rxBuf, 0, RXBUFLEN); } /*串口协议初始化*/ void USART_Agreement_Init(USART_AGREEMENT_TypeDef* p) { p->head1 = 0x0b; p->head2 = 0x0c; p->end1 = 0x0d; p->end2 = 0x0a; } /*串口数据接收*/ USART_RX_FLAG_Typedef USART_Data_RxState(USART_RX_TypeDef* p, USART_AGREEMENT_TypeDef* q) { p->rxBuf[p->rxCnt++] = p->rx_temp; if(p->rxCnt >= 2) { if(p->rxBuf[0] != q->head1 || p->rxBuf[1] != q->head2) { return RX_ERROR; } if(p->rxBuf[p->rxCnt-1] == q->end2 && p->rxBuf[p->rxCnt-2] == q->end1) { p->rxCnt = 0; return RX_OK; } } return RX_BUSY; }

.h文件如下

#ifndef __COMM_H #define __COMM_H #include #define RXBUFLEN 12 typedef enum { RX_OK = 0x00U, RX_ERROR = 0x01U, RX_BUSY = 0x02U }USART_RX_FLAG_Typedef; /*串口数据接收*/ typedef struct { uint8_t rx_temp; uint8_t rxCnt; uint8_t rxBuf[RXBUFLEN]; }USART_RX_TypeDef; /*串口协议*/ typedef struct { uint8_t head1; uint8_t head2; uint8_t end1; uint8_t end2; }USART_AGREEMENT_TypeDef; void USART_Data_Rx_Init(USART_RX_TypeDef*); void USART_Agreement_Init(USART_AGREEMENT_TypeDef*); USART_RX_FLAG_Typedef USART_Data_RxState(USART_RX_TypeDef*, USART_AGREEMENT_TypeDef*); #endif

通过上面代码,我们就可以实现稳定且快速的串口数据接收了,最后我们在中断回调里进行各种功能字判断,就可以得到想要的数据了

中断回调代码如下:

/*串口接收中断回调*/ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART3) { static USART_RX_FLAG_Typedef rx_state; rx_state = USART_Data_RxState(&usart_rx, &agreement); /*帧头错误,数据不更新*/ if(rx_state == RX_ERROR) { usart_rx.rxCnt = 0; //主机重新发送 } /*一帧数据接收完成*/ else if(rx_state == RX_OK) { /*功率功能字*/ if(usart_rx.rxBuf[2] == 0x0a) { /*功率解析*/ power_chassis = ((uint32_t)usart_rx.rxBuf[3]) | ((uint32_t)usart_rx.rxBuf[4]


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3