STM32串口中断接收不定长报文并解析
功能实现背景介绍
本项目中,需要使用STM32的USART6串口与FPGA板(下位机)通信,需要发送和接收数据,有报文应答机制。
使用的报文规则如表格所示
板间报文的通信协议,校验使用的是和校验
- <font size="3">U8 TX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度
- {
- U8 i, ret = 0;
- for(i=0; i<len; i++)
- {
- ret += *(buf++);
- }
- ret = ~ret;
- return ret;
- }
- U8 RX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度
- {
- U8 i, ret = 0;
- for(i=0; i<len; i++)
- {
- ret += *(buf++);
- }
- ret = ret;
- return ret+1;
- }</font>
复制代码
发送和接收的报文要满足不定长
HAL库的中断接收函数
如果要直接使用HAL库的中断接收函数,也就是HAL_UART_Receive_IT()函数
- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5); //下位机FPGA
复制代码
在使用时,选择串口,选择接收的缓冲区,选择接收长度。
- /**
- * @brief Receives an amount of data in non blocking mode.
- * @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
- * the received data is handled as a set of u16. In this case, Size must indicate the number
- * of u16 available through pData.
- * @param huart Pointer to a UART_HandleTypeDef structure that contains
- * the configuration information for the specified UART module.
- * @param pData Pointer to data buffer (u8 or u16 data elements).
- * @param Size Amount of data elements (u8 or u16) to be received.
- * @retval HAL status
- */
- 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;
- }
- }
复制代码
这个函数本质上其实不是中断接收函数,只是配置函数,配置开启中断的信息,并且接收多少定长的数据结束本数据接收,串口的中断接收还是在中断中进行。
我们本次的长度虽然也是定长,但是有两种长度数据的接收,所以还是从设计接收不定长的数据为最终效果。
状态机的运用
对于不定长数据的接收,使用了状态机,分两次中断来接收数据
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- {
- if(huart->Instance == USART6) // 判断是由哪个串口触发的中断
- {
- if(StateMachine_USART6) //状态机为1,都接收完毕,准备校验
- {
- if(re_flag6 == 1)
- {
- UART6_RxCounter = 6;
- re_flag6 = 0;
- }
- else
- {
- len_counter6 = 2+5+UART6_RxBuffer[2]+(UART6_RxBuffer[3]<<8);
- if(UART6_RxBuffer[len_counter6 - 1] == 0x55 && UART6_RxBuffer[0] == 0xAA)
- {
- UART6_RxCounter = len_counter6;
- }
- else
- {
- memset(UART6_RxBuffer,0,0x400);
- UART6_RxCounter = 0;
- }
- }
-
- StateMachine_USART6 = 0; //状态机为0
- len_counter6 = 0;
- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);
- }
- else //状态机为0,只接受到了前五个字节,继续接收后面的字节
- {
- if(UART6_RxBuffer[0] == 0xAA)
- {
- StateMachine_USART6 = 1;
- UART6_RxCounter = 5;
- if(UART6_RxBuffer[2] == 0 && UART6_RxBuffer[3] == 0)
- {
- HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 1);
- re_flag6 = 1;
- }
- else
- HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 2 + UART6_RxBuffer[2] + (UART6_RxBuffer[3] << 8));
- }
- else
- {
- memset(UART6_RxBuffer,0,0x400);
- UART6_RxCounter = 0;
- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);
- }
-
- }
- }
- }
复制代码
核心思想就是先接收报文的头,根据头来判断后面的长度,把应答报文和音量数据报文区分开,不合格的报文直接舍去同时开启新的接收。
文章出处:Outsider Hub
|