STM32之HAL库串口USART丢数据及ORE卡死的解决方案_第1页
STM32之HAL库串口USART丢数据及ORE卡死的解决方案_第2页
STM32之HAL库串口USART丢数据及ORE卡死的解决方案_第3页
STM32之HAL库串口USART丢数据及ORE卡死的解决方案_第4页
STM32之HAL库串口USART丢数据及ORE卡死的解决方案_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

STM32之HAL库串口USART丢数据及ORE卡死的解决方案刚装了VS2019Preview,VS2017系列应该还有最后一章就结束了,找个时间结束掉它。昨晚弄了下STM32的串口通信,发现UART在接收PC串口调试助手发送的数据的时候,会时不时卡死,不能接收新的数据。之前公司有人做这方面的项目的时候也是这个情况,当时发现UART处于ORE(overrunerror)状态,归结为波特率太高,降低波特率算妥协了。结果自己弄Nucleo的开发板也出现这个情况,我想STM官方开发板应该不至于只能跑低速通信。没办法查查吧。首先把ORE的检测关掉。这个东西吧,有啥意义呢?Overrun检测是好的,可以告诉系统目前通信超负荷然后进行调整。但是目前99%以上的开发者都不会管这个东西,另外他们也没有这么极限数据率通信的需求。如果要检测ORE,你的系统中一定要有UART的Errorhandler函数,进行ORE出现时的状态寄存器清理和系统调整。否则就会出现系统被卡死再也无法通信的情况。这个ORE的检测是CubeMX默认打开的,在UART的配置里面,如下(我这是5.0CubeMX):代码里面是这两句(我的CubeMX和MDK都是最新版,可能老版本不一样,如果没有就写ErrorHandler进行错误位复位):huart2.AdvancedInit.OverrunDisable=UART_ADVFEATURE_OVERRUN_DISABLE;huart2.AdvancedInit.DMADisableonRxError=UART_ADVFEATURE_DMA_DISABLEONRXERROR;---------------------------------------------------------2019/6/25更新--------------------------------------------------------------------试了下STM32F103RC并没有这个OverrunDisable开关,之前还认为是CubeMX更新后带来的新特性。如果没有的话那就需要自己写ErrorCallback函数了,如下:/***@briefUARTerrorcallback.*@paramhuartUARThandle.*@retvalNone*/voidHAL_UART_ErrorCallback(UART_HandleTypeDef*huart){/*Preventunusedargument(s)compilationwarning*/if(huart->ErrorCode&HAL_UART_ERROR_ORE){__HAL_UART_CLEAR_OREFLAG(huart);}/*NOTE:Thisfunctionshouldnotbemodified,whenthecallbackisneeded,theHAL_UART_ErrorCallbackcanbeimplementedintheuserfile.*/}这是一个weak函数,把这个函数实现在自己的c文件里就可以覆盖原来的那个。初步测试了下,在Overrun以后能够继续工作,但是发生ORE时肯定会丢数据。所以还是要从根本上去解决ORE出现的原因。-------------------------------------------------------------------------------------------------------------------------------------------------这样就关掉了ORE的检测,现在会出现接收不全数据的情况,但是UART不会卡死,会继续接收新的数据。然而上面的操作实际上没有解决真正的问题,因为并非由于Overrun导致的ORE。换句话来说,目前的数据率和读写操作不可能Overrun。我的main函数代码如下:while(1){/*USERCODEENDWHILE*//*USERCODEBEGIN3*/uint16_trxSize=UART_RXBUF_SIZE;if(USER_UART_Receive(&huart2,uartRxBuf,&rxSize,10)==HAL_OK){HAL_UART_Transmit(&huart2,uartRxBuf,rxSize,10);}}收到什么返回什么,经典测试代码。Overrun指UART处理不了当前的数据率。115200BPS,一收一发显然不满足。所以还是怀疑是库函数有问题。今天晚上回家找了下网上的解决方案,都和我的情况不一样(HAL果然坑)。于是自己开始一点点调试HAL的UART读写代码,基本上认定问题出现在HAL_UART_Receive这个函数。BUG大概就是每次进行读操作时会有个超时,这个超时的作用是如果UART在这个时间内没有收到期望的数据量那么函数就返回TIMEOUT。上面我的代码里设置的超时时间是10ms,看似足够了,但是实际上存在一种错误状态。该状态如下图所示:看完上图应该明白为什么这么低的数据率会ORE了。找到问题解决起来也很简单,改HAL的HAL_UART_Receive代码如下://这是我重写的UART接收函数,除了修复超时导致的丢数据问题以外,增加了//超时后返回当前读取到的数据量,这样可以读不定长帧。目标接收20Byte,//实际发送了10Byte,那么pSize为10,也就是实际接收到的数据量。HAL_StatusTypeDefUSER_UART_Receive(UART_HandleTypeDef*huart,uint8_t*pData,uint16_t*pSize,uint32_tTimeout){uint8_t*pdata8bits;uint16_t*pdata16bits;uint16_tuhMask;uint32_ttickstart;//这里是保证原来的代码结构uint16_tSize=*pSize;//记录第一个数据的到来时间uint8_tfirstData=0;/*CheckthataRxprocessisnotalreadyongoing*/if(huart->RxState==HAL_UART_STATE_READY){if((pData==NULL)||(Size==0U)){returnHAL_ERROR;}/*Incaseof9bits/NoParitytransfer,pDatabufferprovidedasinputparametershouldbealignedonau16frontier,asdatatobereceivedfromRDRwillbehandledthroughau16cast.*/if((huart->Init.WordLength==UART_WORDLENGTH_9B)&&(huart->Init.Parity==UART_PARITY_NONE)){if((((uint32_t)pData)&1)!=0){returnHAL_ERROR;}}/*ProcessLocked*/__HAL_LOCK(huart);huart->ErrorCode=HAL_UART_ERROR_NONE;huart->RxState=HAL_UART_STATE_BUSY_RX;/*Inittickstartfortimeoutmanagment*/tickstart=HAL_GetTick();huart->RxXferSize=Size;huart->RxXferCount=Size;/*ComputationofUARTmasktoapplytoRDRregister*/UART_MASK_COMPUTATION(huart);uhMask=huart->Mask;/*Incaseof9bits/NoParitytransfer,pRxDataneedstobehandledasauint16_tpointer*/if((huart->Init.WordLength==UART_WORDLENGTH_9B)&&(huart->Init.Parity==UART_PARITY_NONE)){pdata8bits=NULL;pdata16bits=(uint16_t*)pData;}else{pdata8bits=pData;pdata16bits=NULL;}/*aslongasdatahavetobereceived*/while(huart->RxXferCount>0U){if(UART_WaitOnFlagUntilTimeout(huart,UART_FLAG_RXNE,RESET,tickstart,Timeout)!=HAL_OK){//这里是超时退出,我在这里把当前接收到的数据量写入pSize返回//目前只支持数据量低于期望Size的不定长数据,超过你的接收数量还是可能出现ORE错误*pSize=*pSize-huart->RxXferCount;returnHAL_TIMEOUT;}//如果是定长帧这个超时时间就是通过波特率计算出的整个帧的超时时间,比如上图中的20byte的通信时间为1.73ms,那么设置一个2ms就差不多了//这里记录下第一个byte到来的时间,从这个时间开始计时,这个超时时间一定要和你的接收数据量相匹配#ifFIXEDSIZEif(firstData==0){tickstart=HAL_GetTick();firstData=1;}#else//如果是不定长接收,这个超时时间改为单byte的超时时间,如115200下一个byte通信时间大概为0.086ms//同时代码改为每个byte都更新超时计时开始时间。理论上可以一次性接收你能开空间大小的帧长。//比较推荐这种判断,对系统整体的阻塞较小。超时时间和数据接收量无关。tickstart=HAL_GetTick();#endifif(pdata8bits==NULL){*pdata16bits=(uint16_t)(huart->Instance->RDR&uhMask);pdata16bits++;}else{*pdata8bits=(uint8_t)(huart->Instance->RDR&(uint8_t)uhMask);pdata8bits++;}huart->RxXferCount--;}/*AtendofRxprocess,restorehuart->RxStatetoReady*/huart->RxState=HAL_UART_STATE_READY;/*Pro

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论