stm32LL库串口空闲中断+DMA接收

本文详细介绍了使用STM32F407VGT6的LL库配置串口,启用空闲中断,并利用DMA实现数据接收的过程。涉及DMA模式设置、中断回调函数、DMA初始化和数据迁移等内容,适合深入理解STM32串口和DMA配合的开发者参考。
摘要由CSDN通过智能技术生成

stm32LL库串口空闲中断+DMA接收

俺用的STM32F407VGT6,cubemx生成的代码。

cubemx的串口配置串口配置
这里就按默认参数配就行,主要是要打开后面的DMA
在这里插入图片描述
在这里点添加就完事了,如果只用串口接收,那只开RX就行,我把TX也开了是为了方便以后拓展功能。
在这里插入图片描述
然后把串口的全局中断开了,好像到这里就完事了,这个是俺很久以前配的,可能有遗漏,不管那么多了。

配完了之后就是生成代码了,这里选用了LL库,之前用HAL库,拿DAC生成个正弦波都有一段会抽一下,换了LL库之后就没问题了。
在这里插入图片描述
然后打开工程,首先来到usart.c,可以看到,cubemx还是很贴心的帮我们生成好了代码,但是就是没帮我们初始化,所谓万事俱备只欠东风。

在这里插入图片描述
在这里把代码贴上来,需要注意的是这里的DMAmode得改成循环模式,不然数据接收到一次之后,你后面的数据再怎么变它都不会刷新。。。

  LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_2, LL_DMA_CHANNEL_4);

  LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_STREAM_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

  LL_DMA_SetStreamPriorityLevel(DMA2, LL_DMA_STREAM_2, LL_DMA_PRIORITY_HIGH);

  LL_DMA_SetMode(DMA2, LL_DMA_STREAM_2, LL_DMA_MODE_CIRCULAR);

  LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_STREAM_2, LL_DMA_PERIPH_NOINCREMENT);

  LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_STREAM_2, LL_DMA_MEMORY_INCREMENT);

  LL_DMA_SetPeriphSize(DMA2, LL_DMA_STREAM_2, LL_DMA_PDATAALIGN_BYTE);

  LL_DMA_SetMemorySize(DMA2, LL_DMA_STREAM_2, LL_DMA_MDATAALIGN_BYTE);

  LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_2);

对了,顺便附带一下LL库实现printf的操作,弄个这个函数就完事了

在这里插入图片描述

int fputc(int ch, FILE *f)

{

	LL_USART_TransmitData8(USART1,ch);
	while(!LL_USART_IsActiveFlag_TC(USART1))
	{
	}

	return ch;

}

咳咳,言归正传,下面来到stm32f4xx_it.c,加入这个函数,也就是空闲中断的回调函数。

在这里插入图片描述

void USART_RxIdleCallback(void)
{

		uint8_t i;

		if(LL_USART_IsActiveFlag_IDLE(USART1))
			
		{
			
			//先清标志位
			
			LL_USART_ClearFlag_IDLE(USART1); 					
						
			if(UartRxDmaBuf[2] == 0xEE)
				
			{
				
				NVIC_SystemReset();
				
			}
			
			//先停止UART流DMA,暂停接收
			
			LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_2); 
			
			
			/* 3.搬移数据进行其他处理 */
			
			for(i=0; i<8; i++)
			{
				
				UartRxBuf[i] = UartRxDmaBuf[i];

			}
									
			UartRxflag = 1; //标志已经成功接收到一包等待处理
			
			LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, 8);
			
			/* 4.开启新的一次DMA接收 */
			
			LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_2);
									
		}
		
}

中间有个串口发送特定数据reset单片机的操作,不需要的可以去掉。

在这里插入图片描述
然后就是改写串口中断处理函数啦,把之前写的函数往里面一丢,然后再清一下标志位,就完事了。

    USART_RxIdleCallback();
	
	LL_USART_ClearFlag_RXNE(USART1);

额额,这里的DMA中断处理函数应该是没有用到,我反正是没开DMA的中断,但是不知道不写会不会有啥影响,也贴出来吧,个人感觉不写是不会有问题的,如果拿这篇文章做验证的话可以先不写。

在这里插入图片描述
OK,事已至此,木已成舟,一切准备工作皆已就绪,相当于导弹造好了,就差摁按钮了。

首先先搞个变量出来接收DMA的数据,对了,忘记说了,这玩意迁移数据好像没多大意义,两个好像是一起刷新的,算了不管了,反正F4内存大,也不差这点空间。
在这里插入图片描述

uint8_t UartRxBuf[8];							 //迁移的上位机数据
uint8_t UartRxDmaBuf[8];           //上位机传输的原始数据
uint8_t UartRxflag = 0;            //数据待处理标志

然后在主函数里加上这些初始化的东西就大功告成啦,记得放在串口初始化函数后面哈,因为串口初始化函数里面还有着一些DMA初始化的操作,所以要先完成。

在这里插入图片描述

	LL_DMA_SetPeriphAddress(DMA2, LL_DMA_STREAM_2, (uint32_t)(&USART1->DR));
    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_STREAM_2, (uint32_t)UartRxDmaBuf);
    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, 8);
	LL_USART_EnableIT_RXNE(USART1);   //使能串口1的中断
	LL_USART_EnableIT_IDLE(USART1);   //使能串口1的空闲中断
	
	LL_USART_EnableDMAReq_RX(USART1);
	LL_DMA_EnableStream(DMA2,LL_DMA_STREAM_2);

额额,稍微解释一下,第一个是设置外设的地址,因为之前在串口初始化里已经将DMA设置为外设到内存了,就是下面那段代码,在串口初始化里面可以找到,这里就不用再写一次了。

 LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_STREAM_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

第二个是设置内存地址,就不用多说了。

第三个是传输的长度,之前的数组设置成多大的这里参数就给多少。

这里讲一下,F4和F1两者LL库的区别,之前在网上查,F1的初始化函数,都不是设置STREAM,而是设置CHANNEL,我想是因为F4有DMA控制器的原因,在F4上多了个这么玩意(请忽视我原谅色的护眼背景)
在这里插入图片描述
而F1应该就是直接CHANNEL就接到仲裁器了吧,手头上没有F1的参考手册,姑且就发挥主观能动性臆测一下。

好了,行文至此,就此搁笔。

具体的还是需要花时间去参透,只有理解了其如何运行,才能得心应手地来配置。

这波,这波是在大气层。在这里插入图片描述

  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值