Độ phân giải ADC, ENOB và nhiễu: ADC 12 bit của ESP32 dùng được bao nhiêu bit, khi nào đủ
Độ phân giải ADC và LSB, nhiễu, số bit hiệu dụng ENOB và bit không nhiễu, ADC 12 bit ESP32 thực tế dùng được bao nhiêu bit, lấy trung bình tăng bit, khi nào cần ADS1115, HX711; có code đo nhiễu.
Độ phân giải ADC (số bit) cho biết bộ chuyển đổi chia dải đo thành bao nhiêu mức, nhưng không cho biết bao nhiêu bit thật sự dùng được: nhiễu, sai số tuyến tính, điện áp tham chiếu lấy mất một phần. Bài này giải thích LSB, độ phân giải, số bit hiệu dụng (ENOB), bit không nhiễu, vì sao ADC 12 bit của ESP32 thường chỉ dùng được khoảng 9–10 bit khi đọc từng mẫu, cách tăng bit bằng lấy trung bình, khi nào cần ADC ngoài, kèm chương trình ESP32 tự đo nhiễu ADC trên mạch của bạn.
1. Độ phân giải và LSB

ADC N bit chia dải đo thành 2N mức. Một bước nhỏ nhất (LSB, bit có trọng số thấp nhất) bằng dải đo chia 2N: ADC 12 bit với dải 3,3 V có LSB khoảng 0,8 mV. Đây là độ phân giải, tức bước nhỏ nhất ADC có thể báo; độ chính xác (số đọc gần giá trị thật bao nhiêu) là chuyện khác, phụ thuộc điện áp tham chiếu, sai số độ lợi, sai số lệch không và độ phi tuyến.
2. Nhiễu: vì sao số đọc nhảy khi điện áp đứng yên

Nhiễu đến từ chính bộ ADC, nguồn cấp, mạch số chạy bên cạnh (Wi-Fi, CPU), dây tín hiệu dài. Kết quả là số đọc của một điện áp không đổi vẫn trải ra một khoảng. Đo độ rộng đó bằng độ lệch chuẩn σ tính theo LSB, rồi suy ra:
- Số bit hiệu dụng (effective resolution) = log2(2N / σ): bao nhiêu bit còn lại khi tính nhiễu theo giá trị hiệu dụng.
- Số bit không nhiễu (noise-free) = log2(2N / (6,6 σ)): bao nhiêu bit hiện ổn định trên màn hình, không nhảy, vì hầu hết số đọc nằm trong khoảng ±3,3 σ.
Datasheet ADC còn dùng ENOB (Effective Number Of Bits) tính từ tỉ số tín hiệu trên nhiễu và méo khi đo sóng sin: ENOB = (SINAD − 1,76 dB) / 6,02. Ý nghĩa giống nhau: số bit của một ADC lý tưởng có cùng mức nhiễu.
3. ADC của ESP32 thực tế dùng được bao nhiêu bit
ADC SAR 12 bit trong ESP32 (dòng chip gốc) khá nhiễu, độ lệch chuẩn vài LSB tùy mạch, nên đọc từng mẫu thường chỉ còn khoảng 9–10 bit hiệu dụng, và số bit không nhiễu còn ít hơn. Ngoài nhiễu, ADC ESP32 còn phi tuyến ở hai đầu dải đo (gần 0 V và gần 3,1 V ở mức suy giảm 11 dB). Dùng analogReadMilliVolts() để thư viện áp hiệu chuẩn có sẵn trong chip, và giữ điện áp đo ở khoảng giữa dải. Cách đọc ADC, chọn cầu chia áp có ở bài đọc ADC trên ESP32 và đo điện áp pin 18650.
4. Lấy trung bình để tăng số bit dùng được

Nếu nhiễu ngẫu nhiên, trung bình M mẫu giảm độ lệch chuẩn đi √M lần: 4 mẫu giảm một nửa (thêm 1 bit), 16 mẫu thêm 2 bit, 64 mẫu thêm 3 bit. Đổi lại, tốc độ lấy mẫu giảm M lần. Giới hạn:
- Lấy trung bình không sửa được sai số hệ thống: phi tuyến, sai độ lợi, điện áp tham chiếu lệch vẫn còn nguyên.
- Nhiễu có chu kỳ (từ nguồn xung, PWM, điện lưới) không giảm theo √M nếu thời gian lấy mẫu trùng nhịp với nhiễu; lọc chống chồng phổ trước ADC vẫn cần. Phần này có ở bài aliasing và bộ lọc chống chồng phổ cùng cụm chủ đề.
- Tụ 100 nF từ chân ADC xuống GND đặt sát chip giảm nhiễu đáng kể với nguồn tín hiệu trở kháng cao như cầu chia áp.
5. ADC 12 bit có đủ không

Cách tính nhanh: lấy dải đo chia cho thay đổi nhỏ nhất cần phân biệt, rồi lấy log2. Ví dụ đo 0–3,3 V cần phân biệt 5 mV: 3300 / 5 = 660 mức, khoảng 9,4 bit, ADC ESP32 đủ nếu lấy trung bình vài mẫu. Đo tín hiệu vài µV của load cell thì cần HX711 24 bit; đo điện áp chính xác hơn, vi sai, có khuếch đại thì dùng ADS1115 16 bit.
6. Chương trình ESP32 đo nhiễu ADC trên mạch của bạn
Nối GPIO34 vào điểm giữa cầu chia hai điện trở 10 kΩ từ 3V3 xuống GND, thêm tụ 100 nF từ GPIO34 xuống GND. Chương trình đọc 256 giá trị ở mỗi mức lấy trung bình 1, 4, 16, 64 mẫu, tính độ lệch chuẩn, khoảng min–max, số bit hiệu dụng, số bit không nhiễu theo công thức ở mục 2. Chỉ dùng gói esp32 cho Arduino IDE.
// PYWORLD.VN - Đo nhiễu ADC của ESP32 trên một điện áp đứng yên: độ lệch chuẩn (LSB), số bit hiệu dụng, số bit không nhiễu
// PYWORLD.VN - So sánh khi lấy trung bình 1, 4, 16, 64 mẫu; GPIO34 nối điểm giữa cầu chia 10k/10k từ 3V3, thêm tụ 100 nF xuống GND
// PYWORLD.VN - Bit hiệu dụng = log2(4096 / độ lệch chuẩn); bit không nhiễu = log2(4096 / (6,6 x độ lệch chuẩn))
#include <math.h>
const int CHAN_ADC = 34;
const int SO_DIEM = 256; // số giá trị (đã lấy trung bình) dùng để tính thống kê
const int CAC_MUC_TB[] = {1, 4, 16, 64};
const float THANG = 4096.0f; // ADC 12 bit
float giaTri[SO_DIEM];
float docTrungBinh(int soMau) {
uint32_t tong = 0;
for (int i = 0; i < soMau; i++) {
tong += analogRead(CHAN_ADC);
}
return (float)tong / soMau;
}
void doMotMuc(int soMau) {
double tong = 0;
for (int i = 0; i < SO_DIEM; i++) {
giaTri[i] = docTrungBinh(soMau);
tong += giaTri[i];
}
double tb = tong / SO_DIEM;
double tongBp = 0;
float nhoNhat = giaTri[0];
float lonNhat = giaTri[0];
for (int i = 0; i < SO_DIEM; i++) {
tongBp += (giaTri[i] - tb) * (giaTri[i] - tb);
nhoNhat = min(nhoNhat, giaTri[i]);
lonNhat = max(lonNhat, giaTri[i]);
}
double doLech = sqrt(tongBp / (SO_DIEM - 1));
if (doLech < 0.01) {
doLech = 0.01; // tránh chia cho 0 khi mọi giá trị trùng nhau
}
double bitHieuDung = log2(THANG / doLech);
double bitKhongNhieu = log2(THANG / (6.6 * doLech));
Serial.printf("TB %2d mau: trung binh %7.1f | lech chuan %5.2f LSB | min-max %6.1f | %4.1f bit hieu dung | %4.1f bit khong nhieu\n",
soMau, tb, doLech, lonNhat - nhoNhat, bitHieuDung, bitKhongNhieu);
}
void setup() {
Serial.begin(115200);
analogReadResolution(12);
analogSetPinAttenuation(CHAN_ADC, ADC_11db); // dải đo khoảng 0..3,1 V
delay(500);
Serial.println("Do nhieu ADC tren GPIO34 (giu nguyen dien ap vao)");
}
void loop() {
uint32_t mv = 0;
for (int i = 0; i < 64; i++) {
mv += analogReadMilliVolts(CHAN_ADC);
}
Serial.printf("Dien ap vao khoang %u mV\n", (unsigned)(mv / 64));
for (int k = 0; k < 4; k++) {
doMotMuc(CAC_MUC_TB[k]);
}
Serial.println();
delay(5000);
}

Dùng chương trình này để so sánh: tháo tụ 100 nF, cấp nguồn bằng cáp USB khác, bật Wi-Fi, chạy relay bên cạnh, rồi xem độ lệch chuẩn thay đổi thế nào. Đó là cách nhanh nhất để biết cải tiến mạch nào có tác dụng.
7. Lỗi hay gặp
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| Số đọc nhảy vài chục LSB | nguồn tín hiệu trở kháng cao, không có tụ, dây dài | tụ 100 nF tại chân ADC, dây ngắn, lấy trung bình |
| Đọc sai ở gần 0 V hoặc gần 3,3 V | vùng phi tuyến của ADC ESP32 | chỉnh cầu chia để điện áp nằm giữa dải |
| Số đọc thay đổi khi bật Wi-Fi | nhiễu nguồn khi phát sóng; ADC2 không dùng được khi bật Wi-Fi | dùng chân ADC1 (GPIO32–39), tụ nguồn tốt |
| Trung bình nhiều mẫu vẫn lệch giá trị thật | sai số hệ thống, không phải nhiễu | hiệu chuẩn hai điểm với đồng hồ đo |
8. Xem thêm
- Đo điện áp 16 bit bằng module ADS1115 với ESP32
- Đọc ADC trên ESP32 và đo điện áp pin 18650 bằng cầu phân áp
- Đo dòng điện với ESP32: INA219 hay ACS712
- Mạch chuyển đổi ADC ADS1115 16 bit
Tần số lấy mẫu cần bao nhiêu, xem bài định lý lấy mẫu Nyquist cùng cụm chủ đề.
Xem thêm