(STM32)AD功能的连接配置方式------单AD多通道实现

一、为何使用ADC

  为了能够使用数字电路处理模拟信号,必须将模拟信号转换成相应的数字信号,方能送入数字系统(例如微型计算机)进行处理,而这一种从模拟信号到数字信号的转换称为模—数转换,或简称为A/D(Analog to Digital)转换[1]。当作为传感器的电路系统产出模拟信号时,AD模块无疑是直观显示传感器功能状态的最佳选择。

  STM32F4xx系列的AD最高可配置12位的分辨率,同时可在其规则通道转换期间可产生 DMA 请求来减轻CPU负担。

  STM32的AD采集主要区别在于使用的AD数量和AD使用的通道数量,多AD的采集优势在于可以增加传感器的扫描频率,获得更加多的AD采集数据,如在AD通道数量比较紧缺而且对数据量没那么多的情况下,单AD多通道采集无疑是比较好的方法。本次主要讨论的就是单AD多通道采集数据的方法。由于规则通道组只有一个数据寄存器,因此,对于多个规则通道的转换,使用 DMA 非常有帮助。这样可以避免丢失在下一次写入之前还未被读出的 ADC_DR 寄存器中的数据[2]

二、AD初始化的方式

  STM32F429中提供了3个AD可供使用,其中DMA2是直接对ADC提供服务的,DMA2的请求映射分别对应的是:ADC1:数据流0通道0和数据流4通道0,ADC2:数据流2通道1和数据流3通道1,ADC3:数据流0通道2和数据流1通道2,详情可参考CPU手册。

  首先需要初始化的是ADC所引出的GPIO引脚,没啥需要注意的,只要没有搞错引脚就行,配置方法可见上一篇(STM32)GPIO库函数使用一览 。

  第二步时配置所需要使用的DMA,配置的时候需要注意的几项:1.ADC的外设基址,负责获取ADC的数据;2.读取数据的地址,从这里可以读出DMA的ADC数据,即是设置一个与通道数相应匹配的大小的数组;3.搞清楚DMA的请求映射。

  最后就是配置ADC,STM32F4中的AD初始化库函数:ADC_CommonInit()ADC_Init()配置的分别是通用类型变量和ADC的初始化

typedef struct 
{
  uint32_t ADC_Mode;   
  uint32_t ADC_Prescaler;
  uint32_t ADC_DMAAccessMode; 
  uint32_t ADC_TwoSamplingDelay;
}ADC_CommonInitTypeDef;

  ADC_CommonInit()中包含的是ADC模式选择,分频,DMA模式配置和采样延迟。

  1.ADC模式主要针对于ADC数量的选择,独立模式可选ADC_Mode_Independent。

  2.分频可选ADC_Prescaler_Div2/Div4/Div6/Div8。

  3.DMA模式,是针对于多ADC中配置的,独立模式选择ADC_DMAAccessMode_Disabled。

  4.采样延迟可配置5-20的任意值,ADC_TwoSamplingDelay_10Cycles。

typedef struct
{
  uint32_t ADC_Resolution;                           
  FunctionalState ADC_ScanConvMode; 
  FunctionalState ADC_ContinuousConvMode;
  uint32_t ADC_ExternalTrigConvEdge; 
  uint32_t ADC_ExternalTrigConv; 
  uint32_t ADC_DataAlign; 
  uint8_t  ADC_NbrOfConversion; 
}ADC_InitTypeDef;

  ADC_Init()中包含的是ADC分辨率,是否扫描,是否连续转换,触发极性和触发选择,数据对齐和通道数目。

  1.分辨率可从12/10/8/6中做选择,ADC_Resolution_12/10/8/6b.

  2.在多通道时需要对扫描转换使能,单通道的不需要。

  3.连续转换指的是在各个通道读值完毕后继续读值。

  4.外部触发的条件有很多,需要根据外设来具体分析

  5.数据对齐有两种,左对齐和右对齐,一般是选择右对齐。

  6.通道数目为对应配置的通道数。


三、AD的配置功能实现

ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_56Cycles);      
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 2, ADC_SampleTime_56Cycles);    
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 3, ADC_SampleTime_56Cycles);     
  ADC_RegularChannelConfig();设置ADC通道的转换顺序及时间。

  ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE); 该函数仅在单ADC模式中使用,功能是在ADC最后传输后DMA启用或禁用请求。

  ADC_DMACmd(ADC1, ENABLE);ADC是否使用DMA的请求。

  ADC_Cmd(ADC1, ENABLE);使用ADC的请求。

  在初始化后,接上ADC的功能请求函数即可完成对ADC功能的配置。

  此时ADC的数据全部由DMA中配置的读取地址中获取,就是当时所写的数组中获取。

四、功能示例

  功能示例中表现的是单AD多通道的例子:

#include "bsp.h"
#include 


static void ADC_Configuration(void);
uint16_t ADC_Value[7]={0};//AD数据
uint16_t local[7]={0};

int  main()
{
  while(1){
    local[0]=(float)(ADC_Value[0]*3.3/4096);
    local[1]=(float)(ADC_Value[1]*3.3/4096);
    local[2]=(float)(ADC_Value[2]*3.3/4096);
    printf("channel 1 value = %fV\r\n",local[0]);
    printf("channel 2 value = %fV\r\n",local[1]);
    printf("channel 3 value = %fV\r\n",local[2]);
  }
}


/*独立模式多通道 电压采集*/
static void ADC_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure_C;
	
	GPIO_InitTypeDef GPIO_InitStructure_A;
	
	ADC_InitTypeDef ADC_InitStructure;
	
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	
        /* 使能 GPIOC clock */
 	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	GPIO_InitStructure_C.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3;
	GPIO_InitStructure_C.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure_C.GPIO_PuPd = GPIO_PuPd_NOPULL;                               //不上拉不下拉
	GPIO_Init(GPIOC, &GPIO_InitStructure_C);

	/* 使能 GPIOA clock */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	GPIO_InitStructure_A.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
	GPIO_InitStructure_A.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure_A.GPIO_PuPd = GPIO_PuPd_NOPULL;                               //不上拉不下拉
	GPIO_Init(GPIOA, &GPIO_InitStructure_A);
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	 
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	
	/* DMA Init 结构体初始化 DMA2 Stream 0 channel 0 配置用于ADC1*/
	DMA_InitTypeDef DMA_InitStructure;
	DMA_DeInit(DMA2_Stream0);
	DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                   //选择DMA通道
	DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)(0x40012000+0x4c);           //外设基址->ADC
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC_Value;                     //储存器地址->读取数据地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                          //数据传输方向为外设到存储器
	DMA_InitStructure.DMA_BufferSize = 7;                                            //缓冲区大小,即一次传输的数据项
	
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                 //外部寄存器只有一个,地址不用递增
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                          //存储器地址递增
	
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;      //外设数据大小为一个字符,四个字节(可改HalfWord为半个字,两个字节)
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;              //存储器数据大小与外设一致
	
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                  //循环传输模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;                              //DMA优先级最高
 
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                           //DMA直连模式        
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;                //FIFO大小,FIFO模式禁止,不用配置
	
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                      //存储器突发单次传输   
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;              //外设突发单次传输
  
	DMA_Init(DMA2_Stream0, &DMA_InitStructure); 
	
	DMA_Cmd(DMA2_Stream0, ENABLE);                                                   //使能DMA数据流
        /* DMA Init 结构体初始化 DMA2 Stream 0 channel 0 配置用于ADC1*/
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);                              //ADC1复位
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);	                         //复位结束	 
	
	/* ADC Common结构体参数初始化*/
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                         //独立模式
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;                      //时钟分频
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;		     //禁止DMA直接访问模式
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles;    //采样时间间隔
	ADC_CommonInit(&ADC_CommonInitStructure);	
	
	/*ADC Init结构体参数初始化*/
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                            //分辨率
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                      //多通道采集,开启扫描模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                //连续转换
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;       //禁止外部边沿触发
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                            //右对齐
    ADC_InitStructure.ADC_NbrOfConversion = 7;                                        //转换通道数
    ADC_Init(ADC1, &ADC_InitStructure);

	/* 配置ADC1 的通道转换顺序和采样时间周期*/
	ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_56Cycles);       //引脚PC0
	ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 2, ADC_SampleTime_56Cycles);       //引脚PC2
	ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 3, ADC_SampleTime_56Cycles);       //引脚PC3
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3,  4, ADC_SampleTime_56Cycles);       //引脚PA3
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4,  5, ADC_SampleTime_56Cycles);       //引脚PA4
	ADC_RegularChannelConfig(ADC1, ADC_Channel_5,  6, ADC_SampleTime_56Cycles);       //引脚PA5
	ADC_RegularChannelConfig(ADC1, ADC_Channel_6,  7, ADC_SampleTime_56Cycles);       //引脚PA6

	ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);                                  //使能DMA请求
	ADC_DMACmd(ADC1, ENABLE);                                                         //使能ADC1 DMA
	ADC_Cmd(ADC1, ENABLE);                                                            //使能ADC1  
	ADC_SoftwareStartConv(ADC1);                                                      //开启软件使能
}

  实现后,可以打印出3个通道的电压值,电压的计算主要与参考电压VREF有关;计算公式为:

电压=(VREF*扫描值)/2^12




  [1]阎石.数字电子技术基础(第五版)[M].高等教育出版社,2006.

  [2]STM32F407, 429参考手册.

你可能感兴趣的:(STM32F4)