问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32 ADC数模转换器详解与实战

创作时间:
作者:
@小白创作中心

STM32 ADC数模转换器详解与实战

引用
CSDN
1.
https://blog.csdn.net/qq_45419343/article/details/139359279

ADC(模拟-数字转换器)是嵌入式系统中常用的一种硬件模块,用于将模拟信号转换为数字信号。本文将详细介绍STM32微控制器中的ADC模块的工作原理和使用方法,并通过具体的代码示例展示如何实现单通道和多通道的AD转换。

一、ADC(Analog-Digital Converter)模拟-数字转换器

  1. ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路数字电路的桥梁
  2. 12位逐次逼近型ADC,1us转换时间
  3. 输入电压范围:0~3.3V,转换结果范围:0~4095
  4. 18个输入通道,可测量16个外部2个内部信号源
  5. 规则组注入组两个转换单元
  6. 模拟看门狗自动监测输入电压范围
  7. STM32F103C8T6ADC资源:ADC1、ADC2,10个外部输入通道
  8. 逐次逼近型ADC
  9. ADC框图
  10. ADC基本结构
  11. 转换模式
  • 单次转换,非扫描模式
  • 连续转换,非扫描模式
  • 单次转换,扫描模式
  • 连续转换,扫描模式
  1. 数据对齐
  2. 转换时间
  • AD转换的步骤:采样,保持,量化,编码
  • STM32 ADC的总转换时间为:
    TCONV = 采样时间 + 12.5个ADC周期
  • 例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
    TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs
  1. 校准
  • ADC有一个内置自校准模式。校准可大幅减小内部电容器组的变化造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
  • 建议在每次上电后执行一次校准
  • 启动校准前,ADC必须处于关电状态超过至少两个ADC时钟周期

二、AD单通道

  1. 按照以下接线方式连接,并将STLINK插到电脑上

  1. AD转换函数驱动模块
  • ADCCLK的配置函数(在RCC中)

  • ADC相关库函数功能

  • AD.c

    #include "stm32f10x.h"                  // Device header
    void AD_Init(void)
    {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);		//开启时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//配置ADCCLK 72MHz/6=12MHz
        
        GPIO_InitTypeDef GPIO_InitStructure;					//配置GPIO
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入,在AIN模式下,GPIO口是无效的,断开GPIO,防止GPIO口的输入输出对模拟电压造成干扰,AIN模式就是ADC的专属模式
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        
        ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);	//采用周期:55.5 转换周期:固定为12.5  一共68个周期	//选择规则组的输入通道
        
        ADC_InitTypeDef ADC_InitStructure;											//结构体初始化ADC
        ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//连续转换模式
        ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据对齐
        ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//触发控制
        ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
        ADC_InitStructure.ADC_NbrOfChannel=1;//通道数目,在扫描模式下会用到几个通道
        ADC_InitStructure.ADC_ScanConvMode=DISABLE;//扫描转换模式
        ADC_Init(ADC1,&ADC_InitStructure);		
        
        ADC_Cmd(ADC1,ENABLE);														//开启AC电源
        
        ADC_ResetCalibration(ADC1);							//复位校准				//ADC校准
        while(ADC_GetResetCalibrationStatus(ADC1) == SET);	//返回复位校准的状态
        ADC_StartCalibration(ADC1);							//开始校准
        while(ADC_GetCalibrationStatus(ADC1) == SET);		//获取校准状态		
    }
    uint16_t AD_GetValue(void)
    {
        ADC_SoftwareStartConvCmd(ADC1,ENABLE);
        while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);	//等待时间:1/12MHz*(55.5+12.5)=5.6us
        return ADC_GetConversionValue(ADC1);//读取后自动清除标志位
    }
    
  • AD.h

    #ifndef __AD_H
    #define __AD_H
    void AD_Init(void);
    uint16_t AD_GetValue(void);
    #endif
    
  1. 编写main.c代码

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "AD.h"
    uint16_t ADValue;
    float Voltage;
    int main(void)
    {
        OLED_Init();
        AD_Init();
        
        OLED_ShowString(1,1,"ADValue:");
        OLED_ShowString(2,1,"Voltage:0.00V");
        while(1)
        {
            ADValue = AD_GetValue();
            Voltage = (float)ADValue/4095*3.3;	//AD值转换成电压
            
            OLED_ShowNum(1,9,ADValue,4);
            OLED_ShowNum(2,9,Voltage,1);
            OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);
            
            Delay_ms(100);
        }
    }
    
  2. 实现效果
    AD单通道

  3. 单通道连续转换、非扫描模式
    修改AD.c

三、AD多通道

  1. 按照以下接线方式连接,并将STLINK插到电脑上

  2. AD转换函数驱动模块

  • AD.c

    #include "stm32f10x.h"                  // Device header
    void AD_Init(void)
    {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);		//开启时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//配置ADCCLK 72MHz/6=12MHz
        
        GPIO_InitTypeDef GPIO_InitStructure;					//配置GPIO
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入,在AIN模式下,GPIO口是无效的,断开GPIO,防止GPIO口的输入输出对模拟电压造成干扰,AIN模式就是ADC的专属模式
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        
        
        ADC_InitTypeDef ADC_InitStructure;											//结构体初始化ADC
        ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//连续转换模式
        //ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
        ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据对齐
        ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//触发控制
        ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
        ADC_InitStructure.ADC_NbrOfChannel=1;//通道数目,在扫描模式下会用到几个通道
        ADC_InitStructure.ADC_ScanConvMode=DISABLE;//扫描转换模式
        
        ADC_Init(ADC1,&ADC_InitStructure);		
        
        ADC_Cmd(ADC1,ENABLE);														//开启AC电源
        
        ADC_ResetCalibration(ADC1);							//复位校准				//ADC校准
        while(ADC_GetResetCalibrationStatus(ADC1) == SET);	//返回复位校准的状态
        ADC_StartCalibration(ADC1);							//开始校准
        while(ADC_GetCalibrationStatus(ADC1) == SET);		//获取校准状态	
        //ADC_SoftwareStartConvCmd(ADC1,ENABLE);		//软件触发
    }
    uint16_t AD_GetValue(uint8_t ADC_Channel)
    {
        ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);	//采用周期:55.5 转换周期:固定为12.5  一共68个周期	//选择规则组的输入通道
        ADC_SoftwareStartConvCmd(ADC1,ENABLE);
        while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);	//等待时间:1/12MHz*(55.5+12.5)=5.6us
        return ADC_GetConversionValue(ADC1);//读取后自动清除标志位
    }
    
  • AD.h

    #ifndef __AD_H
    #define __AD_H
    void AD_Init(void);
    uint16_t AD_GetValue(uint8_t ADC_Channel);
    #endif
    
  1. 编写main.c代码

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "AD.h"
    uint16_t AD0,AD1,AD2,AD3;
    int main(void)
    {
        OLED_Init();
        AD_Init();
        
        OLED_ShowString(1,1,"AD0:");
        OLED_ShowString(2,1,"AD1:");
        OLED_ShowString(3,1,"AD2:");
        OLED_ShowString(4,1,"AD3:");
        while(1)
        {
            AD0 = AD_GetValue(ADC_Channel_0);
            AD1 = AD_GetValue(ADC_Channel_1);
            AD2 = AD_GetValue(ADC_Channel_2);
            AD3 = AD_GetValue(ADC_Channel_3);
            
            OLED_ShowNum(1,5,AD0,4);
            OLED_ShowNum(2,5,AD1,4);
            OLED_ShowNum(3,5,AD2,4);
            OLED_ShowNum(4,5,AD3,4);
            
            Delay_ms(100);
        }
    }
    
  2. 实现效果
    AD多通道

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号