硬件
STM32L475
方案
使用通过修改HAL库,加入IDLE中断,实现不定长数据接收
参考资料
LAT0534_UART_IDLE中断使用_接收不定长串口数据_V0.3
关于资料下载,包括源码,参考的手册:https://www.dianyuan.com/eestar/article-3471.html
cubemx配置
实现过程
首先接入接受的数据缓冲区,并设置缓冲区的大小
//Store the revceived bytes number
uint32_t Rev_Size = 0;
//Receive buffer
uint8_t UART_RX_Buf[15];
然后修改HAL库的usart.c文件
加入extern uint32_t Rev_Size;变量声明
修改HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart)该函数
#else
//修改后的代码
CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE| USART_CR1_IDLEIE));
// CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));//修改前的代码
CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
#endif /* USART_CR1_FIFOEN */
修改HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)该函数,这里需要注意一下加入代码的位置。
__HAL_UNLOCK(huart);
/* Enable the UART IDLE Interrupt*/ //加入的代码
SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
/* Enable the UART Parity Error Interrupt */
SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);
修改void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)函数,光放文档里面的是 USART_SR_IDLE需要换成 USART_ISR_IDLE,NDTR换成CNDTR(具体原因看技术手册和源码)
#if defined(USART_CR1_FIFOEN)
if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
&& (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
|| ((cr3its & USART_CR3_RXFTIE) != 0U)))
#else
//加入的代码
if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))
{
//Record the received bytes number
Rev_Size = huart->RxXferSize - huart->hdmarx->Instance->CNDTR;
//clear the IDLE flag
__HAL_UART_CLEAR_IDLEFLAG(huart);
//Abord the received process
HAL_UART_AbortReceive_IT(huart);
return;
}
if (((isrflags & USART_ISR_RXNE) != 0U)
&& ((cr1its & USART_CR1_RXNEIE) != 0U))
#endif /* USART_CR1_FIFOEN */
{
if (huart->RxISR != NULL)
{
huart->RxISR(huart);
}
return;
}
}
在main.c里面进行函数修改
添加中断,该中断是在开启接收后,当接收到的数据没有到达最大的接收位的时候,但是总线上停止了数据传输,总线进入空闲状态,则产生中止中断。,并进入该函数进行数据处理。
```c
void HAL_UART_AbortReceiveCpltCallback (UART_HandleTypeDef *huart)
{
//Print received Bytes
printf("\n\r[IDLE]Received %d Bytes:",Rev_Size);
for(uint16_t i = 0; i < Rev_Size; i++)
{
printf(" 0x%02X", UART_RX_Buf[i]);
}
//Re-start receiving
HAL_UART_Receive_DMA(&huart1, UART_RX_Buf, 15);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_UART_AbortTransmitCpltCallback can be implemented in the user
file.
*/
}
该中断的解释
```c
/**
* @brief Abort ongoing Receive transfer (Interrupt mode).
* @param huart UART handle.
* @note This procedure could be used for aborting any ongoing Rx transfer started in Interrupt or DMA mode.
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_UART_Receive_DMA(&huart1, UART_RX_Buf, 15);接收中断的启动函数,通过启动接收,并在中止中断里面再次开启实现循环接收。其中15是最大的可接受的数据。
具体使用,需要注意的是,printf函数需要自己加入printf支持。
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("123456789\r\n");
HAL_UART_Receive_DMA(&huart1, UART_RX_Buf, 15);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
结果