1.首先打开cube选型,选择STM32F103ZETX。
2.在Pinout窗口左边栏配置串口,选中Asynchronous模式。右侧窗口会自动显示串口占用的相关引脚为绿色。
3.在clock configuration窗口内配置各部分时钟
4.选择Configuration窗口配置USART1的相关选项,并对DMA进行配置,因为后面会用到DMA,我们这里先暂时配置DMA。
配置完成后选择Project->setting进行如下设置
勾选上为每一个外设分别建立.c/.h文件。
选择工程路径,并选择编译器
最后,生成代码。Project->G Code
1.首先在生成的代码函数中先实现对于串口中断的配置,这部分包括串口中断的使能,空闲中断的使能等。
在void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)函数中添加空闲中断的使能;
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); /*设置串口中断优先级*/
HAL_NVIC_EnableIRQ(USART1_IRQn); /*使能串口中断*/
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); /**使能串口空闲中断*/
2.在串口中断函数中添加如下代码
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)) /*判断是否产生了空闲中断*/
{
UsartReceive_IDLE(&huart1); /*调用UsartReceive_IDLE(&huart1);(自定义)*/
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
3.在usart.c函数中添加如下自定义函数
void UsartReceive_IDLE(UART_HandleTypeDef* uartHandle)
{
uint32_t temp;
if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET)) /*判断串口中断标志位*/
{
HAL_UART_DMAStop(&huart1); /*停止DMA读取*/
temp=huart1.Instance->SR;
temp=huart1.Instance->DR;
temp = hdma_usart1_rx.Instance->CNDTR;
rx_len = BUFFER_SIZE- temp; /*读取到的数据长度*/
printf("rx_len interrupt =%d\r\n",rx_len);
recv_end_flag = 1;
__HAL_UART_CLEAR_IDLEFLAG(&huart1); /*手动清除空闲中断的标志位*/
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE); /*重新启动DMA串口接收*/
}
}
4.在main.c函数中修改如下代码
/*预定义一些测试时会用到的变量*/
#define BUFFER_SIZE 128 /*DMA串口接收可以接收的最大字节数*/
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
uint8_t rx_len=0; /**接收到的字符数据长度*/
uint8_t recv_end_flag=0; /*接收完成标志位*/
uint8_t rx_buffer[128]; /*接收缓冲区*/
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE); /**在初始化程序之后,循环开始之前要先打开DMA接收*/
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(recv_end_flag ==1) /*接收不定长一帧数据完成*/
{
printf("rx_len=%d\r\n",rx_len); /*打印接收到的数据长度*/
printf("%s\r\n",rx_buffer); /*打印接收到的数据内容*/
rx_len=0;
recv_end_flag=0;
}
}
在此次DMA加串口空闲中断的串口接收程序中,可以实现对于不定长数据的正确读取,从而避免了自己判断包头包尾的繁琐工程。同样,如果不适用DMA的话,也可以利用串口接收中断加串口空闲中断的方式实现对不定长数据的读取,方法步骤和次工程类似,在这里不再赘述。
注:使用空闲中断同样也要注意一些问题,在串口收发数据频率较高时,串口空闲中断不被打断的要求就变得很高,此时如果空闲中断被打断,可能会导致误触发空闲中断接收完一帧数据的错误信息,导致一帧数据没有读取完全。