Stm32 第四十四讲:ADC基本原理


Stm32 第四十四~四十五讲:ADC

STM32F10x ADC特点

  • 12位逐次逼近型的模拟数字转换器;
  • 最多带3个ADC控制器;
  • 最多支持18个通道,可最多测量16个外部和2个内部信号源;
  • 支持单次和连续转换模式;
  • 转换结束、注入转换结束和发生模拟看门狗事件时产生中断;
  • 通道0到通道n的自动扫描模式;
  • 自动校准;
  • 采样间隔可以按通道编程;
  • 规则通道和注入通道均有外部触发选项;
  • 转换结果支持左对齐或右对齐方式存储在16位数据寄存器;
  • ADC转换时间:最大转换速率1us。(最大转换速度为1MHz,在ADCCLK=14M,采样周期为1.5个ADC时钟下得到)
  • ADC供电要求:2.4V~3.6V;
  • ADC输入范围:VREF-≤VIN≤VREF+。

ADC引脚

STM32F10x ADC通道和引脚对应关系

ADC引脚

ADC框图


ADC通道组

①. 规则通道组:相当正常运行的程序。最多16个通道。

规则通道和它的转换顺序在ADC_SQRx寄存器中选择,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中。

②. 注入通道组:相当于中断,最多4个通道。

注入组和它的转换顺序在ADC_JSQR寄存器中选择。注入组里转化的总数应写入ADC_JSQR寄存器的L[1:0]中。

单次转换&连续转换

单次转换

连续转换

扫描模式

扫描模式

SCAN

ADC中断

ADC中断

ADC时钟配置

时钟配置寄存器

RCC_ADCCLKConfig();

不要让ADC时钟超过14MHz,否则可能不准。

ADC相关寄存器

ADC_CR1寄存器

ADC_CR1

ADC_CR1

ADC_CR1

ADC_CR2寄存器

ADC_CR2

ADC_CR2

数据对齐

ADC_CR2

ADC_SMPR1寄存器

ADC_SMPR1

ADC_SMPR2寄存器

ADC_SMPR2

ADC的采样时间

可编程的通道采样时间

最小采样时间1us(ADC时钟=14MHz,采样周期为1.5周期下得到

ADC_SQR1/2/3规则序列寄存器

ADC_SQR1/2/3

ADC_JSQR注入序列寄存器

ADC_JSQR

ADC_DR规则通道数据寄存器

ADC_DR

ADC_JDR规则通道数据寄存器

ADC_JDR

ADC_SR状态寄存器

ADC_SR

ADC常用库函数

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_DeInit(ADC_TypeDef* ADCx)
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);

ADC初始化函数

void ADC_Init(ADC_TypeDef ADCx, ADC_InitTypeDef ADC_InitStruct);

typedef struct
{
  uint32_t ADC_Mode;//ADC模式:配置ADC_CR1寄存器的位[19:16]:DUALMODE[3:0]位
  FunctionalState ADC_ScanConvMode; //是否使用扫描模式。ADC_CR1位8:SCAN位 
  FunctionalState ADC_ContinuousConvMode; //单次转换or连续转换:ADC_CR2的位1:CONT
  uint32_t ADC_ExternalTrigConv;  //触发方式:ADC_CR2的位[19:17] :EXTSEL[2:0]             
  uint32_t ADC_DataAlign;   //对齐方式:左对齐还是右对齐:ADC_CR2的位11:ALIGN         
  uint8_t ADC_NbrOfChannel;//规则通道序列长度:ADC_SQR1的位[23:20]: L[3:0]       
}ADC_InitTypeDef;

例如:

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;    //不开启扫描 
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//单次转换模式
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使能函数

void ADC_Cmd(ADC_TypeDef ADCx, FunctionalState NewState);

例如:

ADC_Cmd(ADC1, ENABLE);    //使能指定的ADC1

ADC使能软件转换函数

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)

例如:

ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能ADC1的软件转换启动

ADC规则通道配置函数

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

例如:

ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1,ADC_SampleTime_239Cycles5);

ADC获取转换结果函数

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

例如:

ADC_GetConversionValue(ADC1);//获取ADC1转换结果

ADC模数转换实验

实验目的:ADC1的通道1(PA1)进行单次转化

转换过程

①. 开启PA口时钟和ADC1时钟,设置PA1为模拟输入;

GPIO_Init();      
APB2PeriphClockCmd();

②. 复位ADC1,同时设置ADC1分频因子;

RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_DeInit(ADC1);

③. 初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息;

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);

④. 使能ADC并校准;

ADC_Cmd(ADC1, ENABLE);

⑤. 配置规则通道参数;

ADC_RegularChannelConfig();

⑥. 开启软件转换;

ADC_SoftwareStartConvCmd(ADC1);

⑦. 等待转换完成,读取ADC值。

ADC_GetConversionValue(ADC1);

程序代码

在这里只给出adc.h、adc.c和main.c的代码。

adc.h

#ifndef __ADC_H
#define __ADC_H    
#include "sys.h"

void Adc_Init(void);
u16  Get_Adc(u8 ch); 
u16 Get_Adc_Average(u8 ch,u8 times); 

#endif 

adc.c

#include "adc.h"
#include "delay.h"

//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3                                                                       
void  Adc_Init(void)
{     
    ADC_InitTypeDef ADC_InitStructure; 
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1,ENABLE );      //使能ADC1通道时钟

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

    //PA1 作为模拟通道输入引脚                         
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //模拟输入引脚
    GPIO_Init(GPIOA, &GPIO_InitStructure);    

    ADC_DeInit(ADC1);  //复位ADC1 

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;    //ADC工作模式:ADC1和ADC2工作在独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;    //模数转换工作在单通道模式
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;    //模数转换工作在单次转换模式
    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_ResetCalibration(ADC1);    //使能复位校准  

    while(ADC_GetResetCalibrationStatus(ADC1));    //等待复位校准结束

    ADC_StartCalibration(ADC1);     //开启AD校准

    while(ADC_GetCalibrationStatus(ADC1));     //等待校准结束

//    ADC_SoftwareStartConvCmd(ADC1, ENABLE);        //使能指定的ADC1的软件转换启动功能

}                  
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)   
{
      //设置指定ADC的规则组通道,一个序列,采样时间
    ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );    //ADC1,ADC通道,采样时间为239.5周期                      

    ADC_SoftwareStartConvCmd(ADC1, ENABLE);        //使能指定的ADC1的软件转换启动功能    

    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

    return ADC_GetConversionValue(ADC1);    //返回最近一次ADC1规则组的转换结果
}

u16 Get_Adc_Average(u8 ch,u8 times)
{
    u32 temp_val=0;
    u8 t;
    for(t=0;t<times;t++)
    {
        temp_val+=Get_Adc(ch);
        delay_ms(5);
    }
    return temp_val/times;
}      

main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"     
#include "adc.h"

 int main(void)
 {     
  u16 adcx;
    float temp;
    delay_init();             //延时函数初始化      
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    uart_init(115200);         //串口初始化为115200
     LED_Init();                 //LED端口初始化
    LCD_Init();                 
     Adc_Init();                  //ADC初始化

    POINT_COLOR=RED;//设置字体为红色 
    LCD_ShowString(60,50,200,16,16,"WarShip STM32");    
    LCD_ShowString(60,70,200,16,16,"ADC TEST");    
    LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    LCD_ShowString(60,110,200,16,16,"2015/1/14");    
    //显示提示信息
    POINT_COLOR=BLUE;//设置字体为蓝色
    LCD_ShowString(60,130,200,16,16,"ADC_CH0_VAL:");          
    LCD_ShowString(60,150,200,16,16,"ADC_CH0_VOL:0.000V");           
    while(1)
    {
        adcx=Get_Adc_Average(ADC_Channel_1,10);
        LCD_ShowxNum(156,130,adcx,4,16,0);//显示ADC的值
        temp=(float)adcx*(3.3/4096);
        adcx=temp;
        LCD_ShowxNum(156,150,adcx,1,16,0);//显示电压值
        temp-=adcx;
        temp*=1000;
        LCD_ShowxNum(172,150,temp,3,16,0X80);
        LED0=!LED0;
        delay_ms(250);    
    }
 }

文章作者: Mat Jenin
文章链接: http://matjenin.xyz
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mat Jenin !
  目录