项目笔记:在stm32f103c8上用DMA控制串口收发

一、传统串口收发与引入DMA控制的区别

传统串口收发每一步都经过CPU处理和控制,当总线数据量大且频繁时CPU要反复地进入中断中处理,而引入DMA的差异就在于DMA会自动处理这个过程,并不需要占用CPU。

二、在不同芯片上所包含的DMA数量不同

对于stm32f103c8这颗芯片只有DMA1,但它有7个通道,每个通道对应不同外设 如下

三、对于DMA初始化及其配置

cpp 复制代码
    DMA_DeInit(DMA1_Channel4);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; 
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&UP_TxBuffer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = 20;//TxMaxLen;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel4, &DMA_InitStructure);
	DMA_DeInit(DMA1_Channel5);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&UP_RxBuffer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//	DMA_InitStructure.DMA_BufferSize = sizeof(RxBuffer);
	DMA_InitStructure.DMA_BufferSize = 149;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_ClearFlag(DMA1_FLAG_GL4|DMA1_FLAG_TC4|DMA1_FLAG_HT4|DMA1_FLAG_TE4);
	
	DMA_Init(DMA1_Channel5,&DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel5,ENABLE);

其中较为关键的三步:

DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;

DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&UP_TxBuffer;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

第一二步是两个容器的地址,即告诉DMA数据流的源头和目的地,第三步指明DMA的传输方向,从UP_TxBuffer首地址开始流向USART1->DR即实现了串口的发送。
接受亦是如此

DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;

DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&UP_RxBuffer;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

不同点在于第二步的缓冲区不同以及第三步的数据流向不同,这里为USART1->DR流向UP_Rxbuffer即实现了串口的接收。

四、关于数据帧的接收处理

cpp 复制代码
void USART1_IRQHandler(void)
{
    
	unsigned char i = 0,len = 0;
	//当总线空闲时,往外发送数据
//	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){
//		
//	}
	if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET){			
		//读串口SR和DR清除idle标志
		
		DMA_Cmd(DMA1_Channel5,DISABLE);
		
		if(1){
			
			len = 149 - DMA_GetCurrDataCounter(DMA1_Channel5);
			for(i = 0;i<len;i++){
				UP_analysis_buf[i] = UP_RxBuffer[i];
			}
			//uart1_send_string(UP_RxBuffer,strlen((char*)UP_RxBuffer));
			//memset(UP_RxBuffer,0,149);
		}
//			if(sendFlag == 0){
//				memset(UP_RxBuffer,0,149);
//				memset(UP_TxBuffer,0,20);
				DMA_SetCurrDataCounter(DMA1_Channel5,149);
				DMA_Cmd(DMA1_Channel5,ENABLE);
				USART_ClearITPendingBit(USART1,USART_IT_IDLE);
				i = USART1->SR;
				i = USART1->DR;
				sendFlag = 1;
			//}
		}
		
//	if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)
//	{
//		USART_ClearITPendingBit(USART1,USART_IT_TC);
//	}
}

这里利用串口的空闲中断,当总线产生一个空闲中断时代表一帧数据的结束,这时我们可对数据选择我们需要的长度进行备份从而方便解析。

五、数据的发送方法

如下对缓冲区进行填充并使能DMA相应通道就能自动处理这一过程。

cpp 复制代码
                memset(UP_TxBuffer,0,20);
				for(i = 0;i<strlen(UP_RxBuffer);i++){
					UP_TxBuffer[i] = UP_RxBuffer[i];
				}
				memset(UP_RxBuffer,0,149);
				UP_TxBuffer[i] = '\0';
				//snprintf(UP_TxBuffer,strlen(UP_RxBuffer)+1,UP_RxBuffer);
				//strcpy(UP_TxBuffer,UP_RxBuffer);
				DMA_SetCurrDataCounter(DMA1_Channel4,strlen(UP_TxBuffer));
				DMA_Cmd(DMA1_Channel4 ,ENABLE);
相关推荐
hazy1k12 小时前
51单片机基础-最小系统设计
stm32·单片机·嵌入式硬件·mcu·51单片机·proteus
_Brooke_13 小时前
CS336笔记2-Architectures,Hyperparameters
笔记
奋斗的牛马13 小时前
FPGA—ZYNQ学习spi(六)
单片机·嵌入式硬件·学习·fpga开发·信息与通信
被遗忘的旋律.13 小时前
Linux驱动开发笔记(十九)——IIC(AP3216C驱动+MPU6050驱动)
linux·驱动开发·笔记
清风66666614 小时前
基于单片机的智能高温消毒与烘干系统设计
数据库·单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
wyiyiyi14 小时前
【数据结构+算法】进栈顺序推算、卡特兰数与逆波兰表达式
汇编·数据结构·笔记·算法
Jerry丶Li14 小时前
二十四、STM32的DMA
stm32·单片机·嵌入式硬件
Larry_Yanan15 小时前
QML学习笔记(五十二)QML与C++交互:数据转换——时间和日期
开发语言·c++·笔记·qt·学习·ui·交互
TL滕15 小时前
从0开始学算法——第二天(时间、空间复杂度)
数据结构·笔记·学习·算法
C++chaofan15 小时前
MyBatis - Plus学习笔记
java·spring boot·笔记·后端·mysql·架构·mybatis