ADC采样详解单片机如何读取电压、电流和温度一、本文适用场景ADC 是单片机和嵌入式开发中非常常见的外设。无论是 STM32、GD32、ESP32还是其他 MCU只要涉及模拟量采集基本都会用到 ADC。例如读取电池电压检测电源电压采集电机电流读取温度传感器采集光敏电阻、电位器、压力传感器等模拟信号做电源系统监控做过压、过流、过温保护。很多初学者学习 ADC 时容易有这些疑问ADC 到底是什么单片机为什么不能直接读取模拟电压ADC 读出来的 2048 是什么意思12 位 ADC 为什么范围是 0~4095参考电压 Vref 有什么作用ADC 值怎么换算成实际电压电流为什么要先变成电压再采样温度为什么也能通过 ADC 读取ADC 读数乱跳、偏差大、一直为 0、一直满量程应该怎么排查本文将从 ADC 的基本概念开始详细介绍 ADC 的采样原理、分辨率、参考电压、换算公式以及电压、电流、温度三类典型采样应用。二、什么是 ADCADC 的英文全称是Analog to Digital Converter中文叫模数转换器它的作用是把连续变化的模拟电压转换成单片机可以处理的数字值。单片机内部处理的是数字信号比如 0、1、寄存器数值、变量值等。但是现实世界中的很多物理量是连续变化的例如电池电压是连续变化的 电流大小是连续变化的 温度变化也是连续的 光照强度、压力、声音、电位器输出也都是连续变化的。单片机不能直接理解这些连续变化的模拟量所以需要 ADC 把模拟电压转换成数字量。简单理解模拟电压 → ADC → 数字值 → MCU程序处理图1 ADC采样基础与工作原理ADC 的本质是把模拟信号转换成离散数字值。单片机程序读取到的不是电压本身而是 ADC 转换后的数字结果。三、ADC读取的到底是什么很多初学者容易误以为ADC 可以直接读取电压、电流、温度。严格来说这个说法并不准确。ADC 真正读取的是输入到 ADC 引脚上的模拟电压。也就是说ADC 不能直接读取电流 ADC 不能直接读取温度 ADC 不能直接读取压力 ADC 不能直接读取光照强度。这些物理量必须先通过传感器或前端电路转换成电压再送入 ADC。例如电压采样通过分压电路把高电压缩小后送入 ADC 电流采样通过采样电阻或霍尔传感器把电流转换成电压 温度采样通过 NTC、LM35 等温度传感器输出电压再送入 ADC。所以可以记住一句话ADC 直接测的是电压其他物理量需要先转换成电压。四、ADC 的基本工作流程ADC 采样一般可以分为几个步骤1. 选择 ADC 通道 2. 启动 ADC 转换 3. 对输入电压进行采样保持 4. ADC 内部完成量化和编码 5. 转换结果存入 ADC 数据寄存器 6. CPU 或 DMA 读取 ADC 结果 7. 程序根据公式换算成实际物理量简化流程如下模拟信号 ↓ 采样保持 ↓ 量化 ↓ 编码 ↓ ADC数据寄存器 ↓ MCU读取 ↓ 软件换算1. 选择通道单片机通常有多个 ADC 输入通道例如ADC_IN0 ADC_IN1 ADC_IN2 ADC_IN3 ...每个通道可以连接不同的外部模拟信号。例如ADC_IN0 接电池电压分压 ADC_IN1 接电流传感器输出 ADC_IN2 接 NTC 温度检测电路。2. 启动转换程序配置好 ADC 后可以通过软件启动转换也可以由定时器触发 ADC 定时采样。常见方式包括软件触发 定时器触发 外部事件触发 连续转换模式 扫描转换模式。3. 采样保持ADC 在转换前会先对输入电压进行短时间采样并保持住这个电压。这个过程叫采样保持如果采样时间太短输入电容还没有充到真实电压ADC 结果可能会偏小或不稳定。4. 量化和编码ADC 会把 0~Vref 范围内的输入电压划分成很多个等级。例如 12 位 ADC2^12 4096 个等级数字输出范围是0 ~ 4095输入电压越接近 VrefADC 数值越大。输入电压越接近 0VADC 数值越小。五、ADC 分辨率是什么意思ADC 分辨率表示 ADC 可以把输入电压划分成多少个离散等级。常见 ADC 分辨率有8位 10位 12位 16位它们对应的数字范围如下ADC 位数等级数量数字输出范围8 位2^8 2560 ~ 25510 位2^10 10240 ~ 102312 位2^12 40960 ~ 409516 位2^16 655360 ~ 65535以 12 位 ADC 为例最小值0 最大值4095 中间值约 2048所以当你看到 ADC 结果为 2048 时不能直接理解为 2048V而应该理解为输入电压大约是参考电压的一半。六、参考电压 Vref 是什么ADC 的参考电压 Vref 决定了 ADC 的满量程范围。可以简单理解为ADC 用 Vref 作为“最大可测电压”的参考。例如Vref 3.3V 12位ADC那么 ADC 输入范围通常是0V ~ 3.3V对应数字范围是0 ~ 4095也就是说输入 0V → ADC 约等于 0 输入 1.65V → ADC 约等于 2048 输入 3.3V → ADC 约等于 4095注意ADC 引脚输入电压不能超过允许范围。如果 ADC 供电或参考电压是 3.3V就不能直接把 5V、12V、24V、60V 等高电压直接接到 ADC 引脚否则可能损坏 MCU。图2 ADC分辨率、参考电压与换算公式ADC 分辨率决定等级数量参考电压决定满量程范围。ADC 结果本质上是输入电压在 0~Vref 范围内对应的数字比例。七、ADC 值和电压怎么换算ADC 最核心的换算公式是ADC值 Vin / Vref × (2^N - 1)其中VinADC输入电压 Vref参考电压 NADC分辨率位数 2^N - 1ADC最大数字值反过来如果已知 ADC 值要计算实际输入电压Vin ADC值 / (2^N - 1) × Vref八、12 位 ADC 换算示例假设ADC分辨率12位 Vref3.3V ADC读取值2048因为 12 位 ADC 的最大值为2^12 - 1 4095所以输入电压为Vin 2048 / 4095 × 3.3计算结果大约是Vin ≈ 1.65V所以ADC 2048大约代表输入电压 1.65V九、为什么 ADC 分辨率越高测量越细ADC 的最小电压分辨能力通常用 LSB 表示。LSB 可以理解为ADC 数值变化 1对应的最小电压变化。计算公式近似为LSB Vref / (2^N - 1)假设 Vref 3.3VADC 位数最大值约等于每 1 个数值代表的电压8 位255约 12.94 mV10 位1023约 3.22 mV12 位4095约 0.806 mV16 位65535约 0.050 mV可以看到位数越高每一级对应的电压越小理论测量越细。但是注意分辨率高不等于一定准确。实际精度还受到参考电压稳定性、噪声、PCB布局、输入电路、采样时间、温漂、校准等因素影响。十、单片机如何读取电压ADC 最常见的应用就是读取电压。如果被测电压本身就在 ADC 输入范围内例如0V ~ 3.3V可以通过简单滤波后接入 ADC。但是如果被测电压高于 ADC 输入范围例如5V 12V 24V 48V 60V就不能直接接入 ADC需要先进行电阻分压。十一、电阻分压采样电压典型分压电路如下Vin | R1 | ---- Vadc → ADC引脚 | R2 | GND输出到 ADC 的电压为Vadc Vin × R2 / (R1 R2)例如要测量一个最高 60V 的电压而 ADC 最大只能输入 3.3V则需要通过 R1、R2 把 60V 缩小到 3.3V 以内。假设R1 180kΩ R2 10kΩ Vin 60V则Vadc 60 × 10 / (180 10) 60 × 10 / 190 ≈ 3.16V这样 60V 输入时ADC 引脚电压约为 3.16V没有超过 3.3V比较安全。程序中再反向换算Vin Vadc × (R1 R2) / R2十二、电压采样注意事项电压采样时要注意1. ADC 输入不能超过允许范围例如 MCU ADC 最大输入为 3.3V则 ADC 引脚电压必须保持在 0~3.3V 范围内。超过范围可能导致ADC读数饱和 结果不准确 MCU引脚损坏 芯片不可逆损坏。2. 分压电阻比例要合理分压比例过小测量分辨率会变差。分压电阻过大ADC 输入阻抗太高采样电容充电慢容易造成读数偏差。3. 输入端可以加 RC 滤波常见做法是在 ADC 输入前加小电阻和电容信号 ---- R ---- ADC | C | GND这样可以抑制高频噪声让 ADC 读数更稳定。十三、单片机如何读取电流ADC 不能直接读取电流。电流采样的核心思想是先把电流转换成电压再让 ADC 读取这个电压。常见方法有两种采样电阻法 霍尔电流传感器法十四、采样电阻法读取电流采样电阻法是在电流路径中串联一个小阻值电阻。电流流过采样电阻时会产生一个电压降。根据欧姆定律Vsense I × Rs其中Vsense采样电阻两端电压 I被测电流 Rs采样电阻阻值例如Rs 0.01Ω I 5A则Vsense 5 × 0.01 0.05V也就是 50mV。这个电压比较小通常需要经过运算放大器放大后再送入 ADC。假设放大倍数为 50 倍Vadc 0.05 × 50 2.5V然后 ADC 读取 2.5V再通过软件反推电流。十五、霍尔电流传感器法霍尔电流传感器可以把电流转换成模拟电压输出。常见特点隔离测量 不用直接串大电流采样电阻 适合较大电流 输出通常为模拟电压。例如某些霍尔电流传感器输出无电流时输出 Vcc/2 正向电流时电压升高 反向电流时电压降低。程序读取 ADC 后需要根据传感器规格书中的灵敏度进行换算。十六、电流采样注意事项电流采样时要注意1. 采样电阻功率采样电阻会发热功率为P I^2 × R例如I 10A R 0.01Ω则P 10^2 × 0.01 1W采样电阻功率必须留足裕量。2. 采样电阻不能随便选太大电阻越大压降越大发热越大也会影响原电路工作。3. 小信号需要放大采样电阻产生的电压可能只有几 mV 到几十 mV直接送入 ADC 分辨率可能不够需要运放放大。4. 地线布局很重要大电流回路和 ADC 小信号地线混在一起会导致采样噪声和误差。十七、单片机如何读取温度ADC 读取温度本质上也是读取电压。温度传感器会把温度变化转换成电压变化。常见方案包括NTC热敏电阻 LM35模拟温度传感器 TMP36等模拟温度传感器 MCU内部温度传感器十八、NTC 热敏电阻采样温度NTC 是负温度系数热敏电阻。它的特点是温度升高电阻变小 温度降低电阻变大。常见电路是 NTC 和普通电阻组成分压电路Vref | R1 | ---- Vadc → ADC | NTC | GND或者Vref | NTC | ---- Vadc → ADC | R1 | GND不同接法下温度升高时 ADC 电压变化方向不同。程序需要先通过 ADC 值算出 Vadc再算出 NTC 电阻值最后通过查表或公式换算成温度。十九、NTC 电阻值计算以一种常见接法为例Vref | R | ---- Vadc | NTC | GND此时Vadc Vref × Rntc / (R Rntc)可以推导出Rntc R × Vadc / (Vref - Vadc)得到 NTC 电阻后可以通过查表或者 B 值公式换算温度。实际项目中查表法更加常见、稳定也方便标定。二十、LM35 等模拟温度传感器有些温度传感器会直接输出与温度成比例的电压。例如 LM35 常见关系为10mV / ℃也就是25℃ 时输出约 250mV 30℃ 时输出约 300mV程序通过 ADC 读取电压后就可以换算温度温度 输出电压 / 10mV这类传感器比 NTC 换算简单但要注意供电范围、输出范围和精度。图3 ADC如何读取电压、电流和温度电压通常通过分压后进入 ADC电流通常先经过采样电阻或霍尔传感器转换成电压温度通常通过 NTC 或模拟温度传感器输出电压后再采样。二十一、ADC 采样模式ADC 常见采样模式包括1. 单次转换模式启动一次 ADC转换一次读取一次结果。适合按需读取电池电压 偶尔检测传感器 低速状态监测。2. 连续转换模式ADC 不断转换程序不断读取结果。适合持续监控电压 持续采集模拟量 简单波形采集。3. 扫描模式ADC 依次采样多个通道。例如通道0电压 通道1电流 通道2温度ADC 会按照配置顺序依次采样。4. ADC DMA 模式当采样数据量较大或者需要连续采样多个通道时常用 DMA 自动搬运 ADC 结果。典型流程ADC转换完成 ↓ DMA自动把ADC结果搬到数组 ↓ 达到一定长度后通知CPU处理这样 CPU 不需要每次都手动读取 ADC 数据寄存器。二十二、ADC 数据为什么会乱跳ADC 读数乱跳是非常常见的问题。原因可能包括1. 输入信号本身有噪声模拟信号可能受到电源纹波、电机干扰、开关电源噪声等影响。2. 参考电压不稳定Vref 如果波动ADC 结果也会跟着波动。因为 ADC 值本质上是Vin / Vref所以 Vref 不稳定会直接影响结果。3. ADC 输入悬空ADC 引脚没有明确电压时会受到外界干扰读数随机变化。4. 采样时间太短ADC 内部采样电容还没有充到稳定电压就开始转换结果会不准。5. 前端阻抗太高分压电阻太大或者信号源驱动能力太弱会导致 ADC 采样电容充电不足。6. PCB 布局不好模拟地和数字地处理不合理大电流回路干扰 ADC 信号会导致采样不稳定。二十三、ADC 常见异常现象和原因1. ADC 一直为 0可能原因ADC引脚接地 通道配置错误 GPIO没有配置为模拟输入 ADC没有启动 没有读取正确的数据寄存器 传感器没有供电 输入信号断开。2. ADC 一直满量程例如 12 位 ADC 一直是4095可能原因输入电压超过 Vref ADC引脚被拉到高电平 分压电阻接错 通道配置错误 参考电压异常。3. ADC 数值偏小可能原因分压比例计算错误 采样时间太短 前端阻抗太大 输入电容充电不足 参考电压设置错误 传感器输出能力不足。4. ADC 数值偏大可能原因分压电阻焊错 Vref 实际值比程序假设值低 输入存在干扰 地线电位不一致 公式换算错误。5. 多通道之间相互影响可能原因前一个通道电压残留 采样时间太短 通道源阻抗过高 没有丢弃第一次采样值 ADC扫描顺序不合理。二十四、ADC 调试方法调试 ADC 时建议不要一上来就看代码而是按下面顺序排查。第一步先看硬件连接确认传感器是否供电 信号线是否接对 GND是否共地 ADC引脚是否正确 输入电压是否超过范围 分压电阻是否焊对。第二步用万用表测 ADC 引脚电压不要只看程序里的 ADC 值。应该直接测量 ADC 引脚实际电压。例如测到ADC引脚电压 1.65V那么 12 位 ADC、Vref3.3V 时ADC 应该约为2048如果程序读到的值差很多就说明软件配置或参考电压设置可能有问题。第三步确认 Vref用万用表测量参考电压。如果程序里按 3.3V 换算但实际 Vref 是 3.25V结果就会存在误差。第四步确认采样时间信号源阻抗较高时应适当增加 ADC 采样时间。第五步多次采样平均对噪声较大的信号可以使用多次采样平均。例如连续采样 16 次然后取平均ADC_avg (adc1 adc2 ... adc16) / 16这样可以降低随机噪声。图4 ADC调试技巧与常见问题排查ADC 调试时要同时检查硬件连接、参考电压、原始 ADC 值、换算公式和软件滤波。读数不准不一定是代码问题很多时候是前端电路和参考电压问题。二十五、软件滤波方法ADC 采样常见软件滤波方式有1. 多次平均滤波连续采样多次取平均值。优点简单 容易实现 适合随机噪声。示例uint16_tADC_GetAverage(uint8_ttimes){uint32_tsum0;for(uint8_ti0;itimes;i){sumADC_ReadRaw();}returnsum/times;}2. 中值滤波采样多次后排序取中间值。适合去除偶发尖峰干扰。3. 滑动平均滤波保存最近 N 次采样结果每次更新平均值。适合连续平滑显示。4. 一阶低通滤波公式为filtered filtered × a new_value × (1 - a)其中a越大输出越平滑但响应越慢。二十六、STM32 HAL ADC 单次采样示例下面代码仅用于理解流程不同芯片和工程配置可能不同。uint16_tADC_ReadRaw(void){HAL_ADC_Start(hadc1);HAL_ADC_PollForConversion(hadc1,10);uint16_tvalueHAL_ADC_GetValue(hadc1);HAL_ADC_Stop(hadc1);returnvalue;}这段代码的流程是启动 ADC 等待转换完成 读取 ADC 数据寄存器 停止 ADC 返回原始 ADC 值。二十七、ADC 值换算成电压示例假设12位ADC Vref 3.3V代码可以这样写floatADC_ToVoltage(uint16_tadc_value){return(float)adc_value*3.3f/4095.0f;}使用示例uint16_tadc_rawADC_ReadRaw();floatvoltageADC_ToVoltage(adc_raw);如果adc_raw 2048则voltage大约为1.65V二十八、分压电路测量高电压代码示例假设分压电阻为R1 180kΩ R2 10kΩADC 引脚测得电压为Vadc实际输入电压为Vin Vadc × (R1 R2) / R2代码示例floatADC_ReadInputVoltage(uint16_tadc_value){floatvref3.3f;floatr1180000.0f;floatr210000.0f;floatvadc(float)adc_value*vref/4095.0f;floatvinvadc*(r1r2)/r2;returnvin;}二十九、电流采样代码示例假设采样电阻 Rs 0.01Ω 运放放大倍数 Gain 50 Vref 3.3V 12位ADC电流计算Vadc ADC值 / 4095 × 3.3 Vsense Vadc / Gain I Vsense / Rs代码示例floatADC_ReadCurrent(uint16_tadc_value){floatvref3.3f;floatrs0.01f;floatgain50.0f;floatvadc(float)adc_value*vref/4095.0f;floatvsensevadc/gain;floatcurrentvsense/rs;returncurrent;}三十、NTC 温度采样代码示例假设 NTC 和固定电阻分压Vref | R_fixed | ---- ADC | NTC | GND则Rntc R_fixed × Vadc / (Vref - Vadc)代码示例floatADC_ReadNTCResistance(uint16_tadc_value){floatvref3.3f;floatr_fixed10000.0f;floatvadc(float)adc_value*vref/4095.0f;if(vadc0.0f||vadcvref){return-1.0f;}floatr_ntcr_fixed*vadc/(vref-vadc);returnr_ntc;}得到 NTC 电阻后可以通过查表或 B 值公式换算成温度。实际工程中推荐使用查表法ADC值/电阻值 → 查表 → 温度值这样更方便做标定和误差修正。三十一、ADC 工程实践建议1. 不要让 ADC 输入超过芯片允许范围这是最重要的安全原则。例如 ADC 最大输入为 3.3V就必须保证输入电压在 0~3.3V 之间。2. 分压电路要留裕量不要让最大输入刚好等于 ADC 满量程。例如 ADC 满量程为 3.3V建议最大输入时分压到3.0V 左右留出一定安全裕量。3. 采样前先用万用表确认电压调试 ADC 时先测 ADC 引脚真实电压再看程序读取值。4. 多通道采样时适当延长采样时间不同通道之间电压差较大时采样时间太短容易串扰。5. 稳定参考电压很重要ADC 的结果依赖 Vref。参考电压不稳定ADC 结果就不稳定。6. 合理使用滤波硬件上可以加 RC 滤波软件上可以做平均滤波、中值滤波或低通滤波。7. 注意共地被测信号和单片机 ADC 必须有共同参考地否则测量结果可能完全错误。图5 ADC实战电压、电流、温度怎么接实际项目中ADC 通常不会直接接复杂信号而是通过分压、采样电阻、运放、传感器和滤波电路进行调理后再送入 ADC 引脚。三十二、ADC 学习重点总结学习 ADC可以先记住下面这些结论ADC 是模数转换器。ADC 的作用是把模拟电压转换成数字量。ADC 读取的不是物理量本身而是输入引脚上的电压。电压、电流、温度都需要先转换成 ADC 可读取的电压。ADC 分辨率决定数字等级数量。12 位 ADC 的输出范围是 0~4095。参考电压 Vref 决定 ADC 满量程范围。ADC 值和电压之间是比例关系。公式为Vin ADC值 / (2^N - 1) × Vref。高电压不能直接接 ADC必须分压。电流不能直接进 ADC必须先通过采样电阻或传感器转换成电压。温度通常通过 NTC 或模拟温度传感器转换成电压。ADC 读数乱跳可能是噪声、Vref不稳、输入悬空、采样时间不足或地线干扰。ADC 一直满量程要重点检查输入是否超过范围。ADC 一直为 0要重点检查通道、接线、供电和输入信号。调试 ADC 时先测 ADC 引脚真实电压再看程序读取值。软件滤波可以提高稳定性但不能解决硬件接错问题。工程中 ADC 采样要结合硬件调理、稳定参考、正确换算和软件滤波一起考虑。三十三、结语ADC 是单片机读取现实世界模拟信号的重要桥梁。可以用一句话总结ADC 不是直接读取电压、电流和温度的最终含义 而是先读取一个与这些物理量相关的模拟电压 再通过公式、查表或标定把数字值换算成实际物理量。真正掌握 ADC需要把下面几个概念串起来输入电压 参考电压 分辨率 ADC数字值 前端调理电路 软件换算 滤波和校准在实际项目中ADC 采样是否准确不只取决于代码也取决于电路设计、参考电压、PCB布局、采样时间和软件处理方法。所以调试 ADC 时不能只看程序还要结合万用表、示波器、电路原理图和实际波形一起分析。