Temeller · 15 dk okuma

ADC Nedir? Analog Dijital Dönüşüm, Çözünürlük ve analogRead

ADC nedir, nasıl çalışır? Analog ve dijital sinyal farkı, 10 ve 12 bit çözünürlük, analogReference, volta çevirme formülü, ESP32 ADC2 ve gürültü azaltma.

ADC (Analog-Dijital Dönüştürücü), bir pine gelen ve sürekli değişebilen gerilimi mikrodenetleyicinin işleyebileceği bir sayıya çeviren devredir. Arduino'da analogRead() komutunu her çalıştırdığında arka planda bu dönüştürücü çalışır: Arduino Uno'nun 10 bitlik ADC'si 0–5 V arasındaki gerilimi 0 ile 1023 arasında bir sayıya, ESP32 ve Raspberry Pi Pico'nun 12 bitlik ADC'leri ise yaklaşık 0–3,3 V'u 0 ile 4095 arasında bir sayıya dönüştürür. Potansiyometre, LDR, toprak nem sensörü, joystick ve sıcaklık sensörü gibi analog çıkış veren her parçayı okuyabilmenin anahtarı ADC'dir.

Bu yazıda analog ve dijital sinyal arasındaki farkı, ADC'nin bir gerilimi adım adım nasıl sayıya çevirdiğini, çözünürlüğün ve referans geriliminin ölçümü nasıl etkilediğini öğreneceksin. Okunan değeri volta çeviren formülü, analogReference ile ölçüm aralığını değiştirmeyi, örnekleme hızını ve gürültüyü azaltmanın pratik yollarını gerçek sayılarla göreceğiz. ESP32'nin uçlarda doğrusal olmayan ADC'sini, Wi-Fi ile ADC2 çakışmasını ve attenuation (zayıflatma) ayarını, Raspberry Pi Pico'nun ADC'sini MicroPython ile kullanmayı da ele alacak, son olarak işin tersini yapan DAC'a kısa bir giriş yapacağız.

Potansiyometre ile ADC okuma
Potansiyometre, ADC'yi denemenin en kolay yoludur: orta bacağındaki gerilim, düğmeyi çevirdikçe 0 V ile besleme gerilimi arasında değişir.

Analog ve dijital sinyal arasındaki fark nedir?

Analog sinyal, belirli bir aralıkta sonsuz sayıda değer alabilen ve zamanla kesintisiz değişen bir büyüklüktür. Bir potansiyometrenin orta bacağındaki gerilim 0 V'tan 5 V'a giderken 1,2 V, 1,21 V, 1,215 V gibi aradaki her değerden geçer; mikrofonun ürettiği ses dalgası, bir termistörün sıcaklıkla değişen gerilimi ya da pilin yavaşça düşen gerilimi de analogdur. Dijital sinyal ise yalnızca belirli seviyeleri tanır. Arduino'nun lojik dünyasında bu seviyeler iki tanedir: LOW (0) ve HIGH (1). Uno'da bir dijital giriş yaklaşık 1,5 V'un altını LOW, 3,0 V'un üstünü HIGH sayar; aradaki bölge tanımsızdır. digitalRead() bu yüzden bir pildeki 3,7 V ile 4,2 V arasındaki farkı göremez, ikisine de HIGH der. Dijital sinyalin gücü gürültüye dayanıklı olmasıdır: 4,6 V da 5,0 V da aynı HIGH anlamına gelir. Analog bir değeri ölçmek, saklamak ya da hesaplamaya sokmak için onu önce bir sayıya, yani dijital bir değere çevirmen gerekir; bu işi yapan parça ADC'dir.

ADC nedir, nasıl çalışır?

ADC'nin işi iki adımda özetlenebilir. İlki örneklemedir: dönüştürücü, ölçüm anında girişteki gerilimi küçük bir kondansatöre (örnekle-tut devresi) kopyalar ve dönüşüm bitene kadar sabit tutar; ATmega328P'de bu kondansatör yaklaşık 14 pF'tır. İkincisi nicemlemedir (kuantalama): tutulan gerilim, referans gerilimi eşit basamaklara bölen bir ölçekte en yakın basamağa yuvarlanır ve basamağın numarası sonuç olarak verilir. Arduino Uno, ESP32 ve Pico'daki ADC'lerin hepsi ardışık yaklaşım (SAR, Successive Approximation Register) tipindedir. SAR ADC bir sayı tahmin oyunu gibi çalışır: önce referansın yarısını dener, giriş bundan büyükse en yüksek biti 1 yapar, küçükse 0 bırakır; sonra kalan aralığın yarısını dener ve bunu her bit için tekrarlar. 10 bitlik bir ADC böylece yalnızca 10 karşılaştırmayla 1024 olasılık arasından doğru basamağı bulur. Aşağıdaki tabloda basitlik için 4 bitlik bir ADC'nin 5 V referansla 3,2 V'luk bir girişi nasıl ölçtüğünü görüyorsun:

AdımDenenen bitKarşılaştırma gerilimiGiriş (3,2 V) büyük mü?Sonuç bitleri
1Bit 3 (değeri 8)8 / 16 × 5 = 2,500 VEvet → 11000
2Bit 2 (değeri 4)12 / 16 × 5 = 3,750 VHayır → 01000
3Bit 1 (değeri 2)10 / 16 × 5 = 3,125 VEvet → 11010
4Bit 0 (değeri 1)11 / 16 × 5 = 3,4375 VHayır → 01010
SonuçTüm bitler bitti1010 = 10 → 10 × 5 / 16 = 3,125 VHata 0,075 V (bir basamak 0,3125 V)1010

Sonuçtaki 0,075 V'luk fark nicemleme hatasıdır ve hiçbir ADC bundan kaçamaz: gerçek gerilim iki basamağın arasındaysa ADC yalnızca basamaklardan birini söyleyebilir. Hata bir basamağın (LSB) altında kalır, bu yüzden basamak ne kadar küçükse ölçüm o kadar ince olur. Örnekle-tut kondansatörünün her ölçümde dolması gerektiği için ADC'yi besleyen kaynağın direnci de önemlidir: ATmega328P'nin veri sayfası kaynağın çıkış direncinin yaklaşık 10 kΩ ya da daha düşük olmasını önerir; daha yüksek dirençli bir gerilim bölücü kondansatörü zamanında dolduramaz ve okumalar kayar. Mikrodenetleyicilerdeki SAR tipinin dışında başka ADC türleri de vardır. Sigma-delta ADC'ler yavaş ama çok hassastır; tartı projelerinde kullanılan HX711 24 bit, I2C ile bağlanan ADS1115 modülü ise 16 bit çözünürlük sunar. Flash ADC'ler her basamak için ayrı bir karşılaştırıcı kullanır; çok hızlıdırlar ve osiloskoplarda bulunurlar.

ADC çözünürlüğü: 10 bit ve 12 bit ne demek?

Çözünürlük, ADC'nin ölçüm aralığını kaç basamağa böldüğünü söyler. N bitlik bir ADC 2^N basamak üretir: 10 bit 1024 basamak (0–1023), 12 bit 4096 basamak (0–4095), 16 bit ise 65.536 basamak demektir. Bir basamağın gerilim karşılığına LSB (en düşük anlamlı bit) denir ve LSB = Vref / 2^N formülüyle bulunur. Arduino Uno'da 5 V / 1024 = 4,88 mV, ESP32 ve Pico'da 3,3 V / 4096 = 0,81 mV olur. Yani Uno 4,88 mV'tan küçük değişimleri göremez; 10 mV/°C çıkış veren LM35 ile bu yaklaşık 0,5 °C'lik bir adım demektir. Ancak çözünürlük ile doğruluk aynı şey değildir. Bir ADC'nin gürültüsü, doğrusal olmayan davranışı ve referans hatası, kâğıt üzerindeki bitlerin bir kısmını işe yaramaz hale getirir. Bunu anlatan ölçüye etkin bit sayısı (ENOB) denir: Raspberry Pi Pico'daki RP2040'ın ADC'si 12 bitlik sonuç verir ama veri sayfasına göre etkin bit sayısı 8,7'dir. Üç kartın ADC özelliklerini yan yana koyalım:

ÖzellikArduino Uno R3ESP32 (WROOM-32)Raspberry Pi Pico
ADC çözünürlüğü10 bit (0–1023)12 bit (0–4095)12 bit (MicroPython'da 0–65535'e ölçeklenir)
Analog giriş6 (A0–A5; Nano'da A0–A7)18 kanal: ADC1'de 8, ADC2'de 103 pin (GP26–GP28) + VSYS/3 (GP29) + sıcaklık sensörü
Varsayılan ölçüm aralığı0–5 VYaklaşık 0–3,1 V (11 dB zayıflatma)0–3,3 V (ADC_VREF)
Bir basamak (LSB)4,88 mVYaklaşık 0,8 mV0,81 mV
Referans seçenekleriDEFAULT (5 V), INTERNAL (1,1 V), EXTERNAL (AREF)Zayıflatma: 0, 2,5, 6 ve 11 dBADC_VREF pinine harici referans
Örnekleme hızıYaklaşık 10.000 ölçüm/sSürekli (DMA) modda 20 kHz – 2 MHzDonanımda 500.000 ölçüm/s
Doğruluk notuMutlak hata ±2 LSBUçlarda doğrusal değil, kalibrasyon gerekirENOB 8,7 bit, yaklaşık 30 mV ofset
Analog çıkış (DAC)Yok (PWM kullanılır)2 kanal, 8 bit (GPIO 25 ve 26)Yok (PWM kullanılır)

Okunan ADC değerini volta çevirme formülü

ADC'nin verdiği sayı tek başına bir anlam taşımaz; onu gerilime çevirmek için referans gerilimini ve basamak sayısını kullanırsın: Gerilim = ADC değeri × Vref / 2^N. Arduino Uno'da bu V = değer × 5,0 / 1024 olur; analogRead() 512 döndürdüyse pindeki gerilim 512 × 5 / 1024 = 2,50 V'tur. Ters yönde, belirli bir gerilimin hangi sayıya karşılık geleceğini değer = V × 1024 / Vref ile bulursun: 3,3 V, Uno'da yaklaşık 675 olarak okunur. Birçok örnekte 1024 yerine 1023'e bölündüğünü görürsün. ATmega328P'nin veri sayfası ADC = Vin × 1024 / Vref formülünü verir; en büyük değer olan 1023, Vref'in bir basamak altını temsil eder. 1023'e bölmek en üst değeri tam 5,00 V gösterir ama bütün değerleri yaklaşık %0,1 kaydırır. Bu fark ADC'nin kendi ±2 LSB'lik hatasından küçüktür, yani ikisi de iş görür; önemli olan projede tutarlı olmaktır. Asıl büyük hata kaynağı Vref'in kendisidir: USB'den beslenen bir Uno'nun 5V pini çoğu zaman 4,7 ile 5,1 V arasındadır ve formüle 5,0 yazmak %5'e varan hata yaratır. Bu yüzden hassas ölçümlerde 5V pinini multimetreyle ölçüp gerçek değeri koda yaz. ESP8266'nın tek analog girişi (A0) de 10 bittir; yonganın kendisi 0–1 V ölçer, NodeMCU ve Wemos D1 Mini gibi kartlardaki dahili bölücü bu aralığı yaklaşık 0–3,2 V'a genişletir.

Kart ve ayarOkunan aralıkVolta çevirmeÖrnek
Arduino Uno / Nano (DEFAULT, 5 V)0–1023V = değer × 5,0 / 1024768 → 3,75 V
Uno, analogReference(INTERNAL)0–1023V = değer × 1,1 / 1024512 → 0,55 V
ESP32 (11 dB)0–4095Kalibre: analogReadMilliVolts() / 1000; kaba: değer × 3,3 / 40951650 mV → 1,65 V
Raspberry Pi Pico (read_u16)0–65535V = değer × 3,3 / 6553532768 → 1,65 V
ESP8266 NodeMCU / Wemos D1 Mini (A0)0–1023V = değer × 3,2 / 1024512 → 1,60 V

Potansiyometre bağlantısı: Arduino, ESP32 ve Pico

Potansiyometre bacağıArduino UnoESP32Raspberry Pi Pico
Kenar bacak 15V3V33V3(OUT) (pin 36)
Orta bacak (sinyal)A0GPIO 34 (ADC1_CH6)GP26 / ADC0 (pin 31)
Kenar bacak 2GNDGNDAGND (pin 33) ya da GND
İsteğe bağlı gürültü kondansatörüA0 ile GND arasına 100 nFGPIO 34 ile GND arasına 100 nFGP26 ile AGND arasına 100 nF
ESP32 ve Raspberry Pi Pico'nun analog girişleri en fazla 3,3 V kabul eder; potansiyometrenin kenar bacağını 5 V'a bağlamak ya da 5 V çıkışlı bir sensörü doğrudan bağlamak pini kalıcı olarak bozabilir. Uno'da da girişe besleme geriliminden (5 V) yüksek ya da 0 V'tan düşük gerilim verme; daha yüksek gerilimleri bir gerilim bölücüyle indir. Hiçbir şey bağlı olmayan, boşta kalan bir analog pin ise rastgele değerler okur; bu bir arıza değil, pinin "havada" olmasıdır.

Adım adım: Arduino ile ilk ADC okuması

  1. Devreyi kur: 10 kΩ'luk bir potansiyometrenin kenar bacaklarını 5V ve GND'ye, orta bacağını A0'a bağla.
  2. 5V pinini ölç: Multimetreyle 5V ile GND arasındaki gerilimi ölç ve koddaki VREF sabitine yaz (ör. 4.93).
  3. Kodu yükle: Aşağıdaki kodu Arduino IDE'de aç, kartı ve portu seçip yükle.
  4. Serial Monitor'ü aç: Hızı 9600 baud yap ve düğmeyi çevirdikçe ADC değerinin 0 ile 1023 arasında değiştiğini izle (ayrıntılar Serial Monitor rehberinde).
  5. Doğrula: Multimetreyle A0 ile GND arasını ölç ve ekrandaki gerilimle karşılaştır; fark 10–20 mV civarında kalmalı.
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() ölçümü yaklaşık 100 µs'de tamamlar ve 0–1023 arasında bir tam sayı döndürür. Kod bu sayıyı önce formülle volta, sonra map() ile yüzdeye çevirir. map() tam sayı aritmetiği kullandığı için kesirli kısmı atar; ondalıklı bir sonuç gerekiyorsa hesabı float ile kendin yap. Bu ölçüm oransal (ratiometric) bir ölçümdür: potansiyometre de ADC de aynı 5 V'tan beslendiği için besleme 4,9 V'a düşse bile düğmenin konumu, yani ADC değeri değişmez; değişen yalnızca hesaplanan gerilimdir. LDR ve NTC gibi bölücüyle okunan sensörlerde de durum aynıdır. Buna karşılık bir pilin gerilimini ya da LM35 gibi sabit mV çıkışlı bir sensörü ölçerken Vref'in gerçek değeri doğrudan sonuca yansır.

Referans gerilimi ve analogReference

Referans gerilimi (Vref), ADC ölçeğinin en üst noktasıdır: girişteki gerilim Vref'e eşitse ya da onu aşarsa sonuç en büyük değerde (1023) takılır. Vref'i küçültmek ölçüm aralığını daraltır ama her basamağı küçültür, yani küçük sinyalleri daha ince ölçersin. Arduino Uno'da referansı analogReference() fonksiyonuyla seçersin. INTERNAL seçeneğinde Vref 1,1 V olur ve bir basamak 1,07 mV'a iner; 10 mV/°C veren bir LM35'i yaklaşık 0,1 °C adımlarla okuyabilirsin, karşılığında 1,1 V'un, yani 110 °C'nin üstü ölçülemez. Dahili 1,1 V referansın kendisi yongadan yongaya 1,0 ile 1,2 V arasında değişebilir, bu yüzden hassas projelerde bir kez multimetreyle kalibre etmek gerekir. Referans değiştikten sonraki ilk birkaç okuma hatalı olabilir; Arduino'nun belgeleri de bunu belirtir, bu yüzden referansı değiştirdikten sonra birkaç okumayı atmak iyi bir alışkanlıktır. Ayrıca referans ayarı kartın bütün analog pinlerini birlikte etkiler. Seçenekler karta göre farklıdır:

SeçenekReferansKartlarNe zaman kullanılır?
DEFAULT5 V (3,3 V'luk kartlarda 3,3 V)Uno, Nano, Mega, LeonardoPotansiyometre, LDR, joystick gibi beslemeyle oransal sensörler
INTERNAL1,1 V (ATmega328P); Leonardo'da 2,56 VUno, Nano, Leonardo (Mega'da yok)LM35 gibi küçük gerilimli sensörler
INTERNAL1V1 / INTERNAL2V561,1 V / 2,56 VYalnız MegaMega'da küçük sinyaller
EXTERNALAREF pinindeki gerilim (0–5 V)Uno, Nano, MegaKendi hassas referansını (ör. 2,5 V ya da 4,096 V) kullanmak
AR_INTERNALYaklaşık 1,43 V (yonganın iç referansı)Uno R4 Minima ve WiFiUno R4'te küçük sinyaller
AREF pinine harici bir referans bağladıysan, analogRead()'i çağırmadan önce analogReference(EXTERNAL) yazmalısın. Aksi halde yonganın içinde üretilen referans AREF pinindeki gerilimle kısa devre olur ve mikrodenetleyici zarar görebilir. Referanslar arasında geçiş yapacaksan harici gerilimi AREF'e 5 kΩ'luk bir dirençle bağla; pinin içindeki yaklaşık 32 kΩ'luk dirençle bölücü oluşacağı için AREF'teki gerilimin biraz düşeceğini (2,5 V için yaklaşık 2,2 V) hesaba kat. AREF'e asla 0 V'tan düşük ya da 5 V'tan yüksek gerilim verme.

Örnekleme hızı: ADC saniyede kaç ölçüm yapar?

Örnekleme hızı, ADC'nin bir saniyede kaç ölçüm alabildiğidir. Arduino Uno'da ADC saati 16 MHz'in 128'e bölünmesiyle 125 kHz'e ayarlanır ve bir dönüşüm 13 saat çevrimi sürer; analogRead() bu yüzden yaklaşık 100 µs alır ve saniyede en fazla 10.000 civarında ölçüm yapılabilir. Sıcaklık, ışık ya da pil gerilimi gibi yavaş değişen büyüklükler için bu fazlasıyla yeterlidir; saniyede 10 ölçüm bile çoğu zaman yeter. Hızlı sinyallerde ise Nyquist kuralı devreye girer: bir sinyali kaybetmeden yakalamak için en yüksek frekansının en az iki katı hızda örneklemen gerekir, pratikte 5–10 katı tercih edilir. 50 Hz'lik şebeke uğultusunu görmek için en az 100 ölçüm/s, 4 kHz'e kadar konuşma sesini kaydetmek için en az 8.000 ölçüm/s gerekir. Daha hızlı ölçüm gerekiyorsa Uno'da ADC'nin ön bölücüsünü küçültebilirsin: setup() içine ADCSRA = (ADCSRA & 0xF8) | 0x04; yazınca bölücü 16 olur, ADC saati 1 MHz'e çıkar ve analogRead() yaklaşık 16 µs'ye iner; bunun bedeli bir miktar doğruluk kaybıdır. ESP32'de tek tek analogRead() çağrıları saniyede on binlerce ölçüme izin verir, DMA kullanan sürekli modda (Arduino'da analogContinuous()) ise 20 kHz ile 2 MHz arasında bir hız seçilebilir; bu mod yalnızca ADC1 pinleriyle çalışır. Raspberry Pi Pico'nun ADC'si 48 MHz'lik ayrı bir saatle her ölçümü 96 çevrimde, yani 2 µs'de bitirir ve saniyede 500.000 ölçüme ulaşır; MicroPython'daki bir döngü bu hıza yetişemez, tam hız için C SDK ve DMA gerekir.

ESP32 ADC: doğrusal olmama, ADC2 ve Wi-Fi çakışması, attenuation

ESP32'nin 12 bitlik ADC'si kâğıt üzerinde Uno'dan dört kat ince ölçer, ama pratikte üç konuya dikkat etmen gerekir. Birincisi doğrusal olmama: ESP32'nin ADC'si 0 V'a yakın bölgede yaklaşık 100–150 mV'a kadar 0 okur, üst uçta ise giriş 3,3 V'a ulaşmadan 4095'e doyar; aradaki eğri de tam bir doğru değildir. İkincisi referans sapması: ESP32'nin iç referansı tasarımda 1100 mV'tur, ama Espressif'e göre yongadan yongaya 1000 ile 1200 mV arasında değişir; bu, kalibrasyonsuz okumada yaklaşık ±%9'luk bir hata demektir. Espressif bu yüzden yongalara üretimde kalibrasyon verisi (eFuse) yazar. Arduino'daki analogReadMilliVolts() fonksiyonu bu veriyi kullanarak ham değeri doğrudan kalibre edilmiş milivolta çevirir ve çoğu durumda analogRead() × 3,3 / 4095 hesabından çok daha doğru sonuç verir. Üçüncüsü zayıflatma (attenuation): ADC'nin çekirdeği yaklaşık 1 V'a kadar ölçebilir; daha yüksek gerilimler girişteki ayarlanabilir bir zayıflatıcıyla küçültülür. Arduino'da varsayılan ayar 11 dB'dir ve yaklaşık 3,1 V'a kadar okumaya izin verir, ama Espressif'in bu ayar için önerdiği doğru ölçüm aralığı 150–2450 mV'tur. Küçük sinyallerde zayıflatmayı düşürmek hem doğruluğu hem de çözünürlüğü artırır:

ZayıflatmaArduino sabitiDoğru ölçüm aralığıKullanım
0 dBADC_0db100–950 mVKüçük sinyaller, en ince ölçüm
2,5 dBADC_2_5db100–1250 mV1 V civarındaki sensör çıkışları
6 dBADC_6db150–1750 mVOrta seviye sinyaller
11 dB (varsayılan)ADC_11db150–2450 mV (okuma yaklaşık 3,1 V'a kadar sürer)Potansiyometre ve 0–3,3 V sensörler
ESP32'de ADC2'yi Wi-Fi sürücüsü de kullanır. Wi-Fi başlatıldıktan sonra ADC2 pinlerinden (GPIO 0, 2, 4, 12, 13, 14, 15, 25, 26, 27) okuma yapılamaz; ESP-IDF bu durumda zaman aşımı hatası (ESP_ERR_TIMEOUT) döndürür, Arduino çekirdeğinin güncel sürümlerinde analogRead() de 0 verir. Wi-Fi'li projelerde analog sensörleri her zaman ADC1 pinlerine bağla: GPIO 32, 33, 34, 35, 36 (VP) ve 39 (VN). Bunlardan 34–39 yalnızca giriş olarak çalışır ve dahili pull-up dirençleri yoktur, bu da onları analog okuma için ideal yapar. GPIO 0, 2, 12 ve 15 ayrıca açılış (boot) pinleri olduğu için analog sensöre hiç uygun değildir.
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}

Kod iki sonucu yan yana gösterir: ham değeri basit formülle çeviren hesap ve analogReadMilliVolts()'un kalibre ettiği değer. Potansiyometreyi uçlara doğru çevirdikçe aradaki farkın büyüdüğünü, en altta formülün 0,000 V gösterdiği yerde multimetrenin hâlâ 0,1 V civarı ölçtüğünü fark edeceksin. analogSetPinAttenuation() zayıflatmayı yalnız bir pin için, analogSetAttenuation() ise bütün pinler için değiştirir. ESP32'de gürültü Uno'dan belirgin şekilde fazladır, özellikle Wi-Fi yayın yaparken; Espressif'in önerisi de girişe 100 nF'lık bir kondansatör eklemek ve birden çok örneğin ortalamasını almaktır, koddaki 16 ölçümlük ortalama bunu yapar. ESP32-S3 ve ESP32-C3 gibi daha yeni yongalarda kalibrasyon daha gelişmiş bir eğri uydurma yöntemiyle yapılır, ama pin numaraları ve ADC2 kuralları modele göre değiştiği için kartının pin haritasına mutlaka bak (Pinout aracı). 3,3 V'tan yüksek gerilimleri ölçmek için bölücü kurmayı gerilim bölücü yazısında anlatıyoruz.

Raspberry Pi Pico ile ADC (MicroPython)

Raspberry Pi Pico'da dışarıdan kullanılabilen üç analog giriş vardır: GP26 (ADC0), GP27 (ADC1) ve GP28 (ADC2). GP29 (ADC3) kart üzerinde VSYS besleme geriliminin üçte birini ölçer, ADC4 ise yonganın içindeki sıcaklık sensörüne bağlıdır. MicroPython'daki read_u16() fonksiyonu 12 bitlik sonucu 0–65535 aralığına ölçekler; böylece aynı kod farklı kartlarda çalışır, ama gerçek çözünürlük yine 4096 basamaktır. RP2040'ın ayrı bir referans gerilimi yoktur, kendi ADC beslemesini referans alır. Pico'da bu besleme (ADC_VREF, pin 35), 3,3 V'luk anahtarlamalı regülatörün (SMPS) çıkışı yaklaşık 200 Ω'luk bir dirençle süzülerek elde edilir. Raspberry Pi'nin kart belgesi bunun üç sonucunu açıkça yazar: 3,3 V'un doğruluğu sınırlıdır, besleme biraz gürültülüdür ve ADC'nin çektiği akım yüzünden yaklaşık 30 mV'luk bir ofset oluşur. Çözümler de aynı belgededir: GP23'ü HIGH yaparak regülatörü daha az dalgalanan PWM moduna almak, kullanılmayan bir ADC kanalını AGND'ye bağlayıp okuduğun değeri ofset olarak çıkarmak ve çok daha iyi doğruluk için ADC_VREF ile AGND arasına LM4040 gibi 3,0 V'luk bir referans bağlamak (bu durumda ölçüm aralığı 0–3,0 V olur). Ayrıca RP2040'ın ADC'sinde 512, 1536, 2560 ve 3584 değerlerinde küçük sıçramalar (DNL hatası) olduğu bilinir; birden çok ölçümün ortalamasını almak bunların etkisini azaltır. Pico W'de GP23 kablosuz yongaya ayrıldığı için regülatör modu WL_GPIO1 üzerinden kontrol edilir; aşağıdaki kodda GP23 satırlarını Pico W'de sil.

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)

ADC gürültüsünü azaltma yöntemleri

Sabit bir gerilimi ölçerken bile ADC değerinin bir iki basamak oynaması normaldir; nicemleme, besleme hattındaki dalgalanma, uzun kabloların topladığı parazit ve yakındaki motor ya da Wi-Fi yayınları buna katkı yapar. Uno'da ±1–2 basamaklık oynama sağlıklı sayılır; çok daha fazlası genellikle devrede bir sorun olduğunu gösterir. Gürültüyle hem donanımda hem yazılımda mücadele edebilirsin:

  • Kondansatör ekle: Analog pin ile GND arasına konan 100 nF'lık seramik kondansatör hızlı parazitleri süzer ve yüksek dirençli kaynaklarda örnekle-tut kondansatörüne hazır yük sağlar.
  • Kabloları kısa tut: Sensör kablosu uzunsa sinyal ve GND kablolarını birbirine sar; motor ve röle kablolarını analog hatlardan uzak geçir.
  • Topraklamayı düzgün yap: Motor, röle ve LED şeridi gibi yüksek akım çeken yüklerin dönüş akımı sensörün GND kablosundan geçmesin; toprakları tek bir noktada birleştir (yıldız topraklama).
  • Temiz bir referans kullan: USB beslemesi gürültülüdür; mutlak gerilim ölçümlerinde dahili referans ya da harici bir referans entegresi daha kararlı sonuç verir.
  • Kanal değiştirince ilk okumayı at: ADC'nin girişindeki çoklayıcı (multiplexer) bir önceki kanalın yükünü taşıyabilir; birden çok pini sırayla okurken her pinde bir okumayı boşa harca.
  • Ortalama al: N ölçümün ortalaması rastgele gürültüyü yaklaşık √N kat azaltır; 16 ölçüm gürültüyü dörtte birine indirir.
  • Aşırı örnekleme (oversampling): 4^n ölçümü toplayıp sonucu n bit sağa kaydırırsan n bit fazladan çözünürlük kazanırsın; 16 ölçümün toplamını 2 bit kaydırmak Uno'nun 10 bitini 12 bite çıkarır. Bunun işe yaraması için sinyalde en az bir basamaklık doğal gürültü bulunmalıdır.
  • Medyan ve üstel ortalama filtresi: Medyan filtresi motor kaynaklı ani sıçramaları atar, üstel hareketli ortalama (EMA) ise çok az bellekle yumuşak bir eğri verir.
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}

Kodu yükleyip Arduino IDE'deki Serial Plotter'ı açtığında üç çizgi görürsün: ham değer titrer, 16 ölçümün ortalaması belirgin şekilde sakinleşir, EMA ise en yumuşak ama değişime biraz geç tepki veren eğridir. ALPHA katsayısı 0 ile 1 arasında seçilir: 0,1 her yeni ölçümün sonuca %10 oranında katıldığı, kabaca son 10 ölçümün etkili olduğu bir filtre demektir; değeri büyütürsen tepki hızlanır ama gürültü artar. Hangi filtreyi seçeceğin sinyale bağlıdır; yavaş değişen bir sıcaklık için güçlü bir EMA, hızlı tepki gereken bir joystick için kısa bir ortalama daha uygundur. Hareketli ortalama, medyan filtre ve histerezisi gerçek sensör örnekleriyle sensör verisi filtreleme yazısında karşılaştırıyoruz.

DAC'a kısa giriş: dijitalden analoğa dönüşüm

DAC (Dijital-Analog Dönüştürücü) ADC'nin tersini yapar: bir sayıyı alır ve onunla orantılı bir gerilim üretir. 8 bitlik bir DAC'a 0 yazarsan 0 V, 255 yazarsan besleme gerilimine yakın bir değer, 128 yazarsan bunun yaklaşık yarısını elde edersin. En basit DAC'lar R-2R adı verilen bir direnç merdiveniyle yapılır. Burada sık karıştırılan bir noktayı netleştirelim: Arduino Uno'daki analogWrite() bir DAC değildir, PWM üretir; pin aslında 0 V ile 5 V arasında hızla açılıp kapanır. LED parlaklığı ve motor hızı için bu yeterlidir, ama gerçekten sabit bir gerilim gerekiyorsa PWM çıkışına bir RC alçak geçiren filtre eklemen gerekir; filtrenin zaman sabitini RC zaman sabiti aracıyla hesaplayabilirsin. Gerçek DAC'ı olan kartlara gelince: ESP32'de GPIO 25 ve GPIO 26'da iki adet 8 bitlik DAC vardır ve dacWrite(pin, değer) ile kullanılır; ESP32-S3 ve ESP32-C3'te ise DAC yoktur. Arduino Uno R4'ün A0 pininde 12 bitlik bir DAC bulunur. Uno R3, Nano ve Pico için en kolay yol I2C ile bağlanan 12 bitlik MCP4725 modülüdür. DAC ile ses üretebilir, sinüs ya da üçgen dalga çıkarabilir, hatta DAC çıkışını bir ADC girişine bağlayıp ADC'yi bilinen gerilimlerle test edebilirsin:

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}

ADC ile proje fikirleri

  • Dijital voltmetre: Gerilim bölücüyle 0–25 V arasını ölçüp sonucu LCD'de göster; adımlar Arduino voltmetre yapımı yazısında.
  • Otomatik gece lambası: LDR'nin gerilimini oku, ortam kararınca LED'leri yak.
  • Akıllı saksı: Toprak nem sensörünün analog çıkışıyla toprak kuruyunca pompayı çalıştır.
  • Joystick kontrollü robot: Joystick'in iki ekseni iki ayrı analog giriştir; değerleri motor hızına ve yönüne çevir.
  • Akım ölçer: ACS712'nin akımla orantılı gerilimini okuyarak bir cihazın ne kadar akım çektiğini gör.
  • Ses seviyesi göstergesi: KY-038 ses sensörünün analog çıkışını hızlı örnekle, tepe değerine göre bir LED çubuğu yak.
  • Pil göstergesi: Pilli bir projede gerilimi ölç ve kalan şarjı yüzde olarak ekranda göster.

Sık yapılan hatalar ve çözümleri

BelirtiOlası sebepÇözüm
Hiçbir şey bağlı değilken değer rastgele oynuyorPin boşta (floating)Sensörü bağla; kullanmadığın pinleri okuma ya da GND'ye çek
Değer 1023'te (ESP32'de 4095'te) takılı kalıyorGiriş referansın üstünde ya da INTERNAL seçiliReferansı ya da zayıflatmayı ayarla, yüksek gerilimi bölücüyle indir
ESP32'de Wi-Fi açılınca analogRead() 0 dönüyorSensör bir ADC2 pinine bağlıGPIO 32–39 arasındaki ADC1 pinlerini kullan
ESP32 küçük gerilimlerde 0, büyüklerde 4095 gösteriyorADC uçlarda doğrusal değilanalogReadMilliVolts() kullan, sinyali 150–2450 mV aralığında tut
Hesaplanan gerilim multimetreden %3–5 farklıVref 5,00 V değil (USB beslemesi)5V pinini ölçüp VREF'e yaz ya da kalibrasyon katsayısı ekle
İki pini sırayla okurken değerler birbirini etkiliyorÇoklayıcı ve yüksek kaynak direnciKanal değişince ilk okumayı at, kaynağı 10 kΩ'un altında tut, 100 nF ekle
Motor ya da röle çalışınca değerler zıplıyorOrtak GND hattında gürültü, besleme çöküyorYüklerin GND'sini ayrı hattan getir, kondansatör ve medyan filtre kullan
AREF'e gerilim verdikten sonra okumalar bozulduanalogReference(EXTERNAL) çağrılmadan AREF kullanıldıÖnce EXTERNAL seç ya da AREF'e 5 kΩ'luk dirençle bağlan
INTERNAL seçtikten sonra potansiyometre yarıda 1023 oluyor1,1 V referans bütün analog pinleri etkilerOransal sensörleri okumadan önce DEFAULT'a dön ve birkaç okumayı at
Pico'da giriş GND'deyken bile 0'dan büyük değer okunuyorADC ofseti ve ADC_VREF gürültüsüBir kanalı AGND'ye bağlayıp ofseti ölç ve çıkar, GP23'ü HIGH yap
Bir ADC devresini doğrulamanın en hızlı yolu bilinen bir gerilimi ölçmektir. Önce analog girişi GND'ye bağla ve 0'a yakın bir değer gör. Sonra gerilimini multimetreyle ölçtüğün bir kalem pilin eksisini GND'ye, artısını analog pine bağla: yaklaşık 1,5 V için Uno'da 307 civarı, ESP32'de analogReadMilliVolts() ile 1500 mV civarı, Pico'da read_u16() ile 29.800 civarı görmelisin. Sonuç tutuyorsa kodun ve bağlantın doğrudur; tutmuyorsa sorun büyük ihtimalle referans geriliminde ya da ortak GND'dedir.

ADC, fiziksel dünya ile kodun arasındaki köprüdür: çözünürlüğü, referans gerilimini ve örnekleme hızını bildiğinde ekranda gördüğün her sayının neyi temsil ettiğini ve ne kadar güvenilir olduğunu da bilirsin. Uno'da referansı doğru ölç, ESP32'de ADC1 pinlerini ve analogReadMilliVolts()'u kullan, Pico'da ofseti ve gürültüyü hesaba kat; sonra ortalama ve filtrelerle sonucu sakinleştir. BlueGrays uygulamasında LDR ile ışık şiddeti okuma, LCD ekranlı dijital voltmetre, NTC ile sıcaklık ölçümü, potansiyometreyle servo ve LED parlaklığı kontrolü gibi analog okumaya dayanan projeleri devre şemaları ve kodlarıyla adım adım bulabilirsin.

Sıkça sorulan sorular

ADC nedir ve ne işe yarar?

ADC (Analog-Dijital Dönüştürücü), bir pindeki gerilimi mikrodenetleyicinin işleyebileceği bir sayıya çeviren devredir. Potansiyometre, LDR, sıcaklık ve nem sensörleri gibi analog çıkış veren parçaları okumak için kullanılır. Arduino'da analogRead() komutu bu dönüştürücüyü çalıştırır.

Analog ve dijital sinyal arasındaki fark nedir?

Analog sinyal bir aralıktaki her değeri alabilir ve kesintisiz değişir; dijital sinyal ise yalnızca belirli seviyelerden, Arduino'da LOW ve HIGH'tan oluşur. digitalRead() bir pinin yalnızca 0 mı 1 mi olduğunu söyler, analogRead() ise gerilimin ne kadar olduğunu bir sayıyla verir.

Arduino analogRead neden 0 ile 1023 arasında değer verir?

Arduino Uno'nun ADC'si 10 bittir ve 2^10 = 1024 farklı basamak üretir; bu basamaklar 0'dan 1023'e numaralandırılır. 0 değeri 0 V'u, 1023 ise referans geriliminin (genellikle 5 V) bir basamak altını temsil eder. ESP32 ve Pico'nun 12 bitlik ADC'leri ise 0–4095 arası değer verir.

ADC değeri volta nasıl çevrilir?

Gerilim = ADC değeri × referans gerilimi / basamak sayısı formülünü kullan. Arduino Uno'da V = değer × 5,0 / 1024 olur; ESP32'de analogReadMilliVolts() doğrudan kalibre edilmiş milivolt verir. Pico'da MicroPython'un read_u16() değeri için V = değer × 3,3 / 65535 kullanılır.

ESP32 ADC2 pinleri Wi-Fi ile çalışır mı?

Hayır. ESP32'de ADC2 birimini Wi-Fi sürücüsü de kullandığı için Wi-Fi açıkken ADC2 pinlerinden (GPIO 0, 2, 4, 12–15, 25–27) okuma yapılamaz. Wi-Fi'li projelerde analog sensörleri ADC1 pinlerine (GPIO 32–39) bağla.

DAC nedir, ADC'den farkı ne?

DAC (Dijital-Analog Dönüştürücü) ADC'nin tersini yapar: bir sayıyı gerilime çevirir. ADC bir sensörden gelen gerilimi ölçmek, DAC ise ses ya da sinyal gibi bir gerilim üretmek için kullanılır. Arduino Uno'da DAC yoktur ve analogWrite() PWM üretir; ESP32'de GPIO 25 ve 26'da 8 bitlik iki DAC, Uno R4'te ise A0'da 12 bitlik bir DAC bulunur.

Tüm projeleri gör
Ldr İle Işık Şiddeti Okuma
#11Başlangıç

Ldr İle Işık Şiddeti Okuma

Odanın ne kadar aydınlık olduğunu sayıyla görmek ister misin? Işığa duyarlı küçük bir parça olan LDR ortam ışığını ölçer ve Arduino bu değeri yarım saniyede bir bilgisayar ekranına yazar. Elinle üstün

4.6(81)
139
LCD Ekran ile Dijital Voltmetre
#56Orta
Premium

LCD Ekran ile Dijital Voltmetre

Pilin ya da adaptörün ne kadar gerilim verdiğini kendi yaptığın ölçü aletiyle öğren. İki dirençten oluşan bir bölücü yüksek gerilimi kartın okuyabileceği seviyeye indirir, Arduino da gerçek değeri hes

4.5(27)
36
ESP32 LDR Modülü ile Işık Şiddeti Okuma
#113Başlangıç

ESP32 LDR Modülü ile Işık Şiddeti Okuma

LDR modülünün ham ADC değerini ve karanlık/aydınlık referanslarına göre hesaplanan göreli ışık yüzdesini Serial Monitor'da gerçek zamanlı izleme. Bu yüzde lux ölçümü değildir. Modülün kalibrasyon mantığını öğretir. Proje 10'un öncesinde yapılması ideal; çünkü eşik değerini belirlemek için kullanılır.

4.6(36)
55
ESP32 Potansiyometre ile LED Parlaklık (Analog → PWM)
#115Orta
Premium

ESP32 Potansiyometre ile LED Parlaklık (Analog → PWM)

Bu projede bir potansiyometre ile LED parlaklığını analog olarak kontrol ediyoruz. ESP32'nin ADC pini potansiyometreden gelen 0-3.3V gerilimi okur, ardından bu değer PWM (Pulse Width Modulation) sinyaline çevrilerek LED'e gönderilir. Böylece potansiyometreyi çevirdikçe LED kademeli olarak parlar ve söner. Arduino Core 3.0+ ile analogWrite() doğrudan kullanılabilir; ESP32-S2/S3'te ADC çözünürlüğü 12-bit'e sabitlenir.

4.5(19)
32
NTC ve 2x16 Lcd Ekran İle Sıcaklık Ölçümü
#44Başlangıç
Premium

NTC ve 2x16 Lcd Ekran İle Sıcaklık Ölçümü

Ortamın sıcaklığını küçük bir boncuk gibi görünen sensörle ölç. NTC adlı bu parça ısındıkça elektriği daha kolay geçirir; Arduino bu değişimi okuyup bir formülle santigrat dereceye çevirir ve iki satı

4.5(33)
44
Potansiyometre İle Servo Motor Kullanım
#36Başlangıç
Premium

Potansiyometre İle Servo Motor Kullanım

Potansiyometrenin düğmesini çevirdikçe servo motorun kolu da onunla birlikte döner; düğmenin bir ucu sıfır dereceye, öbür ucu yarım tura karşılık gelir. Arduino düğmenin konumunu sürekli okur ve servo

4.6(37)
52
Joystick İle Led Kontrol
#59Orta
Premium

Joystick İle Led Kontrol

Oyun kolundaki küçük çubuğu hangi yöne sonuna kadar itersen o yöndeki LED yanar: sağ, sol, yukarı ve aşağı için dört ayrı renk var. Çubuğu bıraktığında ortaya döner ve bütün LED'ler söner. Robot araba

4.7(50)
67
ESP32 Renk Mikser Lambası (3 Pot + RGB LED + OLED)
#138İleri
Premium

ESP32 Renk Mikser Lambası (3 Pot + RGB LED + OLED)

ESP32 ile 3 potansiyometre çevirerek istediğin rengi karıştıran akıllı bir renk mikser lambası! Kırmızı, yeşil ve mavi potansiyometreleri çevirdikçe ortak katot RGB LED anlık olarak renk değiştirir. SSD1306 OLED ekranda her renk için 0-255 aralığında değer, görsel dolgu barları ve HEX web renk kodu (#FF8040 gibi) canlı olarak gösterilir. Mini bir profesyonel renk stüdyosu — RGB renk teorisi, ADC analog okuma, PWM ile parlaklık kontrolü ve I2C ekran tasarımını tek projede öğretir. Grafik tasarımc

4.7(6)
10