STM32F103 ADC软件触发+DMA数据传输(内部温度)

DMA知识介绍

DMA,又叫做直接存储器访问。是一种硬件机制,在单片机系统中常用于数据传输或存储器操作等场合,其目的是在不占用 CPU 时间的情况下,通过直接操作内存和外设实现数据的高速传输。相比于传统的 CPU 访问方式,DMA 机制的数据传输速度更高,能够提高系统的性能和效率。在单片机中,DMA 通常用于高速数据传输、缓存清空、内存拷贝、外设数据处理等场合。例如,当需要将传感器数据从 ADC 外设存取到存储器中时,可以使用 DMA 实现高速数据传输,从而提高系统的性能和效率。

DMA就是把数据从地址A转移到地址B,因此使用 DMA 需要配置 DMA 控制器,包括设置源、目的地址、数据传输长度、传输方向等参数,并启动 DMA 控制器执行数据传输。同时,为了保证数据的正确性和完整性,需要进行一定的数据校验和错误处理。

代码展示

下面我将以图文结合的方式来进行DMA实验的代码分析,我这里最终实现的效果是软件触发转换的ADC值通过DMA将数据运输至内存当中,采用的传感器是单片机的内部温度传感器。

main.c

extern u32 SendBuff;	//发送数据缓冲区
int main(void)
{	 
	u16 i=0;
	u16 adc1; 
	delay_init();	    	//延时函数初始化	  
	uart_init(115200);	 	//串口初始化为115200
	LED_Init();		  		//初始化与LED连接的硬件接口

	MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)&SendBuff,1);
	
	Adc_Init();		  	//ADC初始化	 
	while(1)
	{		
		adc1=T_Get_Adc(ADC_Channel_16);
		printf("adc1=%d\r\n",adc1); //得到真实的adc数据
		printf("DMA DATA:\r\n");    

		ADC_DMACmd(ADC1,ENABLE); 	//使能ADC1的DMA发送  
		DMA_Cmd(DMA1_Channel1, ENABLE);	//开始一次DMA传输	


	    printf("传输后dma=%d\r\n",SendBuff);	//输出传输过来的数据,对比真实数据判断是否正确
		SendBuff=0;

		//系统指示灯
		i++;
		delay_ms(10);
		if(i==20)
		{
			LED0=!LED0;//提示系统正在运行	
			i=0;
		}	
		printf("--------------------\r\n");			
	}
}

首先进行一些必要的初始化,根据查表得知ADC1使用的是DMA1的通道1,因此在DMA初始化中我们需要填入DMA1的通道1、ADC1的DR寄存器地址、传输后内存中变量的地址、传输数据量这几个参数,本次实验每次传输只传输1个32位长度的数据,因此数量为1。

2a3f9844ff1948f18b08fc465ddbe49e.png

接着主循环中因为我们需要验证传输前后的准确性,所以在传输前将ADC的DR寄存器中的值输出出来,DMA传输后将SendBuff的值输出出来作对比。

函数T_Get_Adc()的作用是启动一次模数转换,并返回ADC1中DR寄存器中的数值,接着是进行一次DMA传输。

dma.c

u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度 	    
//DMA1的各通道配置
//从ADC->内存模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量 
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
	DMA_InitTypeDef DMA_InitStructure;
 	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA传输
	// DMA1通道配置	
	DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值

	DMA1_MEM_LEN=cndtr;
	DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设基地址
	DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取发送到内存
	DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;  //内存地址寄存器不变
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //数据宽度为16位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //工作在循环模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有中优先级 
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
	  	
} 
//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{ 
	DMA_Cmd(DMA_CHx, DISABLE );  //关闭USART1 TX DMA1 所指示的通道      
 	DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
 	DMA_Cmd(DMA_CHx, ENABLE);  //使能USART1 TX DMA1 所指示的通道 
}	  

本函数中主要是对DMA的配置,传入外设基地址和内存基地址,然后设置传输方向为外设到内存;缓存大小即每次数据传输的数据量,此处为1;然后设置内存和外设地址都不变;因为ADC数据大小为0~4095,所以设置数据宽度为半字(范围0~65535);工作在循环模式,优先级设置中优先级,此处不重要,因为只传输一个;非内存到内存。

函数开启一次DMA传输和之前main函数中直接调用的那一句话效果相同,只不过先使能再使能更稳定一点。

adc.c

		   
//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3	
u32 SendBuff;

void Adc_Init(void)  //ADC通道初始化
{
	ADC_InitTypeDef ADC_InitStructure; 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );	  //使能GPIOA,ADC1通道时钟
	
	// ADC1配置  
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //分频因子6时钟为72M/6=12MHz
  	ADC_DeInit(ADC1);  //将外设 ADC1 的全部寄存器重设为缺省值

	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//模数转换工作在单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//模数转换工作在循环转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
	
	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1
	ADC_TempSensorVrefintCmd(ENABLE); //开启内部温度传感器

	ADC_ResetCalibration(ADC1);	//重置指定的ADC1的复位寄存器

  	while(ADC_GetResetCalibrationStatus(ADC1));	//获取ADC1重置校准寄存器的状态,设置状态则等待
	ADC_StartCalibration(ADC1);	 //
	while(ADC_GetCalibrationStatus(ADC1));		//获取指定ADC1的校准程序,设置状态则等待
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);	
}

u16 T_Get_Adc(u8 ch)   
{
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );	//ADC1,ADC通道3,第一个转换,采样时间为239.5周期	  			    
 
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}

首先对ADC时用到的硬件进行时钟使能;然后设置分频因子;设置ADC参数,设置ADC1和ADC2工作在独立模式,模数转换在单通道,循环转换,软件触发启动转换,数据右对齐,每次只转换1个通道的数据;将ADC1使能并开启内部温度传感器,最后就是对ADC1进行校准。

在函数T_Get_Adc()中我们也可以清楚的看到,本函数的作用是进行一次模数转换,关键语句时第43行,接着44行判断转换是否结束。

最终效果

802693473112418ea9a84ba8e6c0060f.png

 

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: STM32F103是意法半导体(STMicroelectronics)公司推出的一款基于ARM Cortex-M3内核的32位微控制器。它具有丰富的外设和高性能,常用于各种应用领域。 其中的DMA(Direct Memory Access)是一种高速数据传输方式,它可以在不经过CPU的干预下,直接将数据从外设传输到内存,或者从内存传输到外设。这种方式可以显著提高数据传输的效率。STM32F103中的DMA控制器可以与多个外设进行数据传输,包括ADC和TIM。 ADC(Analog-to-Digital Converter)是模数转换器,用于将模拟信号转换为数字信号。STM32F103ADC模块具有多个通道,可以同时采集多个模拟信号,并将其转换为相应的数字值。通过DMA控制器,ADC模块可以将采集到的数据直接传输到内存,而无需CPU的干预。这样可以实现高效的模拟信号采集。 TIM(Timer)是定时器,可以用于生成各种定时、计数和PWM信号。STM32F103的定时器模块具有多个通道和多种功能,可以用于测量时间间隔、产生定时中断、实现PWM输出等。通过DMA控制器,定时器模块可以将产生的定时或PWM数据直接传输到外设,如LED驱动器等,大大减轻CPU的负担。 综上所述,STM32F103中的DMAADC和TIM模块具有协同工作的能力,可以实现高效的数据传输和信号采集。通过合理配置和使用这些模块,可以大大提升系统的性能和效率。 ### 回答2: STM32F103是一款基于ARM Cortex-M3内核的微控制器,具有丰富的外设资源。DMA(Direct Memory Access)是一种直接内存访问技术,可以实现外设与内存之间的数据传输,提高系统的数据传输效率。ADC(Analog-to-Digital Converter)是模数转换器,用于将模拟信号转换为数字信号。TIM(Timer)则是定时器,用于产生定时和计数操作。 STM32F103支持DMA控制器和多个ADC通道,这使得在数据采集过程中可以使用DMA来直接将ADC采样的数据传输到内存中,而无需CPU参与,从而提高了系统的效率。通过配置DMA通道和ADCDMA请求,可以实现自动转换和传输。在传输完成之后,可以通过DMA传输完成中断来进行相应的处理。 另外,STM32F103还具备多个定时器(TIM),其中包括基本定时器和通用定时器。可以使用定时器来产生特定的时间间隔,并触发相应的事件。通过配置定时器的预分频器、计数器和各种模式,可以满足不同的定时和计数需求。 综上所述,使用STM32F103DMAADC和TIM外设可以实现高效的数据采集和定时操作。通过合理配置和编程,可以满足不同应用场景下的实时数据采集和事件触发需求。 ### 回答3: STM32F103是意法半导体(STMicroelectronics)生产的一款32位单片机,它具有强大的性能和丰富的外设功能。其中DMA(Direct Memory Access,直接内存访问)是一种数据传输技术,ADC(Analog-to-Digital Converter,模数转换器)是一种模拟信号转换为数字信号的设备,而TIM(Timer/Counter,定时器/计数器)是用于计时和计数的设备。 在STM32F103中,DMA用于优化数据传输,通过在外设和存储器之间建立直接通道,实现数据的高速传输,减轻了单片机的处理负担。ADC是用于将模拟信号转换为数字信号的重要功能模块,可以采集外部传感器的模拟信号,并将其转换为数字形式供单片机处理。而TIM用来实现各种计时和计数功能,例如控制器模块中的PWM(Pulse Width Modulation,脉冲宽度调制)输出、测量时间间隔等。 在应用中,可以使用DMA来优化ADC数据传输。通过配置DMA控制器,可以在ADC转换值就绪后,自动将转换结果复制到指定的存储位置,实现高效的数据传输。另外,TIM可以与ADC结合使用,通过定时触发ADC的转换,实现周期性采样。这样可以实现周期性信号的连续采样,满足一些实时性要求较高的应用场景。 总之,STM32F103DMAADC和TIM等功能模块的结合应用可以实现高效的数据传输和处理,满足各种应用需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值