STM32基于DMA的高效串口通信实现
本文章实现STM32F103C8T6开发板基于HAL库使用DMA方式的串口通信。
文章目录
一、认识DMA
(1)DMA定义
在STM32微控制器中,DMA(Direct MemoryAccess)是指直接内存访问技术。
它是一种数据传输技术,通过将数据直接从外设(如UART、SPI、I2C等)传
输到内存,或者从内存传输到外设,而不需要CPU的干预,从而提高了数据传
输的效率。
DMA控制器有自己的寄存器和逻辑,可以独立地读取和写入数据,而不需要
CPU的干预。它可以通过配置寄存器来控制数据传输的源地址、目标地址、
数据大小、传输方向和触发条件等。
使用DMA的好处是可以减少CPU的负载,提高数据传输的效率。当需要大量数
据传输时,例如音频、图像或其他大型数据块时,采用DMA可以显著减少CPU的
开销,使CPU能够专注于其他任务。
在STM32中,DMA控制器通常与外设和存储器之间进行数据传输。它可以实现
多个外设之间的数据传输,或者在外设和存储器之间进行数据传输。通过配置DMA
通道和传输参数,可以实现高效的数据传输,从而提高系统的性能。
(2)STM32F10xxxDMA资源
DMA1控制器:请求映象
上图可以看到我们本次使用的串口1对应DMA通道和优先级。
DMA2控制器:
二、CubeMX配置工程
配置RCC:
串口配置:
DMA配置:
时钟配置:
工程设置:
完成以上配置后生成工程代码。
三、代码编写
1.DMA串口发送接收函数
HAL库在使用DMA经行串口发送时,我们可以调用下面这个函数
HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
上述函数参数定义为:哪个串口发送,需要发送的变量,发送变量的字节长度。
DMA串口接收数据,可以调用下面这个函数(参数同发送):
HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
2.DMA串口空闲中断函数
我们在使用DMA方式进行串口通信时,不可能每次都等到接收到定长的数据后才进行我们的数据处理,所以,我们需要用到DMA串口空闲中断,当串口的RX端没有数据进入时,发生中断。就可以实现不定长数据的接收与发送了。下面是这个函数:
HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
值得注意的是,其中前两个参数的定义依旧是哪个串口和接收到的数据,最后的Size参数不再是接收到数据的长度,而是接收的一帧数据最大限度长度。
使用上述函数,就可以在接收到一帧数据后,进入中断。
3.DMA串口空闲中断回调函数
注意,HAL_UARTEx_ReceiveToIdle_DMA ,的回调函数不再是RxCpltcallback 函数,而是下面这个:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);
参数定义是:发生中断的对应串口,和接收数据的长度。
4.主函数编写
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//开启空闲中断
uint8_t flag = 0;
uint8_t message[] = "hello windows!\n";
while (1)
{
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,receivedata,sizeof(receivedata));
if(flag==1)
{
HAL_UART_Transmit_DMA(&huart1,(uint8_t *)message,sizeof(message));
HAL_Delay(500);
}
}
}
5.中断服务函数编写
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart == &huart1)
{
//将接受到的数据原封不动的转发
HAL_UART_Transmit_DMA(&huart1,receivedata,Size);
//数据处理
if(strcmp(receivedata,"start")==0)
flag = 1;
else if(strcmp(receivedata,"stop")==0)
flag = 0;
else
flag = 0;
//重新打开空闲中断
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,receivedata,sizeof(receivedata));
}
}
通过上面代码就可以实现以下功能:STM32系统给上位机(win10)连续发送“hello windows!”;当上位机给stm32发送字符“stop”后,stm32暂停发送“hello windows!”;发送一个字符“start”后,stm32继续发送。
四、板级验证
五、总结
本次实验,从认识DMA到使用DMA,虽然只是使用了DMA很简单的功能,但可以认识DMA功能之强大,当程序功能揉杂的时候,能够使用DMA功能释放CPU的压力。
本次实验,在使用DMA空闲中断时,当接收数据的长度等于中断发生最大长度的一半时,也会触发中断,这是因为每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。我们需要将对应的中断功能关闭,使用我们自己想要的功能。
HAL库中关闭该功能可以使用:__HAL_UART_DISABLE_IT() 这个函数。