利用的是STM32F412RETx的芯片,板子是电子工程师做的
利用STM32CubeMX V5.2.1、Keil uVision5做开拓,利用HAL库

利用过程中多次涌现串口吸收的问题,末了都办理了,这里记录一下
串口的HAL有3类API
// 同步堵塞收发HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size, uint32_t Timeout);HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size, uint32_t Timeout);// 异步中断传输HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size);HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size);// 异步DMA传输(Direct Memory Access,DMA),不经由CPU,外设直接读写内存HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size);HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size);
我利用的是异步中断HAL_UART_Receive_IT的进行串口数据吸收,这个须要用到
吸收完成中断回调void HAL_UART_RxCpltCallback(UART_HandleTypeDef huart);
在中断回调中只进行数据的解析,不做过多其他处理,避免中断韶光过长,中断中也不要利用延时函数,只管即便不在中断中进行IO输出操作。
第一种串口吸收问题:征象为开机后串口可以吸收数据,一下子后就一贯没有数据了。
查看缺点为:HAL_UART_Receive_IT返回HAL_BUSY
先说一下我的利用方法:利用HAL_UART_Receive_IT吸收数据,须要在每次吸收完成后,再次调用HAL_UART_Receive_IT函数,一样平常是在HAL_UART_RxCpltCallback函数的末端再次HAL_UART_Receive_IT。
HAL_UART_Receive_IT有个状态返回值,可以自己看一下这个函数的实现,代码也就几十行
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size){ / Check that a Rx process is not already ongoing / if (huart->RxState == HAL_UART_STATE_READY) { if ((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } / Process Locked / __HAL_LOCK(huart); huart->pRxBuffPtr = pData; huart->RxXferSize = Size; huart->RxXferCount = Size; huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX; / Process Unlocked / __HAL_UNLOCK(huart); / Enable the UART Parity Error Interrupt / __HAL_UART_ENABLE_IT(huart, UART_IT_PE); / Enable the UART Error Interrupt: (Frame error, noise error, overrun error) / __HAL_UART_ENABLE_IT(huart, UART_IT_ERR); / Enable the UART Data Register not empty Interrupt / __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); return HAL_OK; } else { return HAL_BUSY; }}
一样平常这个函数失落败都是返回HAL_BUSY居多,这里有两种情形会返回HAL_BUSY
1. huart->RxState != HAL_UART_STATE_READY,串口没准备好或者串口正在吸收数据中,如果时正在吸收数据,意味着其他地方已经调用过HAL_UART_Receive_IT,直接忽略等待吸收完造诣好,而我知道只有在HAL_UART_RxCpltCallback有再次调用,以是其他地方调用不存在,而且失落败时查看过状态huart->RxState 是即是 HAL_UART_STATE_READY
2. __HAL_LOCK(huart);加锁失落败,锁被占用。
看一下__HAL_LOCK(__HANDLE__)的定义
#define __HAL_LOCK(__HANDLE__) \ do{ \ if((__HANDLE__)->Lock == HAL_LOCKED) \ { \ return HAL_BUSY; \ } \ else \ { \ (__HANDLE__)->Lock = HAL_LOCKED; \ } \ }while (0U)
这里就判断了一次,如果锁被占用,直接返回,从我这边测试可以看到,一样平常都是由于锁被暂用然后返回了HAL_BUSY,那么就要看一下哪里占用了锁。
吸收数据利用的是异步中断的函数HAL_UART_Receive_IT(),然而发送数据我利用的是同步堵塞的函数HAL_UART_Transmit(),可以自己看一下HAL_UART_Transmit()的实现,这里不列代码了,HAL_UART_Transmit()函数内从开始发送开始加锁,等待全部数据发送完成后才解锁,以是占用锁的韶光是比较长的。而数据发送也比较多,以是基本剖断是发送造成的加锁。
有两种方法可以办理发送造成的加锁问题:
1. 利用异步函数发送,这样占用锁韶光就短,不过也有概率锁占用,可以选择重试几次可能就可以了
2. huart->RxState=HAL_UART_STATE_READY,且担保不存在多处代码同时发送,那么可以选择暴力解锁,我利用这种方案
下面确认一下被加锁的代码
加锁一样平常是由于要操作一下公用的数据。
下面我们剖析一下串口UART_HandleTypeDef构造体
typedef struct __UART_HandleTypeDef{ USART_TypeDef Instance; /!< UART registers base address / UART_InitTypeDef Init; /!< UART communication parameters / uint8_t pTxBuffPtr; /!< Pointer to UART Tx transfer Buffer / uint16_t TxXferSize; /!< UART Tx Transfer size / __IO uint16_t TxXferCount; /!< UART Tx Transfer Counter / uint8_t pRxBuffPtr; /!< Pointer to UART Rx transfer Buffer / uint16_t RxXferSize; /!< UART Rx Transfer size / __IO uint16_t RxXferCount; /!< UART Rx Transfer Counter / DMA_HandleTypeDef hdmatx; /!< UART Tx DMA Handle parameters / DMA_HandleTypeDef hdmarx; /!< UART Rx DMA Handle parameters / HAL_LockTypeDef Lock; /!< Locking object / __IO HAL_UART_StateTypeDef gState; /!< UART state information related to global Handle management and also related to Tx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef / __IO HAL_UART_StateTypeDef RxState; /!< UART state information related to Rx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef / __IO uint32_t ErrorCode; /!< UART Error code /} UART_HandleTypeDef;
结合HAL_UART_Receive_IT()、HAL_UART_Transmit()两个函数,创造实在收发数据时利用的成员变量基本是分开的,
发送利用pTxBuffPtr、TxXferSize、TxXferCount、hdmatx、gState
吸收利用pRxBuffPtr、RxXferSize、RxXferCount、hdmarx、RxState
共用部分:ErrorCode
gState也可能是公用的,不过暂时在函数HAL_UART_Receive_IT中没创造有利用gState
检讨自己的代码,创造确实是HAL_UART_Transmit()造成的锁,既然基本上紧张成员没有共用,那就暴力解锁
在判断吸收状态为HAL_UART_STATE_READY时,且被加锁,直接暴力解锁if(HAL_UART_STATE_READY == huart->RxState && HAL_LOCKED == huart->Lock){ __HAL_UNLOCK(huart); // 暴力解锁}
至此由于加锁问题而造成的串口溘然吸收不到数据的问题暂时办理了,很暴力的办法
第一种串口吸收问题:同样是上电后串口可以吸收数据,吸收一段韶光后没数据了,
而且HAL_UART_Receive_IT()函数返回的是HAL_OK
检讨了HAL_UART_GetError(),获取到缺点HAL_UART_ERROR_ORE,该当是串口溢出的意思。
只是为什么溢出后就直接停滞吸收了?就算是丢包也不要给我直接停滞事情了呀!
!
!
删库后跑路了???
办理方法如下
既然知道报错,那就考虑清楚缺点标志,特地也看了一下函数HAL_UART_IRQHandler(UART_HandleTypeDef huart);内,的确是有缺点标志的时候,不会调用吸收完成回调
看了多篇文章,试了几种方法后终于找到一个打消缺点标志有效的
利用__HAL_UART_CLEAR_OREFLAG(__HANDLE__)可以清空缺点标志
利用__HAL_UART_CLEAR_FLAG(__HANDLE__, __FLAG__)是没用的
终极完全版的修正如下:
HAL_StatusTypeDef K_UART_Receive_IT(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size){ HAL_StatusTypeDef status = HAL_OK; for(int32_t i = 1; i < 1000; ++i) {#if 1 // 打消缺点 uint32_t isrflags = READ_REG(huart->Instance->SR); if((__HAL_UART_GET_FLAG(huart, UART_FLAG_PE))!=RESET) { __HAL_UART_CLEAR_PEFLAG(huart); } if((__HAL_UART_GET_FLAG(huart, UART_FLAG_FE))!=RESET) { __HAL_UART_CLEAR_FEFLAG(huart); } if((__HAL_UART_GET_FLAG(huart, UART_FLAG_NE))!=RESET) { __HAL_UART_CLEAR_NEFLAG(huart); } if((__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE))!=RESET) { //READ_REG(huart->Instance->CR1);//ORE清标志,第二步读CR //__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_ORE); __HAL_UART_CLEAR_OREFLAG(huart); } if(HAL_UART_ERROR_NONE != huart->ErrorCode) { huart->ErrorCode = HAL_UART_ERROR_NONE; }#endif // 要求吸收 status = HAL_UART_Receive_IT(huart, pData, Size); if(HAL_OK == status) { // 成功 return status; } else if(HAL_BUSY == status) { //printf(\公众HAL_UART_Receive_IT failed. status:%d, RxState:0X%x, Lock:%d\r\n\公众, status, huart->RxState, huart->Lock); if(HAL_UART_STATE_READY == huart->RxState && HAL_LOCKED == huart->Lock && i % 500 == 0) { // 吸收是已经ready的,只是修正数据的锁被lock了,该当是堵塞发送那边一贯在lock中, 轻微重试多次后(即等待一下解锁)就直接暴力解锁 __HAL_UNLOCK(huart); continue; } } else if(HAL_ERROR == status) { // 直接返回缺点 //printf(\"大众HAL_UART_Receive_IT HAL_ERROR\r\n\"大众); return status; } else if(HAL_TIMEOUT == status) { // HAL_UART_Receive_IT 不存在timeout返回 //printf(\"大众HAL_UART_Receive_IT HAL_TIMEOUT\r\n\"大众); } } if(HAL_OK != status) { //printf(\"大众HAL_UART_Receive_IT Err status:%d\r\n\公众, status); } // 重试了N次 return status;}
发送也轻微处理一下
HAL_StatusTypeDef K_UART_Transmit(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size, uint32_t Timeout){ HAL_StatusTypeDef status = HAL_OK; for(int32_t i = 1; i < 100000; ++i) { status = HAL_UART_Transmit(huart, pData, Size, Timeout); if(HAL_OK == status) { // 成功 return status; } else if(HAL_BUSY == status) { //printf(\"大众HAL_UART_Transmit failed. status:%d, gState:0X%x, Lock:%d\r\n\"大众, status, huart->gState, huart->Lock); if(HAL_UART_STATE_READY == huart->gState && HAL_LOCKED == huart->Lock && i % 50 == 0) { // 发送状态是已经ready的,只是修正数据的锁被lock了,该当是其他发送或者吸收锁了, 重试几次后还是一样则暴力解锁 __HAL_UNLOCK(huart); continue; } } else if(HAL_ERROR == status) { // 直接返回缺点 return status; } else if(HAL_TIMEOUT == status) { // 超时则增加韶光重试 Timeout += 200; continue; } } // 重试了N次 return status;}
这样处理后,吸收是可以了,虽然有丢包,至少能一贯吸收,之后创造之以是那么不稳定,由于STM32F412RETx须要在输入电源增加一个电容进行滤波,增减滤波后就正常了,至少没创造丢包,不加打消标志也没问题
参考了很多篇文章,仅列举有用的:
https://blog.csdn.net/mickey35/article/details/78529637
http://bbs.21ic.com/icview-2514912-1-1.html?ordertype=1










