65 STM32F0系列 串口DMA循环接收实验记录

1.引言

        最近因为中断冲突问题,导致串口接收数据时随机丢失一两个字节。无奈串口的中断优先级不能是最高的,所以中断冲突问题明显存在,因此需要串口使用DMA方式来接收数据,从而规避串口接收数据丢失问题。

2.DMA配置经验

        首次使用dma,需要了解一下dma的知识。

        1.首先最重要要了解的一点就是,dma接收数据一定要接收到指定长度的数据,或指定长度的一半数据才能产生接收中断,如果数据没有达到一半或指定长度,就无法产生dma接收数据通知。

        一般解决这个问题是串口空闲中断IDE方式解决。也就是串口传完数据产生空闲中断后去读取DMA收到的数据,就能接收不定长度的数据了。

        然而现实很悲催,我所使用的cortex-m0芯片,居然没有串口空闲中断,为此需要另寻它法。所以就选择了在while(1)循环中接收DMA数据了。

        2.既然配置了串口的DMA接收,因此就不需要启动串口接收中断了,但串口的收发模式配置还是需要的。如下:

UART_InitStructure.UART_Mode		= UART_Mode_Rx | UART_Mode_Tx; //收发模式

        3.DMA模式选择

        DMA_Mode_Normal和DMA_Mode_Circular模式,指的是单次和多次的问题。如果是DMA_Mode_Normal模式,进行完一次DMA数据传输后,要启动第二次DMA传输,需先关闭该DMA通道,重新设置DMA传输数据个数,再开启DMA通道。而DMA_Mode_Circular模式则不需要,其会自动配置。

         下述代码中有这个体现,DMA_Mode_Normal模式下如果不重新配置,则收发就不正常。

        4.查看串口对应的DMA channel

        对于STM32F030单片机UART1引脚对应的DMA channel通道,可以看STM32F030参考手册,而不是芯片手册!!!!别找错文档了。然后查所使用的的引脚对应的通道选择就行。

在这里插入图片描述         我所使用的是USART1,并且没有重映射RX到其它引脚,因此是channel3,这个实际的时候要注意,别搞错了,当然搞错了也没关系,试一下就好了,花不了什么时间。

 

3.实验代码

#define UART1_RX_LEN		(64)
uint8_t tUart1_Rx[UART1_RX_LEN] = {0};


void UART1_Init(void)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    NVIC_InitTypeDef NVIC_InitStructure = {0};
	UART_InitTypeDef UART_InitStructure = {0};

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);	//使能UART1,GPIOA时钟
	/
	//1.引脚初始化
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_0);
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_0);

	GPIO_InitStructure.GPIO_Pin		= GPIO_Pin_6; //PA.9
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.9
	
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_7;//PA10
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_IPU;//浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.10 

	/
	//2.串口初始化
	UART_InitStructure.UART_BaudRate 	= 115200;//串口波特率
	UART_InitStructure.UART_WordLength	= UART_WordLength_8b;//字长为8位数据格式
	UART_InitStructure.UART_StopBits	= UART_StopBits_1;//一个停止位
	UART_InitStructure.UART_Parity		= UART_Parity_No;//无奇偶校验位
	UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;//无硬件数据流控制
	UART_InitStructure.UART_Mode		= UART_Mode_Rx | UART_Mode_Tx; //收发模式
	UART_Init(UART1, &UART_InitStructure); //初始化串口1
	UART_DMACmd(UART1, UART_DMAReq_EN, ENABLE); 
	UART_Cmd(UART1, ENABLE);

	//dma配置
    UART1_DMAInit();
}

void UART1_DMAInit(void)
{
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

	/
	//dma初始化 p -> m
	DMA_DeInit(DMA1_Channel3);	
	DMA_Cmd(DMA1_Channel3, DISABLE);
	DMA_InitStructure.DMA_PeripheralBaseAddr 	= (uint32_t)&UART1->RDR;//外设数据地址
	DMA_InitStructure.DMA_MemoryBaseAddr 		= (uint32_t)tUart1_Rx;  //自己的接收buf
	DMA_InitStructure.DMA_BufferSize			= UART1_RX_LEN;  // 缓存大小
	DMA_InitStructure.DMA_M2M 					= DMA_M2M_Disable;	 // 内存到内存关闭
	DMA_InitStructure.DMA_Mode 					= DMA_Mode_Normal;	// 普通模式
	DMA_InitStructure.DMA_DIR 					= DMA_DIR_PeripheralSRC;	 // 外设到内存
	DMA_InitStructure.DMA_Priority 				= DMA_Priority_High; // DMA通道优先级
	DMA_InitStructure.DMA_MemoryInc 			= DMA_MemoryInc_Enable;// 内存地址递增
	DMA_InitStructure.DMA_PeripheralInc			= DMA_PeripheralInc_Disable;//外设基地址不需要递增
	DMA_InitStructure.DMA_MemoryDataSize 		= DMA_MemoryDataSize_Byte; 
	DMA_InitStructure.DMA_PeripheralDataSize 	= DMA_PeripheralDataSize_Byte;
	DMA_Init(DMA1_Channel3,&DMA_InitStructure);
	DMA_Cmd(DMA1_Channel3, ENABLE); 
	/
}

//因为该单片机没有串口空闲中断
//所以只能使用poll接收dma数据
//该函数放在while(1)中即可
void UART1_DMAChannel3_rcvTask(void)
{
	uint16_t rxSize = 0;

	//获取当前接收到的数据大小
	rxSize = UART1_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel3);
	//如果数据大于0,说明开始接收数据了
	if(rxSize>0)
	{
		//休眠10ms,是因为让串口dma继续接收数据
		//根据115200波特率计算,10ms足够传输1024字节大小的数据
		//所以delay 10ms基本满足单次数据的收
		delay_ms(50);
		DMA_Cmd (DMA1_Channel3,DISABLE);//重新配置DMA时,需要先disableDMA

		//接收完成,再获取一次实际的数据长度
		rxSize = UART1_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel3);

		//接收数据,写入buf
		BleClient_RcvDataBufIn(tUart1_Rx, rxSize);
		
		memset(tUart1_Rx,0,UART1_RX_LEN);    //清空数组
		DMA_Init(DMA1_Channel3, &DMA_InitStructure); //重新配置一次DMA
		DMA_Cmd (DMA1_Channel3,ENABLE); 
	}
}

over!

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值