本文将简单分析,阻塞方式接受发送数据,中断接收发送数据,以及串口空闲中断+DMA方式接收发送数据。
阻塞方式:
串口数据发送的阻塞方式一般是通过等待发送缓冲区为空的方式实现。当向串口发送数据时,用户程序将数据写入到串口发送的缓冲区,并通过查询方式检测缓冲区的空闲状态。如果缓冲区为空,则代表数据已经全部发送完毕,程序就可以退出发送函数。
串口数据接收的阻塞方式一般是通过等待接收缓冲区非空的方式实现。当串口接收到数据时,数据会被存储到串口接收缓冲区中。用户程序可以通过查询方式检测缓冲区状态,当缓冲区中有数据时,程序会读取数据并进行处理。如果缓冲区中没有数据,则程序会一直等待。
串口阻塞方式的数据接收和发送虽然简单易用,但由于是采用阻塞方式进行数据接收和发送,会导致程序在等待期间无法执行其他任务,从而降低了系统的效率。其次,如果传输的数据很多并且速率很快,可能会导致接收缓冲区溢出或者发送缓冲区堆积,引起数据丢失或者数据冲突等问题,所以不做具体简绍。
中断方式:
CUBEMX配置如下:
先配置引脚PA9和PA10,在按需设置波特率,开启一下NVIC,即可。
代码部分:
主函数一定记得提前开启一次接收中断。(一定加上取地址符号)
HAL_UART_Receive_IT(&huart1, &rx_date, 1);//中断方式接收,一次接收一个字符
中断接收回调 函数如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
rxBuf[rxPoint++]=rx_date;
HAL_UART_Receive_IT(&huart1, rx_date, 1); //每一次接收完,下一次都要开启
}
}
发送采用阻塞方式发送:
HAL_UART_Transmit(&huart1, txBuf, sizeof(txBuf), 100);
理论上到这里就可以了,但实际使用过程中,我发现当数据量较多时,配合其他模块一起使用时,容易出现接收不完全的情况。改进方法如下
处理函数
void uartProc(void)
{
int len=rxPoint; //先获取当前字符长度
HAL_Delay(2); //延时两个毫秒,如果没有接收完成,中断回调函数会改变rxPoint的值,导致len!=rxPoint
if(len==rxPoint) //说明接收完成
{
//添加处理代码
}
}
串口空闲中断+DMA
串口空闲中断是指当串口没有传输数据的时候就会触发相应的空闲中断信号,这个信号可以被外设作为数据传输触发源。而DMA(Data Memory Access)技术是指不需要CPU参与的直接从外设的硬件接口直接读写内存,因此在传输大量数据时的速度非常快,而且可以提高CPU的利用率。
CUBEMX配置如下:
与中断方式下没有太大区别,只是增加了DMA。
代码如下:
在stm32g4xx_it.c的void USART1_IRQHandler(void)函数中添加处理代码
初始化代码:
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1,rx_Buf,64);
中断函数添加处理代码:路径如图
代码如下:
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) //判断是不是串口空闲中断
{
uint8_t test;
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除标志位
test= huart1.Instance->ISR;
test= huart1.Instance->RDR;
HAL_UART_AbortReceive(&huart1); //关闭串口
temp = hdma_usart1_rx.Instance->CNDTR; //CNDTR寄存器存储剩下空间大小
rx_len = 64-temp; //一共64个,减掉剩余的个数,得到接收到的个数
rx_Flag = 1; //说明发生了空闲中断
}
进行数据处理:
if(rx_Flag == 1)
{
HAL_UART_Transmit_DMA(&huart1,rx_Buffer,rx_len);
//这里自己添加其他处理代码
rx_len=0;
rx_Flag=0;
HAL_UART_Receive_DMA(&huart1,rx_Buffer,64);
}
注意:也可以把中断空闲标志改为中断回调函数,在中断回调函数中处理数据。
注意:也下两行代码需要和CUBEMX生成代码紧挨在一起。
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1,rx_Buf,64);
如图收拾:
串口中断的处理方式是通过中断触发进行数据的传输,这种方式没办法快速缓存大量的数据,导致数据的接收和传输速度有很大的限制,但是通过串口空闲中断+DMA可以解决这个问题。
串口空闲中断+DMA的好处有以下几个方面:
-
传输速度更快:通过DMA技术,数据的传输速度可以更快,可以提高串口通信的传输速率。
-
可以大缓存量传输:在传输大量数据时,通过DMA技术可以进行批量传输,从而可以提高传输效率。
-
降低系统资源占用率:通过使用DMA,CPU无需参与数据传输,大大降低了CPU的占用率,更好的利用了CPU的资源。
注意:在中断函数中,不要使用printf,sprintf,浮点数运算。printf,sprintf效率低,不适合放到中断里面,浮点数运算将涉及到额外的寄存器操作,三者均属于不可重入函数,使用不安全。