STM32 UART接收与DMA 的学习笔记

实验介绍:

        在使用UART接收数据时,通常中断的频率时比较快的,八个字节的数据就会有八次中断来接受数据,会影响主程序。这里就引用到了DMA的使用,DMA不会影响主程序,当我的UART接收端有数据时,会自动将数据搬运到内存。此时,cpu只需要判断是否内存中是否接收到了数据即可。

        在接收数据时,是如何判断将一包数据保存到缓存中? 当检测到RX引脚空闲(高电平)时间超过传输一个字符帧所需的时间时,就会产生空闲中断标志LDLEF。当一包数据发送过来时字节与字节之间的空闲时间是可以忽略不记的,但是,包与包之间的空闲时间就长了,可以利用这个来判断接收到了一包数据。

实验过程:

配置DMA:


/**
************************************************************
* @brief  DMA配置
* @param	
* @return
************************************************************
*/
static void usbComDmaInit(void)
{
	//使能DMA时钟
	RCC_AHBPeriphClockCmd(uartInfo.dmaPeriphClock, ENABLE);
	//复位该通道的DMA设置
	DMA_DeInit(uartInfo.dmaCh);
	//DMA配置结构体
	DMA_InitTypeDef dmaConfig;
	//搬运的内存基地址(数组)
	dmaConfig.DMA_MemoryBaseAddr = (uint32_t)ricvBuf;
	//外设的基地址(USART的数据寄存器,基地址+0x04)
	dmaConfig.DMA_PeripheralBaseAddr = USART1_DATA_ADDR;
	//设置方向为外设为源地址
	dmaConfig.DMA_DIR = DMA_DIR_PeripheralSRC;
	//最大搬运长度
	dmaConfig.DMA_BufferSize = MAX_BUFF_SIZE;
	//设置外设不为自增,因为数据寄存器地址是固定的
	dmaConfig.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	//设置内存缓冲区地址为增量(数组)
	dmaConfig.DMA_MemoryInc = DMA_MemoryInc_Enable;
	//这里有三种:字节、半字、字,这里选择字节
	dmaConfig.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	dmaConfig.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	//这是内存到内存标志,使用的是外设到内存,选择失能
	dmaConfig.DMA_M2M = DMA_M2M_Disable;
	//模式为接收一次即可,还有一种为循环模式
	dmaConfig.DMA_Mode = DMA_Mode_Normal;
	//优先级设置为高,有四种:低、中等、高、非常高
	dmaConfig.DMA_Priority = DMA_Priority_High;
	//初始化
	DMA_Init(uartInfo.dmaCh, &dmaConfig);
	//使能USART DMA
	USART_DMACmd(uartInfo.uartNu, USART_DMAReq_Rx, ENABLE);
	//使能DMA通道
	DMA_Cmd(uartInfo.dmaCh, ENABLE);
	
}

配置中断服务函数:

/**
************************************************************
* @brief  UART中断服务函数
* @param	
* @return
************************************************************
*/
void USART1_IRQHandler(void)
{
	
	if(USART_GetITStatus(uartInfo.uartNu, USART_IT_IDLE) == SET)
	{
		USART_ClearITPendingBit(uartInfo.uartNu, USART_IT_IDLE);	//清空中断
		USART_ReceiveData(uartInfo.uartNu);		//清空中断
		
		//获取接收数据查看是否为接收到的数据长度	DMA_GetCurrDataCounter 标志位是做递减所以做差值运算
		if (PACKET_DATA_LEN  == (MAX_BUFF_SIZE - DMA_GetCurrDataCounter(uartInfo.dmaCh)))
		{
			g_pktRcvd = true;
		}
		DMA_Cmd(uartInfo.dmaCh, DISABLE);	//关闭使能通道 否则设置不生效
		DMA_SetCurrDataCounter(uartInfo.dmaCh, MAX_BUFF_SIZE); //重新配置dma搬运最大次数 没有重新配置就结束搬运
		DMA_Cmd(uartInfo.dmaCh, ENABLE);	//打开使能通道 
	}
}

        中断服务函数清空中断,需使用USART_ClearITPendingBit清除中断并且调用一次USART_ReceiveData函数方可清除成功,否则会一直触发。

        标志位是做递减操作所以如果递减次数为0就会结束搬运,所以,要重新设置最大搬运次数。需要注意的是设置最大搬运次数时需要关闭通道使能否则设置不成功。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只想做好编程的小王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值