最近想尝试STM32 通过DMA收发数据,网上找了不少参考文章,最后参考https://blog.csdn.net/youmeichifan/article/details/51750435?utm_source=dlogxgwz2 博文中的方法。
按照此文的方法实现了串口的收发,但是实际使用中发现:
接收空闲中断的产生是在数据接收停止一个字节时产生的,但是有时由于上位机编写问题或硬件问题(本人用到的USB转串口的硬件有问题)上位机发送数据不连续,中间有时间间隔大于一个字节,从而造成无法完整接收数据。通过对空闲中断接收数据方法的分析,重新修改代码,实现规定数据格式的不定长数据的接收。
主要实现方法:
1、定义通讯协议:
第一个字节为起始符,我用的是0x7B
第二个字节为数据长度(包含起始符)
2、在接收空闲中断的产生时判断是否接收到合法数据(起始符),判断数据接收长度
3、增加了超时处理
以下是代码:
定义串口结构体:
#define RECEIVELEN 1024
#define USART_DMA_SENDING 1//发送未完成
#define USART_DMA_SENDOVER 0//发送完成
typedef struct
{
uint8_t receive_flag:1;//空闲接收标记
uint8_t dmaSend_flag:1;//发送完成标记
uint16_t rx_len;//接收长度
uint8_t usartDMA_rxBuf[RECEIVELEN];//DMA接收缓存
uint16_t timeOutCount;//超时计数
uint8_t timeOutState;//超时状态 1:允许超时计数 2:超时
}USART_REEIVETYPE;
变量申明:
USART_RECEIVETYPE UsartType1;
串口收发用到的函数:
//DMA发送函数
void Usart1SendData_DMA(uint8_t *pdata, uint16_t Length)
{
while(UsartType1.dmaSend_flag == USART_DMA_SENDING);
UsartType1.dmaSend_flag = USART_DMA_SENDING;
HAL_UART_Transmit_DMA(&huart1, pdata, Length);
}
//DMA发送完成中断回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
__HAL_DMA_DISABLE(huart->hdmatx);
if(huart->Instance==USART1)
UsartType1.dmaSend_flag = USART_DMA_SENDOVER;
if(huart->Instance==USART2)
UsartType2.dmaSend_flag = USART_DMA_SENDOVER;
}
//串口接收空闲中断
void Usart1Receive_IDLE(UART_HandleTypeDef *huart)
{
uint32_t temp;
uint8_t *p;
uint16_t size;
if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);
temp = huart1.hdmarx->Instance->CNDTR;
UsartType1.rx_len += RECEIVELEN - temp; //计算数据长度,RECEIVELEN - temp为本次长度
//判断是否为数据开始,判断起始位
if(UsartType1.usartDMA_rxBuf[0]==0x7b)
{
//判断接收数据长度是否符合
if(UsartType1.rx_len>2)//防止上位机在发了起始位后就有空闲中断产生
{
if(UsartType1.usartDMA_rxBuf[1]<=UsartType1.rx_len)//数据接收完整,buff[0]:数据头,buff[1]数据长度(包含头)
{
//接收标志位=1,
UsartType1.receive_flag=1;
//下次接收缓存指针从头开始,
p=UsartType1.usartDMA_rxBuf;
//接收缓存大小=RECEIVELEN,
size=RECEIVELEN;
//禁止定时器开始对timeOutCount减计数
UsartType1.timeOutState=0;
}
else
{
//下次接收缓存指针为UsartType1.usartDMA_rxBuf+已经接收到的长度,
p=UsartType1.usartDMA_rxBuf+UsartType1.rx_len;
//大小为RECEIVELEN-已经接收到的长度,
size=RECEIVELEN-UsartType1.rx_len;
//给timeout填值
UsartType1.timeOutCount=1000;
UsartType1.timeOutState=1;//允许定时器开始对timeOutCount减计数
}
}
else
{
//下次接收缓存指针为UsartType1.usartDMA_rxBuf+已经接收到的长度,
p=UsartType1.usartDMA_rxBuf+UsartType1.rx_len;
//大小为RECEIVELEN-已经接收到的长度,
size=RECEIVELEN-UsartType1.rx_len;
UsartType1.timeOutCount=1000;
UsartType1.timeOutState=1;//允许定时器开始对timeOutCount减计数
}
}
else
{
UsartType1.rx_len=0;//Reset UsartType1
p=UsartType1.usartDMA_rxBuf;
size=RECEIVELEN;
//禁止定时器开始对timeOutCount减计数
UsartType1.timeOutState=0;
}
HAL_UART_Receive_DMA(&huart1,p,size);//设置DMA接收缓存和大小,为下次接收做准备
}
}
超时计数:
我这里用的是SYSTick的中断,每1ms产生一次中断。
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
if(UsartType1.timeOutCount!=0&UsartType1.timeOutState==1)//USART1超时计数
{
UsartType1.timeOutCount--;
//判断是否发生超时
if(UsartType1.timeOutCount==0)
{
UsartType1.timeOutState=2;
UsartType1.rx_len=0;
//超时发生后,重新设置DMA缓存
HAL_UART_DMAStop(&huart1);
HAL_UART_Receive_DMA(&huart1,UsartType1.usartDMA_rxBuf,RECEIVELEN);
}
}
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
主程序初始化时,打开串口DMA接收
/* USER CODE BEGIN 2 */
HAL_UART_Receive_DMA(&huart1, UsartType1.usartDMA_rxBuf, RECEIVELEN);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
/* USER CODE END 2 */
while(1)中处理数据:
//正常接收到数据
if(UsartType1.receive_flag)
{
UsartType1.receive_flag=0;//清零标记
Usart1SendData_DMA(UsartType1.usartDMA_rxBuf,UsartType1.rx_len);//串口打印收到的数据。
UsartType1.rx_len=0;
}
//此处为超时处理
if(UsartType1.timeOutState==2)
{
UsartType1.timeOutState=0;
}
上一篇:STM32F103RCT6+串口DMA方式接收定长数据
下一篇:STM32 定时器输出比较模式和PWM输出模式的区别
推荐阅读最新更新时间:2024-03-16 16:19
设计资源 培训 开发板 精华推荐
- 市值刚刚突破万亿的特斯拉,同样难逃供应链短缺的“厄运
- 广西壮族自治区发展和改革委员会关于印发《广西新能源汽车充电基础设施规划 (2021—2025年)》的通知
- GRL扩展东莞实验室,继续加速中国布局
- 科沃斯全新品牌“KRUISEE氪见”正式亮相
- Pure Storage连续8年蝉联Gartner“主存储魔力象限”领导者地位
- ASML对话青年软件工程师:半导体发展需更多复合型软件人才
- e络盟开售瑞萨电子与Dialog联手打造的全新产品组合
- 新思科技:在智能网联汽车完整生命周期中加强软件可靠性
- ST 新MDmesh™ K6 800V STPOWER MOSFET提高能效
- Digi-Key Electronics 推出新的 Scheme-it 功能