上篇实现了串口点灯,但是用的是固定长度数据,那么如何实现不定长的接收呢?STM32有用串口接收中断+空闲中断.也有用DMA+空闲中断的,今天我先用串口接收中断+空闲中断原理就是每接收到一个字节产生一次接收中断,将接收的数据放进缓存区,当一包数据接收完会产生空闲中断,这是我们判断接收完成续上篇,这次不用点点点了,因为跟上篇配置一样,简单写个结构体
#define RX_BUF_MAX_LEN 512 // 最大接收缓存字节数
typedef struct
{
uint8_t rx_buff[RX_BUF_MAX_LEN];//缓存区
uint8_t len; //接收长度
uint8_t flag; //用于判断是否接收完 1为接收完
}USRAT_RX;
再写个初始化(清空)结构体
void Clear_Usart(USRAT_RX *usart_rx)//初始化(清空)串口结构体
{
memset((uint8_t *)usart_rx, 0, sizeof(USRAT_RX));//全写0
}
把之前的回调函数注释了,感觉HAL库的回调函数并不好用,直接在中断里写吧
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_RXNE) != RESET)//产生接收中断
{
HAL_UART_IRQHandler(&huart2); // 该函数会清空中断标志,取消中断使能,并间接调用回调函数,清除接收标志
// 收到数据,将其放入缓冲区
usart1_rx.rx_buff[usart1_rx.len++] = recv_buf;
if(usart1_rx.len>RX_BUF_MAX_LEN){//防止刷爆串口缓存
usart1_rx.flag = 1; // 标记接收完成
}
}
if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != RESET)//产生空闲中断(说明接收完)
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2); //清楚空闲中断标志(否则会一直不断进入中断)
usart1_rx.flag = 1; // 标记接收完成
if(usart1_rx.len==0){//防止误入
usart1_rx.flag = 0;
}
}
HAL_UART_Receive_IT(&huart2,&recv_buf,1); // 重新使能接收中断
/* USER CODE END USART2_IRQn 0 */
}
注释已经很清楚了,我就不解释了,我们还要初始化串口结构体,打开接收中断和空闲中断
Clear_Usart(&usart1_rx);//初始化串口结构体
HAL_UART_Receive_IT(&huart2,&recv_buf,1);//使能串口接收中断
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE); // 使能空闲中断
在while(1)里添加判断函数
if(usart1_rx.flag){//判断接收完成
printf("%s\r\n",usart1_rx.rx_buff);//打印出数据
if(strstr((const char *)usart1_rx.rx_buff, "LED_ON") != NULL){//如果匹配到数据LED_ON
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET);
printf("Turn on the LED");
}
else if(strstr((const char *)usart1_rx.rx_buff, "LED_OFF") != NULL){//如果匹配到数据LED_OFF
HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET);
printf("Turn off the LED");
}
else {//不匹配打印error
printf("error\r\n");
}
Clear_Usart(&usart1_rx);//清空串口结构体
}
看效果