先明确本篇交付的是可执行的测量方法
本篇保留计划ID P05与原slug,把题目明确为ADC三点测量方法。没有开发板与万用表的实际记录,就不能编一组“误差只有几毫伏”的结果。下载中提供采样器和空白measurements.csv,完成后你能对自己的板在明确条件下做比较。
我们只测由本板3V3经电阻与电位器产生的低电压,使用GPIO1的ADC1_CH0。芯片、衰减、输入范围和参考仪表都影响结果;“GPIO逻辑供电是3.3V”并不推出“ADC满量程正好是3.3V”。
- 做到这里,你应该看到
- 知道本篇没有本站测量结果,并明确要记录板型、输入点、参考表计与误差定义。
参考:[1] Arduino-ESP32 3.3.12:ADC返回值、分辨率、S3衰减范围[3] 乐鑫:ESP32-S3-DevKitC-1 v1.1,排针与RGB修订
搭一个最大输入留余量的电位器电路
器材为10kΩ线性电位器、2.2kΩ电阻、100nF陶瓷电容和有量程/精度说明的万用表。3V3先经过2.2kΩ接电位器一端,电位器另一端接GND,滑动端接GPIO1(J3-4),100nF跨GPIO1和GND。表计直流电压挡并联在同一输入节点,红GPIO1、黑GND。
顶端名义电压约3.3×10/(10+2.2)=2.70V,低于S3在ADC_11db下文档给出的约3.1V可测上界。这个计算是设计估算,电阻误差、3V3实际值与接触都要考虑;连接ADC前先量滑端全程范围。不要将本电路直接接电池或5V外部信号。
这里使用分立元件而非未知模拟模块:电位器标称10kΩ、线性、总阻值误差不超过20%、额定功率至少0.1W、允许工作电压至少3.3V;串联电阻2.2kΩ、±5%、0.25W;电容100nF、耐压至少10V。购买时核对器件标注/厂家额定值,断电测总阻与滑动端后再连接。标称值不同就重新计算并实际测量输入范围,不能把2.70V当成保护钳位。
| 节点 | 连接 | 目的 |
|---|---|---|
| 3V3 | 2.2kΩ→电位器端点A | 压低名义输入上限 |
| 电位器端点B | GND | 固定下端参考 |
| 滑端 | GPIO1(J3-4) | ADC1_CH0采样 |
| 100nF | GPIO1与GND之间 | 减小输入高频扰动 |
| 万用表 | 红GPIO1、黑GND | 同节点参考读数 |
参考:[1] Arduino-ESP32 3.3.12:ADC返回值、分辨率、S3衰减范围[3] 乐鑫:ESP32-S3-DevKitC-1 v1.1,排针与RGB修订
raw、毫伏和校准分别回答不同问题
analogReadResolution(12)使返回码按12位表达,raw范围0–4095。raw是原始转换码,不能用raw/4095×3300当作可靠电压公式。analogReadMilliVolts通过core中的校准路径给出毫伏值,但仍会受输入和硬件误差影响,不是外部精密电压表。
本例先调用analogRead再调用analogReadMilliVolts,所以同一行的raw与mV不是同一个瞬间、同一次转换的两个表示。电位器固定在稳定输入,才适合比较各窗口均值;快速变化信号需要另行设计同步采样与带宽。
每20毫秒取一组,32组形成一窗,输出raw均值/最小/最大与mV均值。平均能观察随机波动,不能修复接地错误、饱和或系统偏差;raw min/max的跨度也不是准确度。
参考:[1] Arduino-ESP32 3.3.12:ADC返回值、分辨率、S3衰减范围[2] Arduino-ESP32 3.3.12:ADC采样与校准实现
完整采样器与CSV输出
程序只用core内置ADC接口,没有第三方库。配置12位与ADC_11db后开始输出,约每0.64秒一窗,实际周期受循环与串口影响。它没有把任何预期读数写死,也没有在代码里加入未经验证的经验校正常数。
// SPDX-License-Identifier: MIT
#include <Arduino.h>
constexpr uint8_t ADC_PIN = 1;
constexpr uint16_t WINDOW = 32;
uint16_t count = 0, minRaw = 4095, maxRaw = 0;
uint32_t rawSum = 0, mvSum = 0, sampledAt = 0, windowId = 0;
void setup() {
Serial.begin(115200);
analogReadResolution(12);
analogSetPinAttenuation(ADC_PIN, ADC_11db);
Serial.println("P05 core=3.3.12 GPIO1 ADC1_CH0 12bit 11dB");
Serial.println("window,raw_mean,raw_min,raw_max,mV_mean");
}
void loop() {
const uint32_t now = millis();
if (uint32_t(now - sampledAt) < 20) return;
sampledAt = now;
// Separate conversions: do not treat raw and mV as the same instant/sample.
const uint16_t raw = analogRead(ADC_PIN);
const uint32_t mv = analogReadMilliVolts(ADC_PIN);
rawSum += raw;
mvSum += mv;
if (raw < minRaw) minRaw = raw;
if (raw > maxRaw) maxRaw = raw;
if (++count == WINDOW) {
Serial.printf("%lu,%.2f,%u,%u,%.2f\n", (unsigned long)++windowId,
rawSum / float(WINDOW), minRaw, maxRaw, mvSum / float(WINDOW));
count = 0; rawSum = mvSum = 0; minRaw = 4095; maxRaw = 0;
}
}
参考:[1] Arduino-ESP32 3.3.12:ADC返回值、分辨率、S3衰减范围[2] Arduino-ESP32 3.3.12:ADC采样与校准实现[4] Arduino:millis()返回类型与回绕
用三个输入点和每点十窗完成比较
先记录DMM型号、量程、精度声明、开发板模组后缀、core版本、USB供电与环境。若表计精度来源不明,只能称为“与这台表比较”,不能声称可溯源校准。本文未提供实测数据,下载CSV仅有列名。
- 先将滑端调到表计约500mV,等待2秒稳定;记录表计实际值,不把500作为输入真值。
- 保留连续10个window的mV_mean、raw_mean、raw_min和raw_max;记下采样期间表计是否漂移。
- 同样采集约1500mV和2500mV两个输入点各10窗;每次调节后重新等待稳定。
- 对每点算10个mV_mean的均值和标准差,与同期DMM读数比较。差值Δ=Vadc−Vdmm,绝对差=|Δ|,相对差=Δ/Vdmm×100%。
- 先由项目需求定义允许差值,例如把±50mV作为一个拟定要求;这个数不是芯片保证或本站测量结论。不满足时先排输入稳定性、接地、衰减与参考表计,再考虑校正。
- 若拟合校正系数,另取未参与拟合的点验证;只对原三个点回算不能证明全量程精度。
| 记录列 | 必须填入的内容 |
|---|---|
| point/window | 真实点位与窗口号 |
| dmm_model/range/accuracy | 型号、量程、精度来源 |
| dmm_mV/adc_mV_mean | 同时段真实读数 |
| raw_mean/min/max | 程序输出 |
| supply_V/temperature_C/notes | 测量条件与异常 |
- 做到这里,你应该看到
- 三点各十窗有真实记录、仪表信息和计算过程后,才能报告这块板在这些条件下的比较差值。
读数顶格、漂移和校准异常怎样处理
raw一直4095或接近上边界:先停止调高输入,量GPIO1对GND,检查是否误接3V3直通、滑端识别错误或衰减没设置。raw一直0时先量节点是否真的有电压,再查GPIO号与共地。不要用软件缩放掩盖饱和。
读数漂移先检查供电与导线接触,断电确认100nF和共地,固定旋钮后再采样。若raw有效但mV持续异常,保留启动与core错误日志,核对3.3.12的校准路径;不能擅自把异常值解释为有效0V。
断电恢复默认电阻/电位器电路,删除任何临时校正常数后复测。下一步学习I2C,让传感器自己给出数字数据;数字接口仍然要处理供电、地址与错误状态。
参考:[1] Arduino-ESP32 3.3.12:ADC返回值、分辨率、S3衰减范围[2] Arduino-ESP32 3.3.12:ADC采样与校准实现
资料来源与版本说明
资料与固定版本源码核对;构建、仿真与实板为分开的验证维度。资料核对日期:。资料核对、程序构建与实板测试分别记录,不互相替代。