STM32CubeMX:串口DMA

DMA:直接储存区访问,DMA传输将数据从一个地址空间复制到另一个空间。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM何IO设备开辟一条直接传输数据的通道,从而可以提高CPU的效率。一般用到DMA,主要作用为CPU减负。
我们用STM32CubeMX来配置一下串口的DMA实现收发。
选择芯片:
在这里插入图片描述
根据自己的电路设计情况配置时钟,我用的外部晶振25M
在这里插入图片描述

然后配置串口及DMA这里我们配置两个串口串口1和串口2,让这两个串口实现互通,两个串口的配置一样,这里展示串口1的
在这里插入图片描述
在这里插入图片描述
其他配置和我们平时用串口配置一样,就是在DMA这里开启收发就可以,点击Add添加,收发都添加进去,下面mode设置可以选择Normal表单次传输,传输一次后终止传输,Circular表示循环传输,传输完成后又重新开始继续传输,不断循环永不停止。此处选择单次传输。
Increment Address表示地址指针递增。串口数据发送寄存器只能存储8bit,每次发送一个字节,所以数据长度选择Byte。
在这里插入图片描述

最后这里中断要开启,DMA的是默认开启的,如果不开启串口中断,则程序只能发送一次数据,程序不能判断DMA传输是否完成,USART一直处于busy状态。这样我们就配置好了,串口2也如此配置,
在这里插入图片描述
然后设置工程名称及存放地址和使用的编译器,点击生成。生成后点击打开工程,可以先编译一下正常的是没有错误的

发送比较简单 用这个函数直接就可发送,

	HAL_UART_Transmit_DMA();
	uint8_t TXbuff[] = "\r\n**** UART-Hyperterminal communication based on DMA ***\r\n ";
	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)TXbuff, sizeof(TXbuff)-1);

在这里插入图片描述
我们定义了一个数组,然后在while里面循环每隔一秒发一下。

接收就比较麻烦,尤其是不定长的接受,这里我们用到串口的空闲中断,
首先我们要在库函数添加一点代码

/* UART in mode Idle -------------------------------------------------*/
if(((isrflags & USART_SR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
HAL_UART_IdleCpltCallback(huart);
return;
}

将上述代码添加到stm32f4xx_hal_uart.c中,该文件在工程的Drivers\STM32F4xx_HAL_Driver中添加位置:添加在
/* UART in mode Transmitter ------------------------------------------------*/的前面,可ctrl+F弹出查找,输入点击查找。
在这里插入图片描述

__weak void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart);
}

将上述代码添加到
__weak void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart)函数的前面。
在这里插入图片描述

再接着
在stm32f4xx_hal_uart.h中添加
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart);
在这里插入图片描述

最后一步在在usart.c添加回调函数
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{

}
然后这里我们在回调函数里面直接做一个串口1和串口2的数据中转

//定义一些变量和数据缓冲区
uint16_t RecCount1=0  ;      //接收数据个数
uint16_t RecCount2=0  ;      //接收数据个数

uint8_t UART_1_RxBuffer[1024];
uint8_t UART_2_RxBuffer[1024];

#define  LENGTH  1024     //接收缓存区大小,该值需要大于一帧数据的总字符数
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{

	if(huart->Instance == USART1)
	{

			HAL_UART_DMAStop(&huart1);

			//发生空闲中断时,已接收数据个数等于数据总量减去DMA数据流中待接收的数据个数
			RecCount1 = LENGTH - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);

			HAL_UART_Transmit_DMA(&huart2,(uint8_t*)UART_1_RxBuffer,RecCount1);

			HAL_UART_Receive_DMA(&huart1,(uint8_t*)UART_1_RxBuffer,LENGTH);   //启动DMA接收
		

		
	}
	if(huart->Instance == USART2)
	{
			HAL_UART_DMAStop(&huart2);

			//发生空闲中断时,已接收数据个数等于数据总量减去DMA数据流中待接收的数据个数
			RecCount2 = LENGTH - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);

			HAL_UART_Transmit_DMA(&huart1,(uint8_t*)UART_2_RxBuffer,RecCount2);

			HAL_UART_Receive_DMA(&huart2,(uint8_t*)UART_1_RxBuffer,LENGTH);   //启动DMA接收



	}

}

然后在main函数的里启动DMA接收

	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);    //使能IDLE中断
	HAL_UART_Receive_DMA(&huart1,(uint8_t*)UART_1_RxBuffer,LENGTH);    //启动DMA接收
	__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);    //使能IDLE中断
	HAL_UART_Receive_DMA(&huart2,(uint8_t*)UART_2_RxBuffer,LENGTH);    //启动DMA接收

在这里插入图片描述
编译程序然后下载通过串口发数据,我们会看到串口1发的数据串口2会收到,同时串口2发的数据串口1会收到。
在这里插入图片描述
当然这个方法有个弊端,就是我们直接修改的是库函数 ,那么再次用STM32CubeMX生成代码时stm32f4xx_hal_uart.h和stm32f4xx_hal_uart.c中修改的内容就没有了,需要重新修改,其实库函数的文件在你每次改动STM32CubeMX后生成代码时是不会变的,所以先把改好的这两个文件复制一下,然后在生成后直接粘贴过来替代就行。

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值