Loading

什么是ADC

本文是关于ADC(模数转换器)的基本概念、工作原理及基于STM32的驱动实现的详细讲解:


一、ADC核心原理与关键参数

1. ADC基本概念

ADC(Analog-to-Digital Converter)将连续的模拟信号(如电压、温度、声音)转换为离散的数字信号(二进制数值)。其核心步骤包括:

  • 采样:在固定时间间隔内获取模拟信号的瞬时值(时间离散化)。
  • 保持:在采样期间保持信号值不变,避免转换过程中信号变化。
  • 量化:将采样值映射到有限的离散电平(幅值离散化)。
  • 编码:将量化后的值转换为二进制数字(如二进制、格雷码)。

2. 关键参数

  • 分辨率(Resolution)
    ADC输出的二进制位数(如12位、16位),决定最小可分辨的电压变化(LSB,最低有效位)。
    公式:分辨率 = 满量程电压 / (2^N),其中N为位数。
    例如:12位ADC,Vref=3.3V时,LSB = 3.3V / 4096 ≈ 0.8mV。

  • 采样率(Sampling Rate)
    单位时间内完成的采样次数(SPS)。
    关键公式:奈奎斯特定理要求采样率 ≥ 2×信号最高频率,否则会产生混叠(Aliasing)。

  • 参考电压(Vref)
    ADC的基准电压,决定转换范围。例如,若Vref=3.3V,则输入信号范围为0~3.3V。

  • 输入通道(Channel)
    ADC可连接的模拟信号输入引脚。STM32的ADC支持多通道切换,需配置通道映射。

  • 采样时间(Sample Time)
    每次采样过程中,ADC对输入信号稳定时间的设置。需根据信号频率和通道特性调整。


二、ADC驱动实现(以STM32为例)

1. ADC外设初始化流程

步骤

  1. 时钟配置

    • 使能ADC和GPIO时钟(如RCC_APB2PeriphClockCmd)。
    • 设置ADC时钟分频(如ADC_ClockMode)。
  2. 分辨率与参考电压配置

    • 设置分辨率(如12位):ADC_Resolution_12b
    • 选择参考电压(内部或外部):ADC_VoltageRegulat or_Enable启用内部Vref+。
  3. 通道配置

    • 配置模拟输入引脚(如PA0)为模拟模式:GPIO_Init
    • 设置通道参数(如通道号、采样时间):ADC_RegularChannelConfig
  4. 触发源配置

    • 软件触发:ADC_ExternalTrigConvEdge_None
    • 硬件触发(如定时器):ADC_ExternalTrigConv_Tx_TRGO
  5. 使能ADC

    • 初始化ADC:ADC_Init
    • 使能ADC:ADC_Cmd(ADC1, ENABLE)
    • 校准ADC:ADC_ResetCalibrationADC_StartCalibration

2. 启动转换与数据读取

三种方式对比

方式 特点 适用场景
轮询(Polling) 持续查询转换完成标志,简单直接。 低速、单通道采集。
中断(Interrupt) 转换完成触发中断,降低CPU负载。 需实时响应的场景。
DMA(Direct Memory Access) 使用DMA自动传输数据到内存,高效。 高速、多通道或连续采集。

代码示例(轮询模式)

// 启动转换
ADC_StartConversion(ADC1);

// 轮询等待完成
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));

// 读取结果
uint16_t adc_value = ADC_GetConversionValue(ADC1);

3. 多通道采样设计

  • 配置通道序列:通过ADC_RegularChannelConfig设置多个通道,形成转换序列。
  • 数据管理:使用数组存储多通道数据,或通过DMA直接写入缓冲区。
// 配置通道1(PA0)和通道2(PA1)
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5);

// 启动连续转换
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续模式
ADC_Init(ADC1, &ADC_InitStructure);

4. 精度优化手段

  • 硬件滤波:通过ADC的硬件去抖(如ADC_OverrunMode)。

  • 软件滤波

    • 滑动平均:对连续N次采样值求平均。
      uint16_t sum = 0;
      for(int i=0; i<10; i++) {
          sum += ADC_GetConversionValue(ADC1);
          Delay_us(10); // 防止重复读取相同值
      }
      uint16_t avg = sum / 10;
      
    • 中值滤波:取中间值抑制突变噪声。
  • 参考电压稳定性:使用低噪声LDO(如STM32的Vref+需外部去耦电容)。


5. HAL库与寄存器操作差异

方式 特点 适用场景
HAL库 封装了底层寄存器操作,代码简洁。 快速开发,无需深入硬件细节。
寄存器操作 直接配置寄存器,灵活高效。 需自定义时序或优化性能时。

示例:寄存器配置ADC分辨率

// 使用寄存器设置12位分辨率
ADC1->CR1 &= ~ADC_CR1_RES; // 清除分辨率位
ADC1->CR1 |= ADC_CR1_RES_0; // 12位模式

三、典型代码模板(STM32 HAL库)

#include "stm32f1xx_hal.h"

ADC_HandleTypeDef hadc1;
uint16_t adc_value;

void ADC_Init(void) {
    __HAL_RCC_ADC1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    hadc1.Instance = ADC1;
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    hadc1.Init.ScanConvMode = DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    HAL_ADC_Init(&hadc1);

    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = ADC_CHANNEL_0;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

void ADC_Start(void) {
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 10);
    adc_value = HAL_ADC_GetValue(&hadc1);
}

四、注意事项与应用场景

  1. 供电精度

    • 参考电压(Vref+)需稳定,建议使用低噪声LDO并加去耦电容(如10μF+0.1μF)。
    • 多通道切换时,避免不同通道间的串扰(如使用隔离电容)。
  2. 采样时序

    • 高频信号需足够采样时间(如快速变化信号需短采样时间)。
    • 多通道连续转换需确保转换速率与DMA吞吐率匹配。
  3. 典型应用

    • 工业控制:温度、压力传感器(需高分辨率和抗干扰)。
    • 消费电子:电池电压监测(低功耗模式)。
    • 汽车电子:发动机参数采集(需高可靠性与EMC设计)。

五、流程图与思维导图

ADC初始化流程图

graph TD A[启动] --> B{时钟配置} B --> C[使能ADC时钟] C --> D[配置GPIO为模拟模式] D --> E[设置ADC分辨率] E --> F[选择参考电压] F --> G[配置通道参数] G --> H[选择触发源] H --> I[使能ADC并校准] I --> J[完成初始化]

转换流程思维导图

graph TD A[启动转换] --> B[等待完成(轮询/中断/DMA)] B -->|轮询| C[主循环中读取] B -->|中断| D[中断回调函数处理] B -->|DMA| E[DMA缓冲区传输] C --> F[读取数据] D --> F E --> F F --> G{需要滤波?} G -->|是| H[滑动平均或中值滤波] H -->|否| I[直接使用数据]

通过以上步骤,您可以实现一个基础ADC驱动,并根据具体需求优化性能与精度。

posted @ 2025-04-16 10:10  Christopher_James  阅读(773)  评论(0)    收藏  举报