STM32 ADC详解

0一、ADC简介

ADC是Analog-to-DigitalConverter的缩写。指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。典型的模拟数字转换器将模拟信号转换为表示必定比例电压值的数字信号。git

从STM32F207的数据手册中下图看到,STM32F207VC有3个精度为12bit的ADC控制器,有16个外部通道,而144脚的STM32F207Zx和176脚的STM32F207Ix由于带PF脚,因此多8个通道,为24个外部通道。各通道的A/D转换能够单次、连续、扫描或间断执行,ADC转换的结果能够左对齐或右对齐储存在16位数据寄存器中。github

0二、STM32的ADC外设

上面说到,STM32F207有3个12bit的ADC控制器,下文将以ADC3的通道10讲解。app

首先咱们确认下ADC外设所在的地址总线,从STM32F207数据手册中下图看到,ADC属于APB2总线下,APB2时钟频率是60MHz。具体STM32若是经过外部25M晶振获得的60MHz的APB2,请看《STM32F207时钟系统解析》。函数

对应GPIO,咱们从STM32F207数据手册中看到,咱们可使用PC0做为ADC3的通道10。测试

这里须要说明的是,以前的文章使用其余外设时,好比《STM32PWM输出》中,寻找对应的管脚时,咱们都是从STM32F207数据手册的Alternatefunctionmapping表中寻找,这是由于ADC对应的管脚使用的是Additionalfunctions,PWM对应的管脚使用的是Alternatefunctions。ui

区别是:spa

Additionalfunctions:附加,辅助功能,引脚被链接到其余模块使用,使用时直接普通配置便可,例如ADC的采用输入通道,配置为模拟输入。设计

Alternate functions:复用功能,即将IO口用做普通输入输出之外的功能,例如串口输入输出,使用时须要配置复用模式。3d

 

在以前的文章《STM32GPIO详解》中有以下介绍。code

STM32标准外设库中有以下代码

typedef enum
{   
    GPIO_Mode_IN   = 0x00, /*!< GPIO Input Mode */  
    GPIO_Mode_OUT  = 0x01, /*!< GPIO Output Mode */  
    GPIO_Mode_AF   = 0x02, /*!< GPIO Alternate function Mode */  
    GPIO_Mode_AN   = 0x03  /*!< GPIO Analog Mode */
}GPIOMode_TypeDef;

其中GPIO_Mode_AF对应的就是Alternate functions:复用功能,GPIO_Mode_AN对应的就是Additional functions:附加,辅助功能。

 

0三、STM32ADC框图讲解

下图是STM32ADC的结构框图,咱们将其划分为7个部分进行讲解。

一、输入电压范围

ADC所能测量的电压范围就是VREF-≤ VIN ≤ VREF+,把VSSA 和VREF-接地,把VREF+和VDDA 接3V3,获得ADC的输入电压范围为:0~3.3V。

二、输入通道

ADC的信号时经过输入通道进入单片机内部的,单片机经过ADC模块将模拟信号转换为数字信号。上图标记②的部分显示了外部的16个通道,链接的GPIO,对应的关系如上面讲解的,须要在STM32F207数据手册的STM32F20xpin and ball definitions表格中寻找。实际上STM32还有内部通道,ADC1的通道 16链接到了芯片内部的温度传感器,Vrefint 链接到了通道17。ADC2的模拟通道 16和 17链接到了内部的VSS。

三、转换通道

外部的16个通道在转换时又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路(注入通道貌似使用很少),下面简单介绍一下俩种通道:

规则通道

规则通道顾名思义就是,最日常的通道、也是最经常使用的通道,平时的ADC转换都是用规则通道实的。规则通道和它的转换顺序在ADC_SQRx寄存器中选择,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中。

注入通道

注入通道是相对于规则通道的,注入通道能够在规则通道转换时,强行插入转换,至关于一个“中断通道”吧。当有注入通道须要转换时,规则通道的转换会中止,优先执行注入通道的转换,当注入通道的转换执行完毕后,再回到以前规则通道进行转换。最多4个通道,注入组和它的转换顺序在ADC_JSQR寄存器中选择。注入组里转化的总数应写入ADC_JSQR寄存器的L[1:0]中。

一个ADC控制器有多个通道,这就涉及使用多个通道进行转换就涉及到一个前后顺序的问题了,毕竟规则转换通道只有一个数据寄存器。多个通道的使用顺序分为俩种状况:规则通道的转换顺序和注入通道的转换顺序。

规则通道转换顺序

规则通道中的转换顺序由三个寄存器控制:SQR一、SQR二、SQR3,它们都是32位寄存器。SQR寄存器控制着转换通道的数目和转换顺序,只要在对应的寄存器位SQx中写入相应的通道,这个通道就是第x个转换,经过SQR1寄存器就能了解其转换顺序在寄存器上的实现了。

注入通道转换顺序

和规则通道转换顺序的控制同样,注入通道的转换也是经过注入寄存器来控制,只不过只有一个JSQR寄存器来控制,控制关系以下:

须要注意的是,只有当JL=4的时候,注入通道的转换顺序才会按照JSQ一、JSQ二、JSQ三、JSQ4的顺序执行。当JL<4时,注入通道的转换顺序偏偏相反,也就是执行顺序为:JSQ四、JSQ三、JSQ二、JSQ1。

配置转换顺序的函数

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel,uint8_t Rank, uint8_t ADC_SampleTime)

 

0四、触发源

ADC转换的输入、通道、转换顺序都已经说明了,但ADC转换是怎么触发的呢?就像通讯协议同样,都要规定一个起始信号才能传输信息,ADC也须要一个触发信号来实行模/数转换。

其一就是经过直接配置寄存器触发,经过配置控制寄存器CR2的ADON位,写1时开始转换,写0时中止转换。在程序运行过程当中只要调用库函数,将CR2寄存器的ADON位置1就能够进行转换,比较好理解。

另外,还能够经过内部定时器或者外部IO触发转换,也就是说能够利用内部时钟让ADC进行周期性的转换,也能够利用外部IO使ADC在须要时转换,具体的触发由控制寄存器CR2决定。

 

0五、转换周期

可独立设置各通道采样时间

ADC会在数个ADCCLK周期内对输入电压进行采样,可以使用ADC_SMPR1和ADC_SMPR2

寄存器中的SMP[2:0]位修改周期数。每一个通道都可以使用不一样的采样时间进行采样。

总转换时间的计算公式以下:

    Tconv=采样时间+12个周期

示例:

    ADCCLK = 30 MHz且采样时间=3个周期时:

    Tconv= 3+12=15个周期=0.5us (APB2为60MHz时)

最小采样时间0.42us(ADC时钟=36MHz,采样周期为3周期下获得)。

 

0六、数据寄存器

转换完成后的数据就存放在数据寄存器中,但数据的存放也分为规则通道转换数据和注入通道转换数据的。

规则数据寄存器

规则数据寄存器负责存放规则通道转换的数据,经过32位寄存器ADC_DR来存放。

注入数据寄存器

注入通道转换的数据寄存器有4个,因为注入通道最多有4个,因此注入通道转换的数据都有固定的存放位置,不会跟规则寄存器那样产生数据覆盖的问题。 ADC_JDRx是 32位的,低 16位有效,高 16位保留,数据一样分为左对齐和右对齐,具体是以哪种方式存放,由ADC_CR2的 11 位ALIGN 设置。

0七、中断

能够产生4种中断

①DMA溢出中断

当配置了DMA,且DMA溢出时产生中断

②规则通道转换完成中断

规则通道数据转换完成以后,能够产生一个中断,能够在中断函数中读取规则数据寄存器的值。这也是单通道时读取数据的一种方法。

③注入通道转换完成中断

注入通道数据转换完成以后,能够产生一个中断,而且也能够在中断中读取注入数据寄存器的值,达到读取数据的做用。

④模拟看门狗事件

当输入的模拟量(电压)再也不阈值范围内就会产生看门狗事件,就是用来监视输入的模拟量是否常。

0八、电压转换

转换后的数据是一个12位的二进制数,咱们须要把这个二进制数表明的模拟量(电压)用数字表示出来。好比测量的电压范围是0~3.3V,转换后的二进制数是x,由于12位ADC在转换时将电压的范围大小(也就是3.3)分为4096(2^12)份,因此转换后的二进制数x表明的真实电压的计算方法就是:

y=3.3* x / 4096

 

0九、电路图设计

电路图很简单,能够在ADC引脚上输入不一样的电压,也能够直接方便的使用滑动变阻器实现不一样的电压变化。

 

十、代码设计

ADC外设配置的结构体

typedef struct
{
  uint32_t ADC_Resolution;                /*!< Configures the ADC resolution dual mode. 
                                               This parameter can be a value of @ref ADC_resolution */                                   
  FunctionalState ADC_ScanConvMode;       /*!< Specifies whether the conversion 
                                               is performed in Scan (multichannels) 
                                               or Single (one channel) mode.
                                               This parameter can be set to ENABLE or DISABLE */ 
  FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion 
                                               is performed in Continuous or Single mode.
                                               This parameter can be set to ENABLE or DISABLE. */
  uint32_t ADC_ExternalTrigConvEdge;      /*!< Select the external trigger edge and
                                               enable the trigger of a regular group. 
                                               This parameter can be a value of 
                                               @ref ADC_external_trigger_edge_for_regular_channels_conversion */
  uint32_t ADC_ExternalTrigConv;          /*!< Select the external event used to trigger 
                                               the start of conversion of a regular group.
                                               This parameter can be a value of 
                                               @ref ADC_extrenal_trigger_sources_for_regular_channels_conversion */
  uint32_t ADC_DataAlign;                 /*!< Specifies whether the ADC data  alignment
                                               is left or right. This parameter can be 
                                               a value of @ref ADC_data_align */
  uint8_t  ADC_NbrOfConversion;           /*!< Specifies the number of ADC conversions
                                               that will be done using the sequencer for
                                               regular channel group.
                                               This parameter must range from 1 to 16. */
}ADC_InitTypeDef;

ADC_Resolution:ADC 工做模式选择,ADC分辨率

ADC_ScanConvMode:ADC 扫描(多通道)或者单次(单通道)模式选择

ADC_ContinuousConvMode:ADC 单次转换或者连续转换选择

ADC_ExternalTrigConvEdge:ADC 外部触发极性配置

ADC_ExternalTrigConv:ADC 转换触发信号选择

ADC_DataAlign:ADC 数据寄存器对齐格式

ADC_NbrOfConversion:ADC转换通道数目

typedef struct
{
    uint32_t ADC_Mode;//多重ADC模式选择
    uint32_t ADC_Prescaler;  //ADC预分频                             
    uint32_t ADC_DMAAccessMode;   //DMA访问模式       
    uint32_t ADC_TwoSamplingDelay; //2个采样阶段之间的延迟      
}ADC_CommonInitTypeDef;

ADC_CommonInitTypeDef用来配置ADC_CCR寄存器的相关参数

ADC外设和DMA配置代码

/**
  * @brief  ADC3 channel10 with DMA configuration
  * @param  None
  * @retval None
  */
void ADC3_CH10_DMA_Config(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;
 
  /* Enable ADC3, DMA2 and GPIO clocks ****************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
 
  /* DMA2 Stream0 channel2 configuration **************************************/
  DMA_InitStructure.DMA_Channel = DMA_Channel_2;  
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  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);
 
  /* Configure ADC3 Channel10 pin as analog input ******************************/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
 
  /* ADC Common Init **********************************************************/
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);
 
  /* ADC3 Init ****************************************************************/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADC3, &ADC_InitStructure);
 
  /* ADC3 regular channel7 configuration *************************************/
  ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);
 
 /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
 
  /* Enable ADC3 DMA */
  ADC_DMACmd(ADC3, ENABLE);
 
  /* Enable ADC3 */
  ADC_Cmd(ADC3, ENABLE);
}

代码下载验证测试

 

硬件和软件开源地址:

https://github.com/strongercjd/STM32F207VCT6

 

点击查看本文所在的专辑,STM32F207教程

相关文章
相关标签/搜索