历史上的今天
今天是:2024年12月10日(星期二)
2018年12月10日 | STM32的串口空闲中断接收不定长数据
2018-12-10 来源:eefocus
最近想尝试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;
}
史海拾趣
|
CE编译Directx Show播放声音,代码正常,但不能创建COM组件(问题复杂,请仔细看描述) 这几天我可被CE5头都搞大了? 先是 PlatForm Builder 编译的CE 不能播放音乐。 http://topic.eeworld.net/u/20100118/21/f22dfbcd-987f-4651-b1df-4a578fae77a2.html。编译能通过,但一播放就退出! 重装系统才解决!(这个问题解决了,但没有搞 ...… 查看全部问答> |
|
香版主您好,我手上有EKSTM32F107VC-PKT的开发板,这个板子资料只能从网上找一些,官方的好像没有,这两天在弄以太网的程序,根据http://www.stmsky.com/bbs/thread-2956-1-1.html这个帖子上的修改步骤调试程序,一改程序debug后就不能正常进 ...… 查看全部问答> |
|
本来只是想的实现一个开关的,但是最近自己拖拉了所以再加上点功能吧,这个功能就是广告灯的左右移动,不过我加了一个可以开关控单灯的输入。本来准备430也是一样的不过今天拿到开发板发现没有那么多LED⊙﹏⊙,所以就直接用数码管了。 #include ...… 查看全部问答> |
|
本帖最后由 paulhyde 于 2014-9-15 03:53 编辑 最近一直在调ADS1115这款AD,用I/O口模拟的I2C时序,结果总是不理想。读出来的数字我表示看不出规律,输入什么都不接有的时候是满值65535,有的时候乱跳。下面是我的程序,大家看下。我感觉我写的时 ...… 查看全部问答> |
|
首先简单介绍一下这个系统,该系统由矩阵键盘、电源模块、PSOC4、lcd12864、舵机2个、亚克力板2块黑色、支架一套、角度传感器一个、语音模块 介绍系统的功能:可以任意设置平台倾斜的角度,只需使用按键输入你想设定的方向即可,平台会根据角度传 ...… 查看全部问答> |




