ESP32-S3 读取ADC通道
ESP32-S3 读取ADC
ESP32-S3 的 ADC(模数转换器)核心原理是将连续变化的模拟电压,转换为离散的数字值,供数字系统(如CPU)处理。其内部采用了逐次逼近型(SAR) 架构,在转换速度和精度之间取得了良好平衡。
提醒:进入博主 牛瘪汤 主页了解更多。
文章目录
1. ADC 转换介绍
ESP32-S3 的 ADC(模数转换器)核心原理是将连续变化的模拟电压,转换为离散的数字值,供数字系统(如CPU)处理。其内部采用了逐次逼近型(SAR) 架构,在转换速度和精度之间取得了良好平衡。
ESP32-S3 的 ADC集成了2个12位SAR ADC (ADC1, ADC2),共20个通道。ADC将输入的模拟电压(0~参考电压/衰减电压)量化为数字值。默认12位分辨率对应0~4095的数值范围。分辨率(9~12位可调)、采样率(最高2.5 MS/s)、输入范围(通过衰减器可扩展至0~3.3V左右)。
⚙️ ADC转换的核心原理
ADC转换的核心是将模拟电压量化为数字。在ESP32-S3上,这个过程主要遵循以下步骤:
-
采样与量化:ADC在每个采样周期内,对输入引脚的模拟电压进行测量。默认情况下,它使用12位分辨率,这意味着它会将测量范围精细地划分为 4096 (2¹²) 个离散的电压等级。因此,读取到的原始值(通常称为
raw_data)就在 0 到 4095 之间。 -
数字值到电压的换算:读取到的原始值本身只是一个数字,要将其转换为实际的电压值,需要参考一个关键参数——参考电压(( V_{ref} ))。在ESP32-S3的设计中,内部参考电压 ( V_{ref} ) 被设定为 1100 mV (1.1V) 。在不使用衰减的情况下,转换公式如下:
[ V_{data} = \frac{data}{2^{bitwidth} - 1} \times V_{ref} ]
举例来说,如果你使用12位分辨率,读取到的原始值是2048,那么对应的电压大约是 ( 2048 / 4095 \times 1100 \text{ mV} \approx 550 \text{ mV} )。
重要说明:由于芯片制造过程中的微小差异,每颗ESP32-S3的实际 ( V_{ref} ) 值可能在1000 mV到1200 mV之间浮动。这正是官方驱动提供校准功能的原因,通过校准可以获得更精确的电压读数。
🔧 关键机制详解
为了让ADC适应不同的应用场景,ESP32-S3引入了几个关键机制。
1. 衰减(Attenuation):扩展测量范围
从上面的原理我们知道,如果不做任何处理,ADC的最大测量范围就是0~1.1V。为了能测量更高的电压(比如常见的3.3V传感器信号),就必须使用衰减器。衰减器本质上是在ADC内部对输入信号进行按比例缩减,让高电压也能落在ADC的测量范围内。
ESP32-S3提供了四种衰减级别,对应的测量范围如下表所示:
| 衰减设置 | 可测量电压范围(近似) | 适用场景 |
|---|---|---|
| 0 dB | 0 ~ 1.1 V | 测量1.1V以下的信号,精度最高 |
| 2.5 dB | 0 ~ 1.5 V | 测量1.5V以下的信号 |
| 6 dB | 0 ~ 2.2 V | 测量2.2V以下的信号 |
| 11 dB | 0 ~ 3.3 V | 测量3.3V以下的信号(最常用) |
注意:虽然11dB衰减支持到3.3V,但实际应用中,为了留出余量和保证线性度,官方文档建议将可靠测量的上限视为约3.1V左右。绝对不要输入超过3.3V的电压,否则可能损坏芯片。
2. 两种工作模式:单次与连续
根据你的应用需求,可以选择不同的驱动模式:
- 单次模式(Oneshot Mode):适用于一次性或低频采样。比如,每秒钟读取一次温度传感器的值。这种模式下,每次转换都由CPU发起,转换完成后读取结果。
- 连续模式(Continuous Mode):适用于高频、连续的数据采集,比如音频采样或振动分析。此模式会利用DMA(直接内存访问) 技术,将ADC转换结果自动写入内存,无需CPU频繁干预,极大提高了数据吞吐量和效率。
3. 校准(Calibration):获得精确电压
如前所述,由于制造差异,直接用公式计算电压可能会有误差。ESP-IDF(乐鑫的物联网开发框架)提供了ADC校准驱动。它会读取芯片出厂时烧录在eFuse(一种存储器)中的特征值,通过软件算法自动修正原始读数,从而输出更准确的电压值(单位可以是mV或μV)。在要求稍高的场景,建议都使用校准功能。
2. 读取 ADC 电压
Arduino环境提供了非常简便的API,analogReadMilliVolts() 函数更是直接帮你完成了校准,返回毫伏单位的电压值,非常推荐。
// Arduino 示例
const int adcPin = 7; // 使用GPIO7,它对应ADC1的通道
void setup() {
Serial.begin(115200);
// 在Arduino中,analogRead默认已配置为12位和11dB衰减,
analogReadResolution(adcPin);
}
void loop() {
int adcValue = analogRead(adcPin); // 读取原始值 (0-4095)
int voltage_mV = analogReadMilliVolts(adcPin); // 读取校准后的电压值 (mV)
Serial.print("ADC Raw: ");
Serial.print(adcValue);
Serial.print(", Voltage: ");
Serial.print(voltage_mV);
Serial.println(" mV");
delay(500);
}
analogRead(pin):最简单的读取方式,返回0-4095的原始值 。
analogReadMilliVolts(pin):ESP32的增强函数,可以直接返回校准后的毫伏电压值,推荐使用 。
analogSetAttenuation(attenuation):用于设置全局的衰减值 。
3. 读取多组 ADC 电压
确保ESP32-S3开发板已连接Arduino IDE。多通道ADC读取需要明确每个通道对应的GPIO引脚。ESP32-S3的ADC1和ADC2支持多路复用,但需注意部分引脚可能受限制。
// 定义ADC通道对应的GPIO引脚
const int adcPins[] = {1, 2, 3, 4}; // 示例引脚,根据实际硬件调整
const int numChannels = sizeof(adcPins) / sizeof(adcPins[0]);
// 使用滑动平均滤波
const int samples = 5;
int adcReadWithFilter(int pin) {
int sum = 0;
for (int i = 0; i < samples; i++) {
sum += analogRead(pin);
delay(2);
}
return sum / samples;
}
void setup() {
Serial.begin(115200);
analogReadResolution(12);
// 可选:设置衰减器(根据输入电压范围)
analogSetAttenuation(ADC_11db); // ADC_0db, ADC_2_5db, ADC_6db, ADC_11db
}
void loop() {
for (int i = 0; i < numChannels; i++) {
int filteredValue = adcReadWithFilter(adcPins[i]);
Serial.printf("Channel %d: %d\n", adcPins[i], filteredValue);
}
delay(200);
}
4. 触摸按键
ESP32-S3的ADC触摸功能通过内置的触摸传感器通道实现,需调用touchRead()函数读取原始电容值。ESP32-S3支持多个触摸通道(TOUCH0-TOUCH14),无触摸时,数值较高(通常>50,具体与环境电容相关);触摸时:数值显著下降(可能<30);阈值需通过实验校准,不同硬件布局会影响基准值。
触摸按键硬件设计。无需外部电路,直接触碰GPIO焊盘或连接的金属部分即可。若需稳定检测,可增加导电面积(如铜箔)。
#include <Arduino.h>
// 定义触摸传感器引脚(根据ESP32-S3开发板手册选择)
#define TOUCH_PIN 4 // 示例:GPIO4作为触摸输入
// 添加滤波和去抖
#define SAMPLES 5
int getFilteredTouchValue(int pin) {
int sum = 0;
for (int i = 0; i < SAMPLES; i++) {
sum += touchRead(pin);
delay(2);
}
return sum / SAMPLES;
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("ESP32-S3 Touch Sensor Test");
}
void loop() {
int touchValue = touchRead(TOUCH_PIN); // 读取原始电容值
int filteredValue = getFilteredTouchValue(TOUCH_PIN);
Serial.printf("Touch Value: %d\n", touchValue);
Serial.printf("Touch Filter Value: %d\n", filteredValue );
// 判断触摸阈值(需根据实际环境调整)
if (touchValue < 20) { // 值越小表示触摸越强
Serial.println("Touched!");
}
delay(200);
}
💡 提高ADC读数准确性的实用技巧
在实际应用中,你可能会发现ADC读数会有些跳动,这是由噪声引起的。可以尝试以下方法改善:
- 硬件滤波:在ADC输入引脚和GND之间并联一个0.1uF(100nF)的小电容,可以有效滤除高频噪声。
- 软件滤波:在代码中对同一通道进行多次采样,然后取平均值。这是最简单有效的软件滤波方法。
结语
文章都看到完了,就不点个关注吗,老铁!
欢迎关注博主–牛瘪汤 。
更多推荐
所有评论(0)