跳到主要内容

模拟输入

1. 模拟信号

模拟信号是一种在一定范围内可以连续变化的信号。

比如调光灯旋钮,可以平滑地调节灯的亮度,从完全熄灭到最亮,中间有无数个亮度级别。这个亮度调节的过程就是模拟的。而数字信号就像普通电灯开关,只有“开”和“关”。

现实世界中,像温度、光线强度、声音大小等许多物理量都是模拟的,它们的变化是连续而平滑的。

对于 ESP32,若要测量连续变化的信号(例如读取电位器、传感器的数值),仅用 HIGHLOW 两种数字状态是无法实现的。此时,就需要使用 ADC

  • ADC(Analog-to-Digital Converter, 模数转换器):一种能将连续的模拟电压信号(例如 0V ~ 3.3V)转换为 ESP32 可处理的数字值的设备。

    ADC

简单来说,ADC 就像一把将 0~3.3V 之间的电压切分成很多“刻度”的尺子,让每个电压范围都对应一个具体的数字。ADC 能将电压细分成多少个等级,这个能力就叫做分辨率。分辨率越高,能检测的电压变化就越细致。

ESP32 的 ADC 通常是 12 位的,也就是一共可以分成 2¹²(= 4096) 个等级。因此,ADC 的读数范围是 0 ~ 4095

  • 输入电压为 0V,ADC 读数约等于 0
  • 当输入电压从 0V 连续变化到 3.3V 时,ADC 读数会相应地从 0 连续变化到 4095
ADC

这样,ESP32 程序就可以通过 analogRead() 得到 0~4095 之间的整数,这个数值直接对应了输入引脚上的电压大小。

提示

并不是所有 ESP32 引脚都支持模拟输入。需要查询对应开发板的引脚图或者芯片的手册,查找标有“ADC”的引脚作为模拟输入使用。
建议优先选择 ADC1 通道的引脚,以避免与其他功能冲突。

2. 搭建电路

需要使用的器件有:

  • 电位器 * 1
  • 面包板 * 1
  • 导线
  • ESP32 开发板
ESP32-S3-Zero 引脚图

ESP32-S3-Zero-Pinout

接线图

电路解析

让我们理解一下这个模拟信号读取电路是如何工作的:

  1. 电位器的连接:

    • VCC 引脚:连接到 ESP32 的 3.3V,提供电位器工作电压
    • GND 引脚:连接到 ESP32 的 GND,形成电路回路
    • 信号引脚(中间):连接到 ESP32 的 GPIO7(ADC 引脚),输出 0V~3.3V 之间的模拟电压
  2. 电位器工作原理:

    • 电位器内部是一个可变电阻,通过旋转可以改变阻值
    • 旋转电位器旋钮时,信号引脚的输出电压会在 0V 到 3.3V 之间连续变化
    • 完全逆时针:输出接近 0V
    • 完全顺时针:输出接近 3.3V

3. 代码

const int potentiometerPin = 7;  // 定义电位器连接的引脚

void setup() {
Serial.begin(9600); // 初始化串口通信,波特率 9600
}

void loop() {
int analogValue = analogRead(potentiometerPin); // 读取电位器模拟值 (0-4095)
int analogVolts = analogReadMilliVolts(potentiometerPin); // 读取引脚上的电压值,单位是毫伏 (mV)

// 打印第一个标签和数值
Serial.print("ADC_Value:");
Serial.print(analogValue);

// 打印分隔符
Serial.print(",");

// 打印第二个标签和数值,并用 println() 结束
Serial.print("Voltage_mV:");
Serial.println(analogVolts);

delay(100); // 延时 0.1 秒,避免串口刷屏太快
}

运行结果:

将代码烧录到 ESP32 开发板后,打开串口监视器即可看到持续显示的数值。转动电位器时,数值会相应变化:电位器转到一端时数值为 0,转到另一端时数值为 4095。

  • 串口监视器:

    运行结果 - 串口监视器
  • 串口绘图仪:

    运行结果 - 串口绘图仪
深入一点:为什么最大读数不正好对应 3.3V?

你可能会发现,当输入电压达到约 3.1V 时,analogRead() 的读数就已经达到 4095,而不是在 3.3V 时。

这是 ESP32 ADC 的一个设计特性。其内部核心电路能直接处理的电压范围有限,因此它使用了一个名为衰减器 (Attenuator) 的内部模块来扩展可测量的电压范围。

在 Arduino 环境下,默认会启用一个能测量最高电压的衰减选项 (ADC_ATTEN_DB_11)。根据官方文档,此设置下 ESP32 S3 ADC 可靠测量上限约为 3.1V。(注意:不同芯片在不同的衰减选项下,可测量的输入电压范围是不同的。查看 此表。)

因此,当输入电压超过 3.1V 时,读数就会“饱和”,即保持在最大值 4095。

对于读取 0%到 100%的应用,这个默认设置足够。如果需要优化特定电压范围精度,可以学习如何设置不同衰减等级。详情请参阅 官方文档中关于 analogSetAttenuation 的说明

代码解析

  1. analogRead(potentiometerPin)

    读取指定引脚上的模拟电压值。返回 0 ~ 4095 之间的整数,代表当前滑动端电压在 0V ~ 3.3V 这个范围内的位置。

    备注

    在调用 analogRead() 前,不需要使用 pinMode() 定义引脚。

  2. analogReadMilliVolts(potentiometerPin)

    这是一个 ESP32 特有函数。它同样读取指定引脚的模拟信号,但直接将其转换为以毫伏(mV)为单位的电压值并返回。并且其内部实现还包含校准,让读数更准确。

  3. 串口输出与绘图仪格式

      // 打印第一个标签和数值
    Serial.print("ADC_Value:");
    Serial.print(analogValue);

    // 打印分隔符
    Serial.print(",");

    // 打印第二个标签和数值,并用 println() 结束
    Serial.print("Voltage_mV:");
    Serial.println(analogVolts);

    这段代码用于按照特定格式通过串口发送采集到的数据。这种格式 不仅方便在串口监视器中阅读,更重要的是能被 Arduino IDE 的串口绘图仪识别并绘制成曲线图。

    让我们对照下图来解析这个格式的构成:

    串口绘图仪 - 格式

    • 标签和数值: 每个数据由标签和数值组成,并用冒号 (:) 分隔。这有助于在绘图仪的图例中显示名称。

    • 数据分隔符: 多个数据之间用数据分隔符(如逗号 , 、空格 或制表符 \t)隔开。这是告诉绘图仪“一个数据结束,下一个开始”的关键信号。

    • 换行符: 使用 Serial.println() 在所有数据输出后添加换行符。这个换行符是“记录结束”的标志,告诉绘图仪这一时间点的所有数据已发送完毕,可以进行绘制了。

    最终,串口监视器中每行会显示类似 ADC_Value:2048,Voltage_mV:1650 的格式。在串口绘图仪中,你会看到两条分别代表 ADC 原始值和电压值的曲线。

4. 拓展:减少噪声

当你停止转动电位器时,你可能会发现,ADC 读数并不会稳定地停留在某一个值,而是在小范围内持续跳动,有时甚至会出现较大的毛刺。

ADC 噪声

这种现象通常是由噪声引起的。ESP32 的 ADC 对电源噪声和外部环境的电磁干扰比较敏感。

要减少噪声的影响,通常有两种方法:

  • 硬件滤波:在 ADC 输入引脚和 GND 之间并联一个小的旁路电容(例如 100nF 的陶瓷电容),可以有效滤除高频噪声。

  • 软件滤波:在代码中进行多次采样后取平均值。例如,连续读取 10 次 ADC 值,然后将它们的总和除以 10,得到一个更平滑、更稳定的结果。

在大多数要求不高的应用中,轻微的跳动可以忽略。但当你需要高精度读数时,可以尝试使用上述方法。

5. 相关链接