关于使用STM32的HAL库通过串口收发大量数据时串口接受失效的解决办法
写在前面
HAL库的串口收发由于加锁操作,当数据量太大时会出现接受失效的情况。我的项目中使用的是HAL_UART_Transmit()和HAL_UART_Receive_IT(),另外由于我的板子是在不断接收实时数据偶尔丢一点数据几乎没影响,本着尽量进行小改动和不修改库函数本身的原则,我的解决方法如下。其实如果条件允许的话,我比较建议可以使用LL库,可以仅串口部分使用LL库,HAL库和LL库是兼容的(注意:同一外设只能使用一种库)。
代码实现
HAL_StatusTypeDef USART_SendData(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
HAL_StatusTypeDefr state = HAL_OK;
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_RXNEIE_RXFNEIE);
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_RE);
state = HAL_UART_Transmit(huart,pData,Size,Timeout);
HAL_UART_Receive_IT(&huart3,uart3_rxdata,1);
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_RE);
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_RXNEIE_RXFNEIE);
return state;
}
我们每次阻塞发送的时候直接使用上面的函数即可,程序其他地方不用修改,USART_SendData()函数的返回值与输入参数都与HAL_UART_Transmit()函数一样。 注意:代码里面HAL_UART_Receive_IT()函数的输入参数需要根据自己的程序修改
代码思路
USART_SendData()函数的思路比较简单,就是在发送前关闭接收中断,发送完成后再次打开串口接收中断,避免在串口发送过程中进入接收中断。 之所以这样做是因为使用HAL_UART_Receive_IT()函数会对串口进行加锁操作,若此时串口正在发送则加锁失败这将导致接收失效。而由于每次进入接收中断处理函数后接收中断会被关闭,需要在中断处理函数中调用HAL_UART_Receive_IT()函数重新开启中断。 因此,若是在串口发送过程中进入接收中断,则HAL_UART_Receive_IT()会被调用,该函数将对串口进行加锁,而此时串口正在发生,因此加锁操作会失败,从而导致接收失效。 所以我们在发送数据时关闭接收中断就不会在发送数据时调用HAL_UART_Receive_IT()函数,也就不会出现加锁失败的情况了。
|