Dasar · 18 mnt baca

Apa Itu ADC? Konversi Analog ke Digital dengan Arduino

Apa itu ADC dan bagaimana cara kerjanya? Sinyal analog vs digital, resolusi 10 dan 12 bit, analogReference, rumus tegangan, ADC2 ESP32, dan cara mengurangi derau.

ADC (analog-to-digital converter, konverter analog ke digital) adalah rangkaian yang mengubah tegangan yang berubah terus-menerus di sebuah pin menjadi angka yang bisa diolah mikrokontroler. Setiap kali kamu memanggil analogRead() di Arduino, konverter inilah yang bekerja di belakang layar: ADC 10-bit di Arduino Uno mengubah tegangan antara 0 dan 5 V menjadi angka 0 sampai 1023, sedangkan ADC 12-bit di ESP32 dan Raspberry Pi Pico mengubah kira-kira 0–3,3 V menjadi angka 0 sampai 4095. ADC adalah kunci untuk membaca apa pun yang punya output analog: potensiometer, LDR, sensor kelembapan tanah, joystick, dan sensor suhu.

Di panduan ini kamu akan mempelajari perbedaan sinyal analog dan digital, bagaimana ADC mengubah tegangan menjadi angka langkah demi langkah, dan bagaimana resolusi serta tegangan referensi memengaruhi pengukuranmu. Dengan angka nyata, kita akan membahas rumus yang mengubah pembacaan menjadi volt, mengubah rentang pengukuran dengan analogReference, laju sampling, dan cara praktis mengurangi derau. Kita juga akan membahas ADC ESP32 yang tidak linier di ujung-ujung rentangnya, bentrokan ADC2 dengan Wi-Fi, dan pengaturan atenuasi, cara memakai ADC Raspberry Pi Pico dengan MicroPython, lalu terakhir pengenalan singkat DAC, yang mengerjakan kebalikannya.

Membaca potensiometer dengan ADC
Potensiometer adalah cara paling mudah untuk mencoba ADC: tegangan di pin tengahnya berubah antara 0 V dan tegangan catu daya ketika kenopnya diputar.

Apa perbedaan sinyal analog dan digital?

Sinyal analog adalah besaran yang bisa bernilai tak terhingga banyaknya di dalam suatu rentang dan berubah terus-menerus terhadap waktu. Ketika tegangan di pin tengah potensiometer naik dari 0 V ke 5 V, tegangannya melewati setiap nilai di antaranya, seperti 1,2 V, 1,21 V, dan 1,215 V; gelombang suara dari mikrofon, tegangan termistor yang bergantung pada suhu, dan tegangan baterai yang turun perlahan juga analog. Sebaliknya, sinyal digital hanya mengenal level-level tertentu. Di dunia logika Arduino ada dua level: LOW (0) dan HIGH (1). Di Uno, input digital menganggap apa pun di bawah sekitar 1,5 V sebagai LOW dan apa pun di atas 3,0 V sebagai HIGH; daerah di antaranya tidak terdefinisi. Karena itu digitalRead() tidak bisa membedakan baterai 3,7 V dari 4,2 V dan menyebut keduanya HIGH. Kekuatan sinyal digital adalah kekebalannya terhadap derau: 4,6 V dan 5,0 V sama-sama berarti HIGH. Untuk mengukur, menyimpan, atau menghitung dengan nilai analog, kamu harus mengubahnya dulu menjadi angka, dengan kata lain nilai digital, dan bagian yang mengerjakannya adalah ADC.

Apa itu ADC dan bagaimana cara kerjanya?

Tugas ADC bisa diringkas dalam dua langkah. Yang pertama adalah sampling (pengambilan sampel): pada momen pengukuran, konverter menyalin tegangan input ke sebuah kapasitor kecil (rangkaian sample-and-hold) dan menahannya tetap sampai konversi selesai; di ATmega328P kapasitor ini sekitar 14 pF. Yang kedua adalah kuantisasi: tegangan yang ditahan dibulatkan ke langkah terdekat pada skala yang membagi tegangan referensi menjadi langkah-langkah yang sama besar, lalu nomor langkah itu dikembalikan sebagai hasil. ADC di Arduino Uno, ESP32, dan Pico semuanya bertipe successive approximation (aproksimasi berturut-turut; SAR, Successive Approximation Register). ADC SAR bekerja seperti permainan tebak angka: mula-mula ia mencoba setengah dari referensi, mengatur bit paling signifikan menjadi 1 kalau input lebih tinggi dan membiarkannya 0 kalau lebih rendah, lalu mencoba setengah dari rentang yang tersisa dan mengulanginya untuk setiap bit. Begitulah ADC 10-bit menemukan langkah yang tepat dari 1024 kemungkinan hanya dengan 10 perbandingan. Supaya sederhana, tabel di bawah menunjukkan cara ADC 4-bit dengan referensi 5 V mengukur input 3,2 V:

LangkahBit yang diujiTegangan pembandingInput (3,2 V) lebih tinggi?Bit hasil
1Bit 3 (bernilai 8)8 / 16 × 5 = 2,500 VYa → 11000
2Bit 2 (bernilai 4)12 / 16 × 5 = 3,750 VTidak → 01000
3Bit 1 (bernilai 2)10 / 16 × 5 = 3,125 VYa → 11010
4Bit 0 (bernilai 1)11 / 16 × 5 = 3,4375 VTidak → 01010
HasilSemua bit selesai1010 = 10 → 10 × 5 / 16 = 3,125 VGalat 0,075 V (satu langkah 0,3125 V)1010

Selisih 0,075 V pada hasil itu disebut galat kuantisasi, dan tidak ada ADC yang bisa lepas darinya: kalau tegangan sebenarnya berada di antara dua langkah, ADC hanya bisa melaporkan salah satunya. Galatnya selalu di bawah satu langkah (LSB), jadi makin kecil langkahnya, makin halus pengukurannya. Karena kapasitor sample-and-hold harus terisi di setiap pengukuran, hambatan sumber yang menggerakkan ADC juga berpengaruh: datasheet ATmega328P menyarankan impedansi output sekitar 10 kΩ atau kurang, dan pembagi tegangan dengan hambatan lebih besar tidak bisa mengisi kapasitor tepat waktu, sehingga pembacaannya bergeser. Selain tipe SAR yang ada di mikrokontroler, ada jenis ADC lain. ADC sigma-delta lambat tapi sangat presisi: HX711 yang dipakai di proyek timbangan menawarkan 24 bit, dan modul ADS1115 yang tersambung lewat I2C menawarkan 16 bit. ADC flash memakai komparator terpisah untuk setiap langkah; tipe ini sangat cepat dan bisa kamu temukan di osiloskop.

Resolusi ADC: apa arti 10 bit dan 12 bit?

Resolusi menunjukkan menjadi berapa langkah ADC membagi rentang pengukurannya. ADC N-bit menghasilkan 2^N langkah: 10 bit berarti 1024 langkah (0–1023), 12 bit 4096 langkah (0–4095), dan 16 bit 65.536 langkah. Tegangan satu langkah disebut LSB (least significant bit, bit paling tidak signifikan) dan dihitung dengan LSB = Vref / 2^N. Di Arduino Uno hasilnya 5 V / 1024 = 4,88 mV, dan di ESP32 serta Pico 3,3 V / 4096 = 0,81 mV. Jadi Uno tidak bisa melihat perubahan yang lebih kecil dari 4,88 mV; dengan LM35 yang mengeluarkan 10 mV/°C, itu berarti langkah sekitar 0,5 °C. Tapi resolusi dan akurasi bukan hal yang sama. Derau, ketidaklinieran, dan galat referensi ADC membuat sebagian bit yang tertulis di atas kertas tidak berguna. Ukurannya disebut jumlah bit efektif (ENOB, effective number of bits): ADC RP2040 di Raspberry Pi Pico mengembalikan hasil 12 bit, tapi menurut datasheet-nya jumlah bit efektifnya 8,7. Mari bandingkan ADC ketiga board berdampingan:

FiturArduino Uno R3ESP32 (WROOM-32)Raspberry Pi Pico
Resolusi ADC10 bit (0–1023)12 bit (0–4095)12 bit (diskalakan ke 0–65535 di MicroPython)
Input analog6 (A0–A5; A0–A7 di Nano)18 channel: 8 di ADC1, 10 di ADC23 pin (GP26–GP28) + VSYS/3 (GP29) + sensor suhu
Rentang pengukuran bawaan0–5 VSekitar 0–3,1 V (atenuasi 11 dB)0–3,3 V (ADC_VREF)
Satu langkah (LSB)4,88 mVSekitar 0,8 mV0,81 mV
Pilihan referensiDEFAULT (5 V), INTERNAL (1,1 V), EXTERNAL (AREF)Atenuasi: 0 / 2,5 / 6 / 11 dBReferensi eksternal di pin ADC_VREF
Laju samplingSekitar 10.000 pembacaan/dtk20 kHz – 2 MHz di mode kontinu (DMA)500.000 pembacaan/dtk di perangkat keras
Catatan akurasiGalat absolut ±2 LSBTidak linier di ujung-ujung rentang, perlu kalibrasiENOB 8,7 bit, offset sekitar 30 mV
Output analog (DAC)Tidak ada (memakai PWM)2 channel, 8 bit (GPIO 25 dan 26)Tidak ada (memakai PWM)

Rumus mengubah pembacaan ADC menjadi tegangan

Angka yang dikembalikan ADC tidak berarti apa-apa kalau berdiri sendiri; untuk mengubahnya menjadi tegangan, kamu memakai tegangan referensi dan jumlah langkah: Tegangan = nilai ADC × Vref / 2^N. Di Arduino Uno rumusnya V = nilai × 5,0 / 1024, jadi kalau analogRead() mengembalikan 512, tegangan di pin adalah 512 × 5 / 1024 = 2,50 V. Sebaliknya, untuk mencari angka yang sesuai dengan suatu tegangan, pakai nilai = V × 1024 / Vref: 3,3 V terbaca sekitar 675 di Uno. Di banyak contoh kamu akan melihat pembagian dengan 1023, bukan 1024. Datasheet ATmega328P memberi rumus ADC = Vin × 1024 / Vref; nilai terbesar, 1023, mewakili satu langkah di bawah Vref. Membagi dengan 1023 membuat nilai teratas tampil tepat 5,00 V, tapi menggeser setiap nilai sekitar 0,1%. Selisih itu lebih kecil daripada galat ADC sendiri yang ±2 LSB, jadi keduanya bisa dipakai; yang penting konsisten dalam satu proyek. Sumber galat besar yang sebenarnya adalah Vref itu sendiri: pin 5V di Uno yang diberi daya lewat USB sering berada di mana saja antara 4,7 dan 5,1 V, dan menulis 5.0 di rumus bisa menimbulkan galat sampai 5%. Jadi untuk pengukuran yang presisi, ukur pin 5V dengan multimeter dan masukkan nilai sebenarnya ke kodemu. Satu-satunya input analog ESP8266 (A0) juga 10 bit; chip-nya sendiri mengukur 0–1 V, dan pembagi tegangan bawaan di board seperti NodeMCU dan Wemos D1 Mini memperluas rentang itu menjadi sekitar 0–3,2 V.

Board dan pengaturanRentang pembacaanMengubah ke voltContoh
Arduino Uno / Nano (DEFAULT, 5 V)0–1023V = nilai × 5,0 / 1024768 → 3,75 V
Uno, analogReference(INTERNAL)0–1023V = nilai × 1,1 / 1024512 → 0,55 V
ESP32 (11 dB)0–4095Terkalibrasi: analogReadMilliVolts() / 1000; kasar: nilai × 3,3 / 40951650 mV → 1,65 V
Raspberry Pi Pico (read_u16)0–65535V = nilai × 3,3 / 6553532768 → 1,65 V
ESP8266 NodeMCU / Wemos D1 Mini (A0)0–1023V = nilai × 3,2 / 1024512 → 1,60 V

Menyambungkan potensiometer: Arduino, ESP32, dan Pico

Pin potensiometerArduino UnoESP32Raspberry Pi Pico
Pin luar 15V3V33V3(OUT) (pin 36)
Pin tengah (sinyal)A0GPIO 34 (ADC1_CH6)GP26 / ADC0 (pin 31)
Pin luar 2GNDGNDAGND (pin 33) atau GND
Kapasitor peredam derau (opsional)100 nF antara A0 dan GND100 nF antara GPIO 34 dan GND100 nF antara GP26 dan AGND
Input analog ESP32 dan Raspberry Pi Pico menerima paling tinggi 3,3 V; menyambungkan pin luar potensiometer ke 5 V, atau menyambungkan langsung sensor dengan output 5 V, bisa merusak pin secara permanen. Di Uno juga, jangan pernah memberi input tegangan lebih dari tegangan catu daya (5 V) atau kurang dari 0 V; turunkan tegangan yang lebih tinggi dengan pembagi tegangan. Pin analog yang tidak tersambung ke apa pun alias mengambang akan membaca nilai acak; itu bukan kerusakan, pin-nya hanya sedang “menggantung di udara”.

Langkah demi langkah: pembacaan ADC pertamamu dengan Arduino

  1. Rakit rangkaian: Sambungkan pin luar potensiometer 10 kΩ ke 5V dan GND, dan pin tengahnya ke A0.
  2. Ukur pin 5V: Ukur tegangan antara 5V dan GND dengan multimeter dan masukkan ke konstanta VREF di kode (misalnya 4.93).
  3. Upload kode: Buka sketch di bawah di Arduino IDE, pilih board dan port-mu, lalu upload.
  4. Buka Serial Monitor: Atur ke 9600 baud dan perhatikan nilai ADC berubah antara 0 dan 1023 ketika kenop diputar (detailnya di panduan Serial Monitor).
  5. Cek: Ukur antara A0 dan GND dengan multimeter dan bandingkan dengan tegangan di layar; selisihnya seharusnya sekitar 10–20 mV.
C++ (Arduino IDE)
1// Potansiyometreyi ADC ile okuma / Reading a potentiometer with the ADC
2// Kenar bacaklar 5V ve GND'ye, orta bacak A0'a / Outer legs to 5V and GND, wiper to A0
3const int POT_PIN = A0;
4const float VREF = 5.0;      // 5V pininde ölçtüğün gerilim / voltage you measured on the 5V pin
5
6void setup() {
7  Serial.begin(9600);
8}
9
10void loop() {
11  int raw = analogRead(POT_PIN);             // 0-1023 arası sayı / number between 0-1023
12  float volts = raw * VREF / 1024.0;         // sayıyı volta çevir / convert the number to volts
13  int percent = map(raw, 0, 1023, 0, 100);   // yüzdeye ölçekle / scale to percent
14
15  Serial.print(F("ADC: "));
16  Serial.print(raw);
17  Serial.print(F("  Gerilim / Voltage: "));
18  Serial.print(volts, 3);
19  Serial.print(F(" V  Yuzde / Percent: "));
20  Serial.println(percent);
21  delay(200);
22}

analogRead() menyelesaikan satu pengukuran dalam sekitar 100 µs dan mengembalikan bilangan bulat antara 0 dan 1023. Kode ini mula-mula mengubah angka itu menjadi volt dengan rumus tadi, lalu menjadi persen dengan map(). Karena map() memakai aritmetika bilangan bulat, bagian pecahannya dibuang; kalau kamu butuh hasil desimal, hitung sendiri dengan float. Ini adalah pengukuran rasiometrik: karena potensiometer dan ADC mendapat daya dari 5 V yang sama, posisi kenop, dan karena itu nilai ADC-nya, tidak berubah walaupun catu daya turun ke 4,9 V; yang berubah hanya tegangan hasil hitungan. Hal yang sama berlaku untuk sensor yang dibaca lewat pembagi tegangan, seperti LDR dan NTC. Sebaliknya, ketika kamu mengukur tegangan baterai atau sensor dengan output mV tetap seperti LM35, nilai Vref yang sebenarnya langsung masuk ke hasil.

Tegangan referensi dan analogReference

Tegangan referensi (Vref) adalah puncak skala ADC: kalau tegangan input sama dengan atau melebihi Vref, hasilnya tertahan di nilai maksimum (1023). Menurunkan Vref mempersempit rentang pengukuran tapi membuat setiap langkah lebih kecil, sehingga sinyal kecil terukur lebih halus. Di Arduino Uno kamu memilih referensi dengan fungsi analogReference(). Dengan pilihan INTERNAL, Vref menjadi 1,1 V dan satu langkah turun ke 1,07 mV; kamu bisa membaca LM35 (10 mV/°C) dengan langkah sekitar 0,1 °C, tapi sebagai gantinya tidak ada yang bisa diukur di atas 1,1 V, yaitu 110 °C. Referensi internal 1,1 V itu sendiri bisa bervariasi antara 1,0 dan 1,2 V dari satu chip ke chip lain, jadi proyek yang presisi perlu dikalibrasi sekali dengan multimeter. Beberapa pembacaan pertama setelah referensi diganti bisa tidak akurat, seperti juga dicatat di dokumentasi Arduino, jadi membuang beberapa pembacaan setelah berganti referensi adalah kebiasaan yang baik. Pengaturan referensi juga memengaruhi semua pin analog board sekaligus. Pilihannya berbeda dari board ke board:

PilihanReferensiBoardKapan dipakai
DEFAULT5 V (3,3 V di board 3,3 V)Uno, Nano, Mega, LeonardoSensor yang rasiometrik terhadap catu daya, seperti potensiometer, LDR, dan joystick
INTERNAL1,1 V (ATmega328P); 2,56 V di LeonardoUno, Nano, Leonardo (tidak ada di Mega)Sensor bertegangan rendah seperti LM35
INTERNAL1V1 / INTERNAL2V561,1 V / 2,56 VHanya MegaSinyal kecil di Mega
EXTERNALTegangan di pin AREF (0–5 V)Uno, Nano, MegaMemakai referensi presisimu sendiri (misalnya 2,5 V atau 4,096 V)
AR_INTERNALSekitar 1,43 V (referensi internal chip)Uno R4 Minima dan WiFiSinyal kecil di Uno R4
Kalau kamu sudah menyambungkan referensi eksternal ke pin AREF, kamu wajib memanggil analogReference(EXTERNAL) sebelum memanggil analogRead(). Kalau tidak, referensi yang dibangkitkan di dalam chip akan terhubung singkat dengan tegangan di pin AREF dan mikrokontroler bisa rusak. Kalau kamu ingin berpindah-pindah referensi, sambungkan tegangan eksternal ke AREF lewat resistor 5 kΩ; karena resistor itu membentuk pembagi tegangan dengan hambatan internal pin yang sekitar 32 kΩ, perhitungkan bahwa tegangan di AREF akan sedikit turun (sekitar 2,2 V untuk 2,5 V). Jangan pernah memberi AREF tegangan kurang dari 0 V atau lebih dari 5 V.

Laju sampling: berapa kali ADC bisa membaca dalam satu detik?

Laju sampling adalah berapa banyak pengukuran yang bisa dilakukan ADC dalam satu detik. Di Arduino Uno, clock ADC diatur ke 125 kHz dengan membagi 16 MHz dengan 128, dan satu konversi butuh 13 siklus clock; karena itu analogRead() butuh sekitar 100 µs dan kamu bisa membaca paling banyak sekitar 10.000 kali per detik. Itu lebih dari cukup untuk besaran yang berubah pelan seperti suhu, cahaya, atau tegangan baterai; sering kali 10 pembacaan per detik pun sudah cukup. Untuk sinyal cepat, berlaku aturan Nyquist: supaya sinyal tertangkap tanpa ada yang hilang, kamu harus mengambil sampel minimal dua kali lebih cepat daripada frekuensi tertingginya, dan dalam praktik lebih disukai 5–10 kali. Untuk melihat dengung listrik PLN 50 Hz kamu butuh minimal 100 pembacaan/dtk, dan untuk merekam suara bicara sampai 4 kHz minimal 8.000 pembacaan/dtk. Kalau butuh pembacaan lebih cepat di Uno, kamu bisa menurunkan prescaler ADC: menaruh ADCSRA = (ADCSRA & 0xF8) | 0x04; di setup() mengatur prescaler ke 16, clock ADC naik ke 1 MHz, dan analogRead() turun ke sekitar 16 µs, dengan mengorbankan sedikit akurasi. Di ESP32, panggilan analogRead() satu per satu memungkinkan puluhan ribu pembacaan per detik, dan di mode kontinu dengan DMA (analogContinuous() di Arduino) kamu bisa memilih laju antara 20 kHz dan 2 MHz; mode ini hanya bekerja dengan pin ADC1. ADC Raspberry Pi Pico berjalan dengan clock 48 MHz miliknya sendiri, menyelesaikan setiap konversi dalam 96 siklus, yaitu 2 µs, dan mencapai 500.000 pembacaan per detik; perulangan MicroPython tidak bisa mengimbanginya, dan untuk kecepatan penuh kamu butuh C SDK dan DMA.

ADC ESP32: ketidaklinieran, bentrokan ADC2 dengan Wi-Fi, dan atenuasi

Di atas kertas, ADC 12-bit di ESP32 mengukur empat kali lebih halus daripada Uno, tapi dalam praktik ada tiga hal yang perlu diperhatikan. Yang pertama adalah ketidaklinieran: di dekat 0 V, ADC ESP32 membaca 0 sampai sekitar 100–150 mV, dan di ujung atas ia sudah jenuh di 4095 sebelum input mencapai 3,3 V; kurva di antaranya juga bukan garis lurus sempurna. Yang kedua adalah variasi referensi: menurut desainnya, referensi internal ESP32 adalah 1100 mV, tapi menurut Espressif nilainya bervariasi antara 1000 dan 1200 mV dari satu chip ke chip lain, yang berarti galat kira-kira ±9% pada pembacaan yang belum dikalibrasi. Karena itu Espressif menulis data kalibrasi ke eFuse setiap chip selama produksi. Fungsi Arduino analogReadMilliVolts() memakai data ini untuk mengubah nilai mentah langsung menjadi milivolt yang terkalibrasi, dan di kebanyakan kasus jauh lebih akurat daripada menghitung analogRead() × 3,3 / 4095. Yang ketiga adalah atenuasi (attenuation): inti ADC hanya bisa mengukur sampai sekitar 1 V, jadi tegangan yang lebih tinggi diperkecil oleh atenuator yang bisa diatur di bagian input. Bawaan Arduino adalah 11 dB, yang memungkinkan pembacaan sampai sekitar 3,1 V, tapi rentang akurat yang disarankan Espressif untuk pengaturan ini adalah 150–2450 mV. Untuk sinyal kecil, menurunkan atenuasi meningkatkan akurasi sekaligus resolusi:

AtenuasiKonstanta ArduinoRentang akuratKegunaan
0 dBADC_0db100–950 mVSinyal kecil, pengukuran paling halus
2,5 dBADC_2_5db100–1250 mVOutput sensor sekitar 1 V
6 dBADC_6db150–1750 mVSinyal level menengah
11 dB (bawaan)ADC_11db150–2450 mV (pembacaan berlanjut sampai sekitar 3,1 V)Potensiometer dan sensor 0–3,3 V
Di ESP32, ADC2 juga dipakai oleh driver Wi-Fi. Begitu Wi-Fi dinyalakan, kamu tidak bisa membaca dari pin ADC2 (GPIO 0, 2, 4, 12, 13, 14, 15, 25, 26, 27); dalam kondisi itu ESP-IDF mengembalikan error timeout (ESP_ERR_TIMEOUT), dan di versi core Arduino yang sekarang analogRead() mengembalikan 0. Di proyek Wi-Fi, selalu sambungkan sensor analog ke pin ADC1: GPIO 32, 33, 34, 35, 36 (VP), dan 39 (VN). Dari pin-pin ini, 34–39 hanya untuk input dan tidak punya resistor pull-up internal, sehingga ideal untuk pembacaan analog. GPIO 0, 2, 12, dan 15 juga merupakan pin boot (pin strapping), jadi sama sekali tidak cocok untuk sensor analog.
C++ (Arduino IDE)
1// ESP32 ADC: ham değer ve kalibre milivolt / ESP32 ADC: raw value and calibrated millivolts
2// Potansiyometre: 3V3, GND ve orta bacak GPIO 34 / Pot: 3V3, GND and wiper to GPIO 34
3const int POT_PIN = 34;      // ADC1_CH6, Wi-Fi açıkken de çalışır / ADC1_CH6, works with Wi-Fi on
4
5void setup() {
6  Serial.begin(115200);
7  analogReadResolution(12);                     // 0-4095 (varsayılan / default)
8  analogSetPinAttenuation(POT_PIN, ADC_11db);   // yaklaşık 3,1 V'a kadar / up to about 3.1 V
9}
10
11void loop() {
12  uint32_t rawSum = 0;
13  uint32_t mvSum = 0;
14  for (int i = 0; i < 16; i++) {                // 16 ölçümün ortalaması / average of 16 readings
15    rawSum += analogRead(POT_PIN);              // ham ADC değeri / raw ADC value
16    mvSum += analogReadMilliVolts(POT_PIN);     // eFuse kalibrasyonlu mV / eFuse-calibrated mV
17  }
18  float raw = rawSum / 16.0;
19  float naiveV = raw * 3.3 / 4095.0;            // basit formül / naive formula
20  float calibratedV = mvSum / 16.0 / 1000.0;    // kalibre edilmiş / calibrated
21
22  Serial.printf("Ham / Raw: %4.0f  Formul / Formula: %.3f V  Kalibre / Calibrated: %.3f V\n",
23                raw, naiveV, calibratedV);
24  delay(500);
25}

Kode ini menampilkan dua hasil berdampingan: nilai mentah yang diubah dengan rumus sederhana dan nilai terkalibrasi dari analogReadMilliVolts(). Ketika kamu memutar potensiometer ke salah satu ujung, kamu akan melihat selisihnya makin besar, dan di paling bawah, ketika rumus menunjukkan 0.000 V, multimeter masih mengukur sekitar 0,1 V. analogSetPinAttenuation() mengubah atenuasi untuk satu pin, sedangkan analogSetAttenuation() mengubahnya untuk semua pin. ESP32 jelas lebih berderau daripada Uno, terutama ketika Wi-Fi sedang memancar; saran Espressif sendiri adalah menambahkan kapasitor 100 nF di input dan merata-ratakan beberapa sampel, dan itulah yang dilakukan rata-rata 16 pembacaan di kode ini. Chip yang lebih baru seperti ESP32-S3 dan ESP32-C3 memakai kalibrasi curve-fitting yang lebih canggih, tapi nomor pin dan aturan ADC2 berbeda per model, jadi selalu cek peta pin board-mu (alat Pinout). Cara membuat pembagi untuk mengukur tegangan di atas 3,3 V kami jelaskan di panduan pembagi tegangan.

ADC di Raspberry Pi Pico (MicroPython)

Raspberry Pi Pico punya tiga input analog yang bisa dipakai dari luar: GP26 (ADC0), GP27 (ADC1), dan GP28 (ADC2). GP29 (ADC3) mengukur sepertiga tegangan catu VSYS di board, dan ADC4 terhubung ke sensor suhu internal chip. Fungsi read_u16() di MicroPython menskalakan hasil 12 bit ke rentang 0–65535 supaya kode yang sama bisa berjalan di berbagai board, tapi resolusi sebenarnya tetap 4096 langkah. RP2040 tidak punya tegangan referensi terpisah; ia memakai catu ADC-nya sendiri sebagai referensi. Di Pico, catu ini (ADC_VREF, pin 35) diambil dari output regulator switching (SMPS) 3,3 V dan disaring lewat resistor sekitar 200 Ω. Datasheet board Raspberry Pi menyebutkan tiga akibatnya dengan jelas: akurasi 3,3 V-nya terbatas, catunya agak berderau, dan arus yang ditarik ADC menimbulkan offset sekitar 30 mV. Solusinya ada di dokumen yang sama: buat GP23 HIGH supaya regulator masuk ke mode PWM yang riaknya lebih rendah, sambungkan satu channel ADC yang tidak terpakai ke AGND dan kurangkan pembacaannya sebagai offset, dan untuk akurasi yang jauh lebih baik, pasang referensi 3,0 V seperti LM4040 antara ADC_VREF dan AGND (rentang pengukurannya lalu menjadi 0–3,0 V). ADC RP2040 juga dikenal punya lompatan kecil (galat DNL) di nilai 512, 1536, 2560, dan 3584; merata-ratakan beberapa pembacaan mengurangi efeknya. Di Pico W, GP23 dipakai oleh chip nirkabel dan mode regulator dikendalikan lewat WL_GPIO1, jadi hapus baris-baris GP23 di kode di bawah kalau kamu memakai Pico W.

MicroPython
1from machine import ADC, Pin
2import time
3
4pot = ADC(26)                 # GP26 = ADC0 (pin 31)
5chip_temp = ADC(4)            # dahili sıcaklık sensörü / internal temperature sensor
6VREF = 3.3                    # ADC_VREF; multimetreyle ölçüp düzelt / measure and correct with a multimeter
7
8# Yalnız Pico ve Pico 2 (W değil): SMPS PWM moduna, daha az gürültü / Plain Pico and Pico 2 only (not W): SMPS to PWM mode, less noise
9smps_mode = Pin(23, Pin.OUT)
10smps_mode.value(1)
11
12
13def read_average(adc, samples=16):
14    total = 0
15    for _ in range(samples):
16        total += adc.read_u16()           # 0-65535 (12 bit ölçeklenmiş / 12-bit scaled)
17    return total / samples
18
19
20while True:
21    raw = read_average(pot)
22    volts = raw * VREF / 65535            # sayıyı volta çevir / convert the number to volts
23    t_volts = read_average(chip_temp) * VREF / 65535
24    temp_c = 27 - (t_volts - 0.706) / 0.001721    # RP2040 veri sayfası formülü / RP2040 datasheet formula
25    print("ADC: {:5d}  {:.3f} V  Yonga / Chip: {:.1f} C".format(int(raw), volts, temp_c))
26    time.sleep(0.5)

Cara mengurangi derau ADC

Bahkan ketika mengukur tegangan yang stabil, nilai ADC yang bergoyang satu atau dua langkah itu normal; kuantisasi, riak di catu daya, gangguan yang tertangkap kabel panjang, serta motor atau pancaran Wi-Fi di dekatnya semuanya ikut berperan. Di Uno, goyangan ±1–2 langkah dianggap sehat; kalau jauh lebih besar dari itu, biasanya ada masalah di rangkaian. Kamu bisa melawan derau dari sisi perangkat keras maupun perangkat lunak:

  • Tambahkan kapasitor: Kapasitor keramik 100 nF antara pin analog dan GND menyaring gangguan cepat dan memberi kapasitor sample-and-hold muatan yang siap pakai ketika sumbernya berhambatan tinggi.
  • Pendekkan kabel: Kalau kabel sensornya panjang, pilin kabel sinyal dan GND bersama; jauhkan kabel motor dan relay dari jalur analog.
  • Atur grounding dengan benar: Jangan biarkan arus balik dari beban arus besar seperti motor, relay, dan LED strip mengalir lewat kabel GND sensor; satukan ground-ground di satu titik (star grounding).
  • Pakai referensi yang bersih: Daya USB itu berderau; untuk pengukuran tegangan absolut, referensi internal atau IC referensi eksternal memberi hasil yang lebih stabil.
  • Buang pembacaan pertama setelah berganti channel: Multiplexer di input ADC bisa membawa sisa muatan dari channel sebelumnya; ketika membaca beberapa pin bergantian, buang satu pembacaan di setiap pin.
  • Rata-ratakan: Merata-ratakan N pembacaan mengurangi derau acak kira-kira sebesar √N; 16 pembacaan memangkas derau menjadi seperempatnya.
  • Oversampling: Kalau kamu menjumlahkan 4^n pembacaan lalu menggeser hasilnya ke kanan sebanyak n bit, kamu mendapat tambahan resolusi n bit; menggeser jumlah 16 pembacaan sebanyak 2 bit mengubah 10 bit Uno menjadi 12. Supaya ini berhasil, sinyalnya perlu punya derau alami minimal satu langkah.
  • Filter median dan eksponensial: Filter median menghilangkan lonjakan mendadak akibat motor, sedangkan rata-rata bergerak eksponensial (EMA) memberi kurva yang halus dengan memori yang sangat sedikit.
C++ (Arduino IDE)
1// Ham, ortalama ve EMA filtreli ADC değerleri / Raw, averaged and EMA-filtered ADC values
2// Serial Plotter ile izle / Watch with the Serial Plotter
3const int SENSOR_PIN = A0;
4const float ALPHA = 0.1;     // EMA katsayısı (0-1) / EMA coefficient (0-1)
5float ema = 0;
6
7void setup() {
8  Serial.begin(115200);
9  analogRead(SENSOR_PIN);              // ilk okumayı at / discard the first reading
10  ema = analogRead(SENSOR_PIN);        // filtreyi başlat / seed the filter
11}
12
13void loop() {
14  int raw = analogRead(SENSOR_PIN);    // ham değer / raw value
15
16  long sum = 0;
17  for (int i = 0; i < 16; i++) {       // 16 ölçüm topla / sum 16 readings
18    sum += analogRead(SENSOR_PIN);
19  }
20  float average = sum / 16.0;          // ortalama (0-1023) / average (0-1023)
21
22  ema += ALPHA * (raw - ema);          // üstel hareketli ortalama / exponential moving average
23
24  Serial.print(F("ham:"));
25  Serial.print(raw);
26  Serial.print(F(" ortalama:"));
27  Serial.print(average);
28  Serial.print(F(" ema:"));
29  Serial.println(ema);
30  delay(20);
31}

Ketika kamu meng-upload kode dan membuka Serial Plotter di Arduino IDE, kamu akan melihat tiga garis: nilai mentah bergetar, rata-rata 16 pembacaan jelas lebih tenang, dan EMA adalah kurva paling halus tapi bereaksi terhadap perubahan sedikit lebih lambat. Koefisien ALPHA dipilih antara 0 dan 1: 0.1 berarti setiap pembacaan baru menyumbang 10% ke hasil, jadi kira-kira 10 pembacaan terakhir yang berpengaruh; kalau dinaikkan, responsnya makin cepat tapi deraunya makin besar. Filter mana yang dipilih tergantung sinyalnya; EMA yang kuat cocok untuk suhu yang berubah pelan, sedangkan rata-rata pendek lebih baik untuk joystick yang butuh respons cepat. Rata-rata bergerak, filter median, dan histeresis kami bandingkan dengan contoh sensor nyata di panduan menyaring data sensor.

Pengenalan singkat DAC: dari digital ke analog

DAC (digital-to-analog converter, konverter digital ke analog) mengerjakan kebalikan dari ADC: ia menerima angka dan menghasilkan tegangan yang sebanding dengan angka itu. Tulis 0 ke DAC 8-bit dan kamu mendapat 0 V, tulis 255 dan kamu mendapat tegangan yang mendekati tegangan catu, tulis 128 dan kamu mendapat sekitar setengahnya. DAC yang paling sederhana dibuat dengan tangga resistor yang disebut R-2R. Mari luruskan satu kekeliruan yang umum: analogWrite() di Arduino Uno bukan DAC, melainkan menghasilkan PWM; pin-nya sebenarnya berpindah sangat cepat antara 0 V dan 5 V. Itu tidak masalah untuk kecerahan LED dan kecepatan motor, tapi kalau kamu benar-benar butuh tegangan yang stabil, kamu harus menambahkan filter low-pass RC di output PWM; konstanta waktu filternya bisa kamu hitung dengan alat Konstanta waktu RC. Untuk board yang punya DAC sungguhan: ESP32 punya dua DAC 8-bit di GPIO 25 dan GPIO 26 yang dipakai dengan dacWrite(pin, value), sedangkan ESP32-S3 dan ESP32-C3 tidak punya DAC. Arduino Uno R4 punya DAC 12-bit di pin A0. Untuk Uno R3, Nano, dan Pico, cara paling mudah adalah modul MCP4725 12-bit yang tersambung lewat I2C. Dengan DAC kamu bisa membangkitkan suara, mengeluarkan gelombang sinus atau segitiga, bahkan menyambungkan output DAC ke input ADC untuk menguji ADC dengan tegangan yang sudah diketahui:

C++ (Arduino IDE)
1// ESP32 DAC ile sinüs dalgası / Sine wave with the ESP32 DAC
2// Çıkış GPIO 25'te, osiloskopla izle / Output on GPIO 25, watch it with an oscilloscope
3const int DAC_PIN = 25;      // DAC1 = GPIO 25 (DAC2 = GPIO 26)
4const int STEPS = 64;        // bir periyottaki nokta sayısı / points per period
5uint8_t sineTable[STEPS];
6
7void setup() {
8  for (int i = 0; i < STEPS; i++) {
9    sineTable[i] = 128 + 127 * sin(2 * PI * i / STEPS);  // 1-255 arası tablo / table between 1-255
10  }
11}
12
13void loop() {
14  for (int i = 0; i < STEPS; i++) {
15    dacWrite(DAC_PIN, sineTable[i]);   // 0 → 0 V, 255 → yaklaşık 3,3 V / 0 → 0 V, 255 → about 3.3 V
16    delayMicroseconds(150);            // yaklaşık 100 Hz / roughly 100 Hz
17  }
18}

Ide proyek dengan ADC

  • Voltmeter digital: Ukur 0–25 V dengan pembagi tegangan dan tampilkan hasilnya di LCD; langkah-langkahnya ada di panduan Membuat Voltmeter Arduino.
  • Lampu tidur otomatis: Baca tegangan LDR dan nyalakan LED ketika gelap.
  • Pot tanaman pintar: Pakai output analog sensor kelembapan tanah untuk menjalankan pompa ketika tanahnya kering.
  • Robot yang dikendalikan joystick: Dua sumbu joystick adalah dua input analog terpisah; ubah nilainya menjadi kecepatan dan arah motor.
  • Pengukur arus: Baca tegangan ACS712 yang sebanding dengan arus untuk melihat berapa arus yang ditarik sebuah perangkat.
  • Pengukur tingkat suara: Ambil sampel output analog sensor suara KY-038 dengan cepat dan nyalakan bar LED sesuai nilai puncaknya.
  • Indikator baterai: Ukur tegangan di proyek bertenaga baterai dan tampilkan sisa daya sebagai persen di layar.

Kesalahan umum dan cara memperbaikinya

GejalaKemungkinan penyebabPerbaikan
Nilainya melompat acak walaupun tidak ada yang tersambungPin-nya mengambangSambungkan sensornya; jangan baca pin yang tidak dipakai, atau tarik ke GND
Nilainya tertahan di 1023 (4095 di ESP32)Input di atas referensi, atau INTERNAL yang terpilihSesuaikan referensi atau atenuasi, turunkan tegangan tinggi dengan pembagi
Di ESP32, analogRead() mengembalikan 0 begitu Wi-Fi menyalaSensor ada di pin ADC2Pakai pin ADC1, GPIO 32–39
ESP32 menunjukkan 0 untuk tegangan kecil dan 4095 untuk tegangan besarADC tidak linier di ujung-ujung rentangPakai analogReadMilliVolts() dan jaga sinyal di 150–2450 mV
Tegangan hasil hitungan berbeda 3–5% dari multimeterVref bukan 5,00 V (daya USB)Ukur pin 5V dan masukkan ke VREF, atau tambahkan faktor kalibrasi
Ketika dua pin dibaca bergantian, nilainya saling memengaruhiMultiplexer dan hambatan sumber yang tinggiBuang pembacaan pertama setelah berganti, jaga sumber di bawah 10 kΩ, tambahkan 100 nF
Nilainya melompat ketika motor atau relay bekerjaDerau di jalur GND bersama, catu daya turunBeri beban jalur balik GND sendiri, pakai kapasitor dan filter median
Pembacaan jadi kacau setelah memberi tegangan ke AREFAREF dipakai tanpa memanggil analogReference(EXTERNAL)Pilih EXTERNAL dulu, atau sambungkan ke AREF lewat resistor 5 kΩ
Setelah memilih INTERNAL, potensiometer sudah mencapai 1023 di tengah putaranReferensi 1,1 V memengaruhi semua pin analogKembali ke DEFAULT sebelum membaca sensor rasiometrik dan buang beberapa pembacaan
Di Pico, pembacaannya di atas 0 walaupun input disambung ke GNDOffset ADC dan derau ADC_VREFSambungkan satu channel ke AGND, ukur offset-nya dan kurangkan; buat GP23 HIGH
Cara tercepat untuk memeriksa rangkaian ADC adalah mengukur tegangan yang sudah diketahui. Pertama, sambungkan input analog ke GND dan pastikan kamu melihat nilai yang mendekati 0. Lalu ambil baterai AA yang tegangannya sudah kamu ukur dengan multimeter, sambungkan kutub negatifnya ke GND dan kutub positifnya ke pin analog: untuk sekitar 1,5 V kamu seharusnya melihat sekitar 307 di Uno, sekitar 1500 mV dengan analogReadMilliVolts() di ESP32, dan sekitar 29.800 dengan read_u16() di Pico. Kalau hasilnya cocok, kode dan pengkabelanmu sudah benar; kalau tidak, masalahnya kemungkinan besar ada di tegangan referensi atau GND bersama.

ADC adalah jembatan antara dunia fisik dan kodemu: begitu kamu tahu resolusi, tegangan referensi, dan laju sampling-nya, kamu juga tahu apa yang diwakili setiap angka di layar dan seberapa jauh angka itu bisa dipercaya. Ukur referensinya dengan benar di Uno, pakai pin ADC1 dan analogReadMilliVolts() di ESP32, perhitungkan offset dan derau di Pico, lalu tenangkan hasilnya dengan rata-rata dan filter. Di aplikasi BlueGrays kamu akan menemukan proyek yang dibangun di atas pembacaan analog, seperti mengukur intensitas cahaya dengan LDR, voltmeter digital dengan layar LCD, mengukur suhu dengan NTC, serta menggerakkan motor servo dan mengatur kecerahan LED dengan potensiometer, masing-masing dengan skema rangkaian dan kode langkah demi langkah.

Pertanyaan umum

Apa itu ADC dan apa kegunaannya?

ADC (analog-to-digital converter, konverter analog ke digital) adalah rangkaian yang mengubah tegangan di sebuah pin menjadi angka yang bisa diolah mikrokontroler. ADC dipakai untuk membaca komponen yang punya output analog, seperti potensiometer, LDR, serta sensor suhu dan kelembapan. Di Arduino, perintah analogRead() menjalankan konverter ini.

Apa perbedaan sinyal analog dan digital?

Sinyal analog bisa bernilai berapa pun di dalam suatu rentang dan berubah terus-menerus, sedangkan sinyal digital hanya terdiri dari level-level tertentu, yaitu LOW dan HIGH di Arduino. digitalRead() hanya memberi tahu apakah sebuah pin bernilai 0 atau 1, sedangkan analogRead() memberi tahu berapa besar tegangannya dalam bentuk angka.

Kenapa analogRead di Arduino mengembalikan nilai 0 sampai 1023?

ADC Arduino Uno adalah 10-bit dan menghasilkan 2^10 = 1024 langkah berbeda, diberi nomor dari 0 sampai 1023. Nilai 0 mewakili 0 V, dan 1023 mewakili satu langkah di bawah tegangan referensi (biasanya 5 V). ADC 12-bit di ESP32 dan Pico mengembalikan nilai 0 sampai 4095.

Bagaimana cara mengubah nilai ADC menjadi tegangan?

Pakai rumus tegangan = nilai ADC × tegangan referensi / jumlah langkah. Di Arduino Uno rumusnya V = nilai × 5,0 / 1024; di ESP32, analogReadMilliVolts() langsung memberi milivolt yang terkalibrasi. Di Pico, pakai V = nilai × 3,3 / 65535 untuk nilai read_u16() dari MicroPython.

Apakah pin ADC2 ESP32 bisa dipakai bersama Wi-Fi?

Tidak. Di ESP32, driver Wi-Fi juga memakai unit ADC2, jadi kamu tidak bisa membaca dari pin ADC2 (GPIO 0, 2, 4, 12–15, 25–27) selama Wi-Fi menyala. Di proyek Wi-Fi, sambungkan sensor analog ke pin ADC1 (GPIO 32–39).

Apa itu DAC dan apa bedanya dengan ADC?

DAC (digital-to-analog converter, konverter digital ke analog) mengerjakan kebalikan dari ADC: ia mengubah angka menjadi tegangan. ADC dipakai untuk mengukur tegangan yang datang dari sensor, sedangkan DAC untuk menghasilkan tegangan seperti suara atau sinyal. Arduino Uno tidak punya DAC dan analogWrite() menghasilkan PWM; ESP32 punya dua DAC 8-bit di GPIO 25 dan 26, dan Uno R4 punya DAC 12-bit di A0.

Lihat semua proyek
Mengukur Intensitas Cahaya dengan LDR
#11Pemula

Mengukur Intensitas Cahaya dengan LDR

Ingin melihat seberapa terang kamarmu dalam bentuk angka? LDR, komponen kecil yang bereaksi terhadap cahaya, mengukur cahaya di sekitarnya, dan Arduino menulis nilainya ke layar komputermu setiap sete

4.6(81)
139
Voltmeter Digital dengan Layar LCD
#56Menengah
Premium

Voltmeter Digital dengan Layar LCD

Cari tahu berapa tegangan yang diberikan baterai atau adaptor daya dengan alat ukur buatanmu sendiri. Pembagi dari dua resistor menurunkan tegangan tinggi ke tingkat yang bisa dibaca board, dan Arduin

4.5(27)
36
Membaca Intensitas Cahaya dengan Modul LDR ESP32
#113Pemula

Membaca Intensitas Cahaya dengan Modul LDR ESP32

Memantau secara real-time di Serial Monitor nilai ADC mentah modul LDR dan persentase cahaya relatif yang dihitung dari nilai acuan gelap dan terang. Persentase ini bukan pengukuran lux. Mengajarkan logika kalibrasi modul. Ideal dikerjakan sebelum Proyek 10, karena dipakai untuk menentukan nilai ambang.

4.6(36)
55
Kendali Kecerahan LED dengan Potensiometer ESP32 (Analog → PWM)
#115Menengah
Premium

Kendali Kecerahan LED dengan Potensiometer ESP32 (Analog → PWM)

Di proyek ini, kita mengendalikan kecerahan LED secara analog memakai potensiometer. Pin ADC ESP32 membaca tegangan 0-3,3V dari potensiometer, lalu nilai ini diubah menjadi sinyal PWM (Pulse Width Modulation) dan dikirim ke LED. Hasilnya, ketika kamu memutar potensiometer, LED perlahan menerang dan meredup. Dengan Arduino Core 3.0+, analogWrite() bisa langsung dipakai; di ESP32-S2/S3, resolusi ADC tetap 12-bit.

4.5(19)
32
Mengukur Suhu dengan NTC dan Layar LCD 2x16
#44Pemula
Premium

Mengukur Suhu dengan NTC dan Layar LCD 2x16

Ukur suhu di sekitarmu dengan sensor yang mirip manik-manik kecil. Komponen bernama NTC ini makin mudah dilewati listrik ketika makin hangat; Arduino membaca perubahan itu, mengubahnya menjadi derajat

4.5(33)
44
Menggerakkan Motor Servo dengan Potensiometer
#36Pemula
Premium

Menggerakkan Motor Servo dengan Potensiometer

Ketika kamu memutar kenop potensiometer, lengan motor servo ikut berputar: satu ujung kenop berarti nol derajat, ujung lainnya berarti setengah putaran. Arduino terus membaca posisi kenop dan servo la

4.6(37)
52
Kendali LED dengan Joystick
#59Menengah
Premium

Kendali LED dengan Joystick

Dorong tuas kecil joystick sampai mentok ke arah mana pun dan LED untuk arah itu menyala: ada empat warna berbeda untuk kanan, kiri, atas, dan bawah. Lepaskan tuasnya, ia kembali ke tengah dan semua L

4.7(50)
67
Lampu Pencampur Warna ESP32 (3 Potensiometer + LED RGB + OLED)
#138Mahir
Premium

Lampu Pencampur Warna ESP32 (3 Potensiometer + LED RGB + OLED)

Lampu pencampur warna pintar: campur warna apa pun dengan memutar tiga potensiometer di ESP32! Ketika potensiometer merah, hijau, dan biru diputar, LED RGB katoda bersama berubah warna secara real-time. OLED SSD1306 menampilkan nilai setiap warna dalam rentang 0–255, bar pengisi, dan kode warna web HEX (seperti #FF8040). Studio warna mini yang mengajarkan teori warna RGB, pembacaan ADC, pengaturan kecerahan dengan PWM, dan desain layar I2C sekaligus.

4.7(6)
10