stm32六路ADC采集电压——DMA实现

目录

实验概述

DMA概要

初始化源码

结果


实验概述

实验平台:原子的mini开发板(主控RCT6)

使用ADC1的1到6通道采集六路电压,通过串口输出在PC端(XCOM)

ADC_Channel_1--------PA1

ADC_Channel_2--------PA2

ADC_Channel_3--------PA3

ADC_Channel_4--------PA4

ADC_Channel_5--------PA5

ADC_Channel_6--------PA6

DMA概要

直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。
两个DMA控制器有12个通道 (DMA1有7个通道,DMA2有5个通道) ,每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。

使用多路规则通道转换ADC数据时转换好的结果只能存储在一个仅有的数据寄存器之中,如果不对ADC_DR寄存器中的内容做处理,则将会被新转换好的数据覆盖。因此在使用多路ADC数据的转换过程中必须使用DMA对结果进行保存,保证数据不会被覆盖。

初始化源码

以下为初始化代码,包括引脚,DMA,ADC

DMA将每一路ADC的转换结果按顺序存放在adc_original_data[6]中,往复循环,需要哪一路ADC结果就把对应的数组里的值返回处理就好

u16 adc_original_data[6] = {0,0,0,0,0,0};//存放六路ADC原始数据的数组


void  adc_init(void){
	
    GPIO_InitTypeDef GPIO_InitStructure;
	DMA_InitTypeDef DMA_InitInstructure;
	ADC_InitTypeDef ADC_InitStructure;
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );	//使能 ADC1通道时钟
	//PA1 作为模拟通道输入引脚                         
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入引脚
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//初始化两个GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//初始化两个GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//初始化两个GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//初始化两个GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//初始化两个GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	DMA_DeInit(DMA1_Channel1);//复位
	DMA_InitInstructure.DMA_PeripheralBaseAddr =(u32)(&(ADC1->DR));//配置外设的基址,取adc 数据寄存器的地址
	DMA_InitInstructure.DMA_MemoryBaseAddr = (u32)adc_original_data;//把DMA的数据存入数组
	DMA_InitInstructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设到DMA
	DMA_InitInstructure.DMA_BufferSize = 6;//2个通道
	DMA_InitInstructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//
	DMA_InitInstructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitInstructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitInstructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitInstructure.DMA_Mode = DMA_Mode_Circular;//不断地传输,有数据就传输
	DMA_InitInstructure.DMA_Priority = DMA_Priority_High;//DMA优先级
	DMA_InitInstructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel1,&DMA_InitInstructure);
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA请求
	
	
	ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//模数转换工作在多通道模式
	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的寄 存器   
 

 
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1,1, ADC_SampleTime_239Cycles5 );	 
      //ADC1,ADC1通道1,采样时间为239.5周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2,2, ADC_SampleTime_239Cycles5 );	 
     //ADC1,ADC1通道2,采样时间为239.5周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2,3, ADC_SampleTime_239Cycles5 );	 
     //ADC1,ADC1通道3,采样时间为239.5周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2,4, ADC_SampleTime_239Cycles5 );	 
     //ADC1,ADC1通道4,采样时间为239.5周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2,5, ADC_SampleTime_239Cycles5 );	 
     //ADC1,ADC1通道5,采样时间为239.5周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2,6, ADC_SampleTime_239Cycles5 );	 
     //ADC1,ADC1通道6,采样时间为239.5周期
 
    ADC_DMACmd(ADC1,ENABLE);	
    ADC_Cmd(ADC1,ENABLE);
 
	
	ADC_ResetCalibration(ADC1);	//使能复位校准  
	 
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
	
	ADC_StartCalibration(ADC1);	 //开启AD校准
 
	while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能	
	 
	//while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

}

结果

实物接线,就接了三个通道PA1、PA2、PA3

 XCOM上的输出

 such is life

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32的多路ADC采集电压的方法如下: 1. 配置GPIO口为模拟输入模式。 2. 配置ADC时钟和分频器。 3. 配置ADC模式和采样时间。 4. 配置ADC通道和转换顺序。 5. 启动ADC转换。 6. 等待转换完成,读取ADC数据。 7. 计算电压值。 下面是一个简单的代码示例,可以采集PA0、PA1、PA2三个通道的电压值: ```c #include "stm32f10x.h" int main(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; // 使能GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 配置PA0、PA1、PA2为模拟输入模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // 使能ADC1时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 配置ADC时钟和分频器 RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 配置ADC模式和采样时间 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 3; ADC_Init(ADC1, &ADC_InitStructure); // 配置ADC通道和转换顺序 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); // 启动ADC转换 ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); while(1) { // 等待转换完成 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 读取ADC数据 uint16_t adc_value0 = ADC_GetConversionValue(ADC1); ADC_ClearFlag(ADC1, ADC_FLAG_EOC); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); uint16_t adc_value1 = ADC_GetConversionValue(ADC1); ADC_ClearFlag(ADC1, ADC_FLAG_EOC); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); uint16_t adc_value2 = ADC_GetConversionValue(ADC1); ADC_ClearFlag(ADC1, ADC_FLAG_EOC); // 计算电压值 float voltage0 = (float)adc_value0 / 4096 * 3.3; float voltage1 = (float)adc_value1 / 4096 * 3.3; float voltage2 = (float)adc_value2 / 4096 * 3.3; } } ``` 需要注意的是,如果要采集多个通道的电压值,需要先配置扫描模式。在上面的代码中,我们将扫描模式和连续转换模式都开启了,因此ADC会自动按照我们配置的通道顺序进行扫描,并且不停地转换。在每次转换完成后,我们需要手动清除标志位,并且读取转换结果。最后,我们还需要通过计算得到实际的电压值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值