ADC模数转换在stm32上的应用

ADC模数转换在stm32上的应用

文章目录

  • ADC模数转换在stm32上的应用
  • 1. 什么是ADC?
  • 2. stm32中的ADC
  • 3. 12位逐次逼近型ADC
  • 1. 工作原理
  • 2. 主要特性
  • 3. 关键部件
  • 4. 优点
  • 5. 缺点
  • 6. 应用
  • 7. 配置和使用
  • 4. stm32的ADC转换模式
  • 1. 单次转换模式 (Single Conversion Mode)
  • 2. 连续转换模式 (Continuous Conversion Mode)
  • 3. 扫描模式 (Scan Mode)
  • 4. 多ADC同步模式 (Dual/Multi-ADC Synchronization Mode)
  • 5. 触发和外部事件管理
  • 5. ADC单通道&多通道转换
  • 1. 什么是ADC?

    ADC是"Analog-to-Digital Converter"(模数转换器)的缩写。它是一种电子器件或电路,用于将连续变化的模拟信号(如电压或电流)转换为数字信号(通常是二进制码),这样计算机和数字设备就可以处理这些信号。

    在许多电子系统中,比如音频设备、通信系统、测量仪器等,ADC都是一个关键组件。通过ADC,真实世界的物理信号(如声音、温度、压力等)可以被转换成数字形式,进而被微处理器或计算机分析和处理。

    ADC的主要参数包括:

  • 分辨率:表示转换后的数字信号能表示多少个离散值,通常以位数表示(例如8位、12位、16位等)。
  • 采样率:单位时间内能够完成的转换次数,通常用Hz(赫兹)来表示。
  • 量化误差:由于数字信号只能近似表示模拟信号,这种近似带来的误差称为量化误差。
  • 信噪比(SNR):信号功率与噪声功率的比值,反映了ADC输出信号的质量。
  • 动态范围:ADC能有效转换的最大信号幅度与最小可检测信号幅度之比。
  • ADC的类型有很多种,常见的有逐次逼近型(SAR)、积分型(Sigma-Delta)、并行比较型(Flash)等。每种类型的ADC都有其特定的应用场景和技术优势。

    2. stm32中的ADC

    STM32 微控制器中的 ADC(Analog-to-Digital Converter)是一种模拟到数字转换器,用于将模拟信号转换为数字信号,以便微控制器可以处理这些信号。STM32 系列微控制器提供了多种型号,而不同的型号可能拥有不同数量和特性的 ADC。

    以下是一些关于 STM32 中 ADC 的主要特点:

    1. 类型

    2. STM32 的 ADC 通常采用 12 位逐次逼近型设计,这意味着它可以提供 4096 (2^12) 个不同的数字输出值,对应于输入电压的变化。
    3. 分辨率

    4. 12 位的分辨率意味着 ADC 可以区分出输入电压的微小变化,最小分辨率为 VREF / 4096。
    5. 通道数

    6. 不同型号的 STM32 可能有不同的通道数。例如,STM32F10X 系列支持最多 18 个通道,其中 16 个可以连接到外部信号源,另外 2 个用于内部信号源。
    7. STM32F4 系列支持多达 19 个复用通道,可以测量来自 16 个外部源和 2 个内部源的信号。
    8. 转换模式

    9. 单次转换模式:每次只进行一次转换。
    10. 连续转换模式:在连续模式下,ADC 会连续不断地进行转换,直到被软件停止。
    11. 扫描模式:此模式下,ADC 会在指定的多个通道上依次进行转换。
    12. 间断模式:允许在多个连续转换之间插入空闲周期,以减少功耗。
    13. 触发源

    14. ADC 可以通过硬件触发启动转换,例如定时器的中断输出或外部中断线。
    15. 数据对齐

    16. ADC 结果可以左对齐或右对齐在 16 位的数据寄存器中。左对齐意味着最低有效位 (LSB) 在寄存器的最低位位置;右对齐则意味着最高有效位 (MSB) 在寄存器的最高位位置。
    17. 供电要求

    18. 通常,ADC 的供电范围为 2.4V 至 3.6V,而输入电压范围由参考电压 VREF 决定,即 VREF- ≤ VIN ≤ VREF+。
    19. 校准

    20. ADC 提供了校准功能,以确保转换精度。校准可以通过软件命令启动。
    21. 中断和事件

    22. ADC 支持中断机制,在转换结束、注入转换结束以及模拟看门狗事件时可以产生中断。
    23. 多 ADC 模式

    24. 一些 STM32 型号配备了多个 ADC,它们可以独立工作,也可以在双重或三重模式下协同工作,以实现更高的采样率。

    3. 12位逐次逼近型ADC

    12位逐次逼近型ADC(Analog-to-Digital Converter)是一种常用的模数转换器类型,广泛应用于各种电子设备中。

    1. 工作原理

    逐次逼近型ADC的工作原理基于比较器和数字-模拟转换器(DAC)。其基本过程如下:

    1. 初始化:将DAC的输出设为中间值,此时DAC输出为参考电压的一半。
    2. 比较:将输入模拟电压与DAC输出进行比较。
    3. 调整:根据比较结果,调整DAC的输出以接近输入电压。
    4. 重复:重复上述步骤,每次改变DAC输出的一个位,直到所有位都被确定为止。

    具体来说,对于12位ADC,这个过程需要进行12次迭代,每次迭代确定一位的值。每次迭代后,DAC输出值都会向输入电压靠近,最终得到最接近输入电压的12位数字值。

    2. 主要特性

  • 分辨率:12位ADC可以分辨出输入电压的4096个不同级别((2^{12} = 4096))。
  • 量化误差:量化误差是指ADC输出的数字值与实际模拟输入之间的最大偏差。对于12位ADC,量化误差通常为满量程电压的1/4096。
  • 转换时间:转换时间取决于时钟频率和所需的位数。对于12位ADC,如果每个比特需要一个时钟周期,则转换时间大约为12个时钟周期加上一些额外的时间(如建立时间和稳定时间)。
  • 3. 关键部件

  • 比较器:用于比较输入电压与DAC输出。
  • 数字-模拟转换器(DAC):用于生成模拟电压供比较器比较。
  • 逐次逼近寄存器(SAR):存储每次迭代中确定的比特位。
  • 控制逻辑:控制整个转换过程,包括时序和位的更新。
  • 4. 优点

  • 速度快:逐次逼近型ADC通常比其他类型的ADC(如积分型ADC)更快。
  • 易于实现:硬件结构简单,便于集成。
  • 成本效益高:适用于大多数中低速应用,具有良好的性价比。
  • 5. 缺点

  • 功耗:由于需要快速转换,逐次逼近型ADC相对于积分型ADC而言功耗较高。
  • 精度限制:虽然12位分辨率已经足够高,但在需要更高精度的情况下可能不是最佳选择。
  • 6. 应用

  • 数据采集系统:用于测量传感器输出的模拟信号。
  • 音频处理:用于将麦克风等音频源的模拟信号转换为数字信号。
  • 通信系统:用于接收端的信号处理。
  • 工业自动化:用于监控和控制系统的信号采集。
  • 7. 配置和使用

    配置12位逐次逼近型ADC通常涉及以下几个步骤:

  • 设置参考电压:确定ADC的参考电压范围。
  • 选择时钟频率:根据转换速度需求选择合适的时钟频率。
  • 配置分辨率:尽管是12位ADC,但某些情况下可能需要降低分辨率以提高转换速度。
  • 设置触发源:选择硬件触发还是软件触发。
  • 配置中断:设置中断使能,以便在转换完成后接收中断通知。
  • 4. stm32的ADC转换模式

    STM32 微控制器系列提供了多种 ADC(Analog-to-Digital Converter)转换模式来适应不同的应用场景。

    1. 单次转换模式 (Single Conversion Mode)

  • 描述:在这种模式下,每次启动转换后,ADC 将执行一次转换,然后进入待机状态等待下一次启动。
  • 用途:适合不需要连续采样的场合,比如测量按键状态或温度等。
  • 2. 连续转换模式 (Continuous Conversion Mode)

  • 描述:在这种模式下,一旦启动转换,ADC 将连续不断地执行转换,直到通过软件停止或硬件事件自动停止。
  • 用途:适合需要连续采集数据的应用场景,例如实时信号采集。
  • 3. 扫描模式 (Scan Mode)

  • 描述:在扫描模式下,ADC 可以依次转换一组通道,每个通道转换结束后会自动切换到下一个通道,直到完成所有指定通道的转换。
  • 用途:当需要对多个通道进行连续采样时非常有用,比如多路传感器数据采集。
  • 4. 多ADC同步模式 (Dual/Multi-ADC Synchronization Mode)

  • 描述:STM32 的一些型号支持两个或更多 ADC 的同步操作,可以实现多个 ADC 在相同时间点开始转换,这对于需要同步采集多路信号的应用非常有用。
  • 用途:例如在电机控制中,需要同时读取三相电流或电压。
  • 5. 触发和外部事件管理

  • 描述:STM32 ADC 支持由内部或外部事件触发转换开始。这些触发可以来自定时器的输出比较单元、外部引脚变化或其他 ADC 的转换结束。
  • 用途:可以用来实现精确的采样时机控制,比如与 PWM 输出同步采集信号。
  • 5. ADC单通道&多通道转换

    1. 启用ADC和GPIO时钟:

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
      
    2. 这两行代码启用了ADC1外设和GPIOA端口的时钟,这是配置它们之前必须做的步骤。
    3. 配置ADC时钟分频:

      RCC_ADCCLKConfig(RCC_PCLK2_Div6);
      
    4. 这行设置了ADC时钟为APB2总线时钟(PCLK2)的六分之一。ADC时钟频率不应超过其最大限制,通常约为14 MHz。
    5. 配置GPIO作为模拟输入:

      GPIO_InitTypeDef GPIO_InitStructure;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOA, &GPIO_InitStructure);
      
    6. 初始化GPIOA的第0号引脚为模拟输入模式。GPIO的速度设置为50 MHz,这虽然与ADC操作不直接相关,但需要正确配置。
    7. 配置常规通道:

      ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
      
    8. ADC1: 指定要配置的ADC实例,在这个例子中是ADC1。
    9. ADC_Channel_0: 指定要配置的ADC通道,这里是ADC通道0。
    10. 1: 这个参数指定了在常规序列中的通道位置。在这个例子中,通道0被设置为序列中的第一个通道。
    11. ADC_SampleTime_55Cycles5: 指定了采样时间,即ADC采集模拟信号的时间长度。在这个例子中,采样时间为55.5个ADC时钟周期。
    12. 初始化ADC:

      ADC_InitTypeDef ADC_InitStructure;
      ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
      ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
      ADC_InitStructure.ADC_ScanConvMode = DISABLE;
      ADC_InitStructure.ADC_NbrOfChannel = 1;
      ADC_Init(ADC1, &ADC_InitStructure);
      
    13. 这段代码初始化ADC1:
    14. 设置ADC工作模式为独立模式。
    15. 数据对齐方式设置为右对齐。
    16. 外部触发转换禁用。
    17. 连续转换模式禁用。
    18. 扫描模式禁用。
    19. 通道数量设置为1个。
    20. 使能ADC并开始校准:

      ADC_Cmd(ADC1, ENABLE);
      
      ADC_ResetCalibration(ADC1);
      while (ADC_GetResetCalibrationStatus(ADC1) == SET);
      ADC_StartCalibration(ADC1);
      while (ADC_GetCalibrationStatus(ADC1) == SET);
      
    21. 使能ADC1。
    22. 开始重置校准,等待校准重置完成。
    23. 开始校准过程,等待校准完成。

    这个函数用于获取ADC转换后的数值。

    1. 启动软件触发的转换:

      ADC_SoftwareStartConvCmd(ADC1, ENABLE);
      
    2. 启动ADC的软件触发转换。
    3. 等待转换完成:

      while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
      
    4. 等待直到转换结束标志位被置位。
    5. 读取转换结果:

      return ADC_GetConversionValue(ADC1);
      
    6. 返回ADC转换得到的数值。

    单通道转换完整代码

    void AD_Init(void)
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	
    	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    	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);
    	
    	ADC_InitTypeDef ADC_InitStructure;
    	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    	ADC_InitStructure.ADC_NbrOfChannel = 1;
    	ADC_Init(ADC1, &ADC_InitStructure);
    	
    	ADC_Cmd(ADC1, ENABLE);
    	
    	ADC_ResetCalibration(ADC1);
    	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);
    	return ADC_GetConversionValue(ADC1);
    }
    

    多通道转换配置流程

    与单通道不同的是只需要在部分地方进行改动即可:

    1. 配置多个GPIO作为模拟输入:

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
      
    2. 这里配置了GPIOA的引脚0、1、2和3为模拟输入,而不是只配置引脚0。
    3. AD_GetValue函数接受一个参数:

      uint16_t AD_GetValue(uint8_t ADC_Channel)
      
    4. 这个函数现在接受一个uint8_t类型的参数ADC_Channel,表示要读取哪个ADC通道的数据。
    5. 配置指定的ADC通道:

      ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
      
    6. AD_GetValue函数中,使用传递进来的ADC_Channel参数来配置ADC通道,而不是固定配置通道0。
    7. 其他部分保持不变:

    8. 其他部分如ADC的初始化、使能、校准等没有变化。

    完整

    #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);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    	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_InitStructure.ADC_Mode = ADC_Mode_Independent;
    	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    	ADC_InitStructure.ADC_NbrOfChannel = 1;
    	ADC_Init(ADC1, &ADC_InitStructure);
    	
    	ADC_Cmd(ADC1, ENABLE);
    	
    	ADC_ResetCalibration(ADC1);
    	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
    	ADC_StartCalibration(ADC1);
    	while (ADC_GetCalibrationStatus(ADC1) == SET);
    }
    
    uint16_t AD_GetValue(uint8_t ADC_Channel)
    {
    	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
    	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    	return ADC_GetConversionValue(ADC1);
    }
    

    作者:FightingLod

    物联沃分享整理
    物联沃-IOTWORD物联网 » ADC模数转换在stm32上的应用

    发表回复