历史上的今天
返回首页

历史上的今天

今天是: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;

 

 

  }


推荐阅读

史海拾趣

康龙(CONCRAFT)公司的发展小趣事

随着公司实力的不断增强,康龙开始积极拓展国内外市场。公司先后在美国、欧洲等地设立了销售机构,与多家国际知名企业建立了长期稳定的合作关系。同时,康龙还积极参与国际展会和交流活动,提升品牌知名度和影响力。通过不懈的努力,康龙的产品已经成功打入国际市场,并赢得了客户的广泛赞誉。

Allen Avionics Inc公司的发展小趣事

面对电子行业的快速变化和发展趋势,康龙公司积极拥抱数字化转型。公司引入了先进的ERP系统和数字化工具,实现了从供应链、生产管理到财务管理的全面信息化。这不仅提高了公司的运营效率和管理水平,还为公司的产业升级和未来发展奠定了坚实基础。

HTSEMI( Jin Yu Semiconductor )公司的发展小趣事

为了进一步提升技术实力,金宇半导体积极与国内外知名高校和科研机构建立合作关系。2010年,公司与某顶尖大学联合成立了“先进半导体技术研究中心”,共同开展前沿技术的研发。通过产学研的紧密合作,金宇半导体在先进制程工艺、芯片封装测试等领域取得了重大突破,成功推出了多款具有自主知识产权的高端芯片产品,进一步巩固了其在行业内的领先地位。

BOOKHAM公司的发展小趣事

BOOKHAM公司自创立之初,就专注于光学元件的研发和生产。随着电子行业的快速发展,公司不断投入研发资源,终于在一次技术突破中,成功开发出一款高性能的光学元件。这款元件凭借其卓越的性能和稳定的品质,迅速获得了市场的认可,BOOKHAM公司也因此名声大噪,逐渐在电子行业中崭露头角。

ApexTool Group公司的发展小趣事

随着全球电子市场的不断扩大,Apex Tool Group积极实施全球化战略,拓展市场版图。公司在全球范围内建立了多个生产基地和分销网络,以便更好地服务全球客户。同时,Apex Tool Group还积极与全球知名的电子企业开展合作,共同推动电动工具技术的创新和发展。这些举措使得Apex Tool Group在全球电子行业中的地位日益稳固。

Corex Intervest Inc公司的发展小趣事

在技术创新和产品创新的基础上,Corex Intervest Inc公司开始积极拓展市场。公司通过参加国际电子展览、与各大电商平台合作等方式,不断提升品牌知名度和影响力。同时,公司还注重与客户的沟通与合作,根据客户需求定制产品方案,赢得了客户的广泛信任和好评。

问答坊 | AI 解惑

毕业论文 无线电子音乐门铃

哪位朋友有。帮帮忙吧! zhengzhouyuchao@126.com…

查看全部问答>

CE编译Directx Show播放声音,代码正常,但不能创建COM组件(问题复杂,请仔细看描述)

这几天我可被CE5头都搞大了? 先是 PlatForm Builder 编译的CE 不能播放音乐。 http://topic.eeworld.net/u/20100118/21/f22dfbcd-987f-4651-b1df-4a578fae77a2.html。编译能通过,但一播放就退出! 重装系统才解决!(这个问题解决了,但没有搞 ...…

查看全部问答>

mc55模块上电20秒后自动关机问题

将mc55模块/IGT引脚置低电平后,mc55模块上电开机,但20秒后mc55模块会自动关机.每次都是这样,找不到原因,请各位指教.谢谢…

查看全部问答>

wince4.2 USB口为什么会出现这种现象

当我插上u盘的时候,不出现盘标。但是当我拔掉u盘的时候就出现盘标了!这是怎么回事!有谁遇到过这中问题,如何解决?…

查看全部问答>

求教香版主EKSTM32F107VC-PKT问题

香版主您好,我手上有EKSTM32F107VC-PKT的开发板,这个板子资料只能从网上找一些,官方的好像没有,这两天在弄以太网的程序,根据http://www.stmsky.com/bbs/thread-2956-1-1.html这个帖子上的修改步骤调试程序,一改程序debug后就不能正常进 ...…

查看全部问答>

51下广告灯数码管和MSP430数码管

本来只是想的实现一个开关的,但是最近自己拖拉了所以再加上点功能吧,这个功能就是广告灯的左右移动,不过我加了一个可以开关控单灯的输入。本来准备430也是一样的不过今天拿到开发板发现没有那么多LED⊙﹏⊙,所以就直接用数码管了。 #include ...…

查看全部问答>

关于ADS1115的一点问题

本帖最后由 paulhyde 于 2014-9-15 03:53 编辑 最近一直在调ADS1115这款AD,用I/O口模拟的I2C时序,结果总是不理想。读出来的数字我表示看不出规律,输入什么都不接有的时候是满值65535,有的时候乱跳。下面是我的程序,大家看下。我感觉我写的时 ...…

查看全部问答>

【PSOC4心得】6个夜晚完成了系统,智能调整平台分享

首先简单介绍一下这个系统,该系统由矩阵键盘、电源模块、PSOC4、lcd12864、舵机2个、亚克力板2块黑色、支架一套、角度传感器一个、语音模块 介绍系统的功能:可以任意设置平台倾斜的角度,只需使用按键输入你想设定的方向即可,平台会根据角度传 ...…

查看全部问答>