为什么要使用串口不定长接收
正常的接收函数
HAL_UART_Receive(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size,uint32_t Timeout)
huart:句柄
pData:盛放接收数据的变量
Size:接收数据的大小
中断接收函数
HAL_UART_Receive_IT(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)
huart:句柄
pData:盛放接收数据的变量
Size:接收数据的大小
这两个接收函数有一个共有特性,就是定长接收,Size参数就是接收数据的长度,当串口发送长度不固定的数据时,会出现吞字符的现象,会使指令信息不完整。所以,为了保证下位机接收到完整的指令,需要串口可以完整接收不定长度的数据,常用方法有两个,一是使用串口空闲中断实现,二是使用串口空闲中断+DMA实现。
什么是串口空闲中断
串口空闲中断是指当串口接收缓冲区中没有数据时,串口控制器产生的一种中断信号。在串口通信中,当接收到一个完整的数据帧后,通常会有一个停止位,表示数据的传输结束。当接收缓冲区中没有数据时,串口控制器会检测到停止位的连续空闲状态,并产生空闲中断信号。使用串口空闲中断可以消除轮训接收缓冲区的需要,提高系统的性能和效率。
注意:
(1)空闲中断的允许需要手动解除中断屏蔽
(2)空闲中断必须手动清零,不然中断会一直置位,系统会不断进入中断处理函数
方法一:通过串口空闲中断 实现串口不定长接收
思路:
每次接收一个字符触发中断,这样每次进接收中断就保存下当前接到的字符到一个数组里,然后下一个字符来的时候就继续保存到数组里的下一个元素中,以此类推每次中断保存一个字符,那当发完的时候就保存完了,同时触发空闲中断,在空闲中断中那个保存数组就是接收到的数据。然后就可以对这个数组进行判断发送等操作了。
步骤:
一定要注意相关函数添加在的位置!!!!
1、
2、
3、
4、
5、
6、
相关部分代码
1、main.c 内 设计全局变量
/* USER CODE BEGIN 0 */
uint8_t buf[128]={0};
uint8_t buf_recv[64];
/* USER CODE END 0 */
2、主函数
//串口空闲中断+串口接收中断
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //使能空闲中断
HAL_UART_Receive_IT(&huart1,buf,1);//每次接收一个,然后每次都进中断
3、stm32g0xx_it.c 内修改中断函数中的全局变量
/* USER CODE BEGIN 0 */
uint8_t len=0;
extern uint8_t buf_recv[64];
uint8_t buff[64];
/* USER CODE END 0 */
4、修改中断函数 记得添加头文件#include<string.h>
/* USER CODE BEGIN USART1_IRQn 0 */
//使用串口接收中断+空闲中断
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
{ // 1. 获得串口空闲中断标志
__HAL_UART_CLEAR_FLAG(&huart1,UART_CLEAR_IDLEF); // 2. 清除空闲中断标志
//3.这里写中断执行
HAL_UART_Transmit(&huart1,buf_recv,sizeof(buf_recv),1000);
len=0;
memset(buf_recv,0,sizeof(buf_recv));
}else
{
buf_recv[len]=USART1->RDR;
len++;
HAL_UART_Receive_IT(&huart1,buff,1);
}
/* USER CODE END USART1_IRQn 0 */
方法二:串口空闲中断+DMA
原理: 接收足够的长度,当串口空闲时进中断,直接计算当前接收数组实际接收值,然后停止接收即可。
步骤:
1、main.c
2、
3、中断函数改写
效果演示
相关代码
注意代码位置
1、main.c定义全局变量
/* USER CODE BEGIN 0 */
uint8_t buf_ctl[64];
/* USER CODE END 0 */
2、循环接收数据
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_UART_Receive_DMA(&huart1,buf_ctl,64); //接收DMA使能
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //开启串口空闲中断
}
3、中断函数 添加头文件#include<string.h>
添加全局变量
/* USER CODE BEGIN TD */
extern uint8_t buf_ctl[64];//拿到main.c的buf_ctl
uint8_t len;
/* USER CODE END TD */
修改中断函数
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
{ // 1. 获得串口空闲中断标志
__HAL_UART_CLEAR_FLAG(&huart1,UART_CLEAR_IDLEF); // 2. 清除空闲中断标志
HAL_UART_DMAStop(&huart1); // 3. 清除->空闲->停止DMA
len = 64 - hdma_usart1_rx.Instance->CNDTR;
// 4. 设定的传输长度-剩余传输数量(DMA_CNDTRx)=实际长度
buf_ctl[len]='\0';
HAL_UART_Transmit(&huart1,buf_ctl,sizeof(buf_ctl),500);
memset(buf_ctl,0,sizeof(buf_ctl));
HAL_UART_Receive_DMA(&huart1, buf_ctl, 64);
// 6. 重新开启DMA
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
标签:教程,HAL,UART,STM32,中断,串口,buf,空闲
From: https://blog.csdn.net/a1547998353/article/details/139193387