C ile AVR Programlama -17- ADC Kullanımı ve Örnek Kodlar

Önceki yazılarda ADC birimini anlatmış ve ADC’nin görevlerinden bahsetmiştik. Teknik veri kitapçığında yer alan yazmaçları anlatmış ve bu yazmaçların ve yazmaçlardaki bitlerin görevlerini ayrıntılı açıklamıştık. Şimdi ise C dilinde bu yazmaçları nasıl kontrol ederek ADC birimini çalıştıracağımızı anlatalım.

ADC işlemini adım adım anlatmak gerekirse şu şekilde olmalıdır,

  • Seçili ADC kanal ayağını giriş olarak tanımlamalıdır.
  • AVR’nin ADC modülü faal hale getirilmelidir. Çünkü açılış resetinde güç tüketimini önlemek için devre dışıdır.
  • Çevirim hızı seçilir. ADPS2:0 bitleri bu işlemi yapar.
  • ADC giriş kanallarındaki gerilim referansı seçilir. ADMUX yazmacındaki REFS0 ve REFS1 bitleri referans seçmek için görevlidir. ADMUX yazmacındaki MUX4:0 bitleri ise ADC giriş kanalını seçmeye yarar.
  • ADCSRA yazmacındaki ADSC biti HIGH yapılarak çevirim başlatılır.
  • ADCSRA yazmacındaki ADIF yani ADC kesme bayrağı biti kontrol edilerek çevirimin bitmesi beklenir.
  • ADIF biti HIGH konuma geçtikten sonra ADCL ve ADCH yazmaçlarındaki dijital veri çıkışı okunur. Öncelikle ADCL yazmacını sonrası ADCH yazmacını okumak gereklidir.

İşte AVR mikrodenetleyicilerde ADC okuma işlemleri bu şekilde olmaktadır. Elimizin altında bir makina var ve bu makinayı talimatına uygun kullanıp analog değerden dijital değeri elde etmemiz gereklidir. Bu talimatları üretici bize bildirmektedir ve bunun mantığını ve iç yapısını bu noktadan sonra anlatmamız pek mümkün değildir. Çünkü üretici mikrodenetleyici ve çevre birimlerinin bizim için gerekli kısmını teknik veri sayfasında paylaşmaktadır. Daha alt seviyeye inerek konu dışına çıkmış oluruz. İnşallah ileride mikrodenetleyici mimarisini ve dijital elektroniği anlattığımız derslerde buna değineceğiz. Şimdilik yazmaç boyutuna insek dahi biraz ezbere işlem yapmak zorundayız.

Şimdi elimdeki örnek kodlardan dersi anlatmaya devam edelim. C dilinde oluşturduğumuz iki fonksiyonumuz var. Bunlardan biri ADC’yi başlatan ve diğeri ise ADC çevirimi yapıp sonucu geri döndüren asıl fonksiyon olarak görev yapıyor. Öncelikle adc_init() fonksiyonunu yazmaçlar üzerinden anlatarak nasıl çalıştığını anlatalım.

ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); Bu komutta ADCSRA yazmacının ilk üç biti olan ADPS0, ADPS1 ve ADPS2 bir (1) yapılır. ADC saati için ön derecelendirici ayarı ile 16Mhz/128 yani 125KHz ADC referans saati ayarlanmış olur. İşlemci 16MHz’de çalışırken ADC 50kHz ile 200kHz arası çalışmaktadır. O yüzden işlemcinin saat hızı ön derecelendirici (prescaler) ile bölünmelidir. Yüksek frekans hızlı ölçüm fakat düşük doğruluk verir. Düşük frekans ise yavaş ölçüm ve yüksek doğruluk. İhtiyaca göre bölme oranı belirlenmelidir.

ADMUX |= (1<<REFS0); ADC’nin hangi gerilim değerini esas alarak ölçüm yapacağını belirler. ADC yazmaçlarını anlatırken 1.1V, Harici ya da Besleme olarak üç ayrı referans gerilimi alabileceğinden bahsetmiştik. Burada REFS0 bitini bir (1) yaparak referans gerilimini besleme gerilimi yapıyoruz. Yani 0-5V arası 0-1023 farklı değer elde edeceğiz.

ADCSRA |= (1<<ADEN); ADC’yi açıyoruz. ADC açılıştan itibaren kapalı olup boş yere çalışmaz. O yüzden ADC’yi kullanmak üzere şimdi açıyoruz. Bu bit bir makinanın açma kapama düğmesi gibi düşünülebilir. ADEN bitini bir (1) yaparak ADC’yi çalışır hale getirdik.

ADCSRA |= (1<<ADSC);  ADSC biti bir (1) yapılarak bir deneme çevirimi başlatılır. Buradaki amaç birimi bir sonraki çevirime hazırlamaktır. İlk çevirim yavaş olduğu için ilk çevirimi burada yaptık.

ADMUX &= 0xF0;  ADMUX yazmacının gerekli kısımlarını bir sonraki kanal bilgisi yazılmak üzere temizliyoruz. Her çevirimden önce hangi ayaktan ADC bilgisinin okunacağı belirlenmelidir. Bunu da fonksiyon byte değerinden (uint8_t) argüman alarak bir sonraki kodda işletecektir.

ADMUX |= channel;  ADMUX yazmacına kanal numarası(yani ayak numarası 0, 1, 2.. vd.) yazılır. Böylelikle hangi ayaktan analog okuma yapacağımızı belirlemiş oluruz.

ADCSRA |= (1<<ADSC);  ADCSRA yazmacındaki ADSC biti bir (1) yapılarak yeni çevirim başlatılır. Artık çevirimin bitmesini ve değer okumayı bekleyeceğiz.

while(ADCSRA & (1<<ADSC));  ADCSRA yazmacındaki ADSC bayrak biti çevirim bitince bir (1) konumuna geçer. O yüzden bunun bir olmasını bekleyene kadar mikrodenetleyiciyi döngüye sokuyoruz.

return ADCW;  Çevirim bittiğini bayrak bitinden öğrendikten sonra ADCW yani ADCH ve ADCL yazmaçlarının toplamı olan veriyi değer olarak döndürüyoruz. ADCW’in açılımı ADC Word demektir yani 16-bit veriden oluşur. Bu mikrodenetleyicinin teknik veri sayfasında verilmese de kodda yer almaktadır. Bu olmasaydı önce ADCL yazmacındaki veriyi okuyup sonra da ADCH yazmacındaki veriyi 8-bit sola kaydırıp ADCL yazmacındaki veriyi attığımız word tipindeki değişkene atabilirdik.  ADC verisinin atılacağı değişken muhakkak 8 bitten büyük olmalıdır. Bu int (word) olabilir.

ADC hakkında anlatacaklarımızın hepsi bu kadarla sınırlı olmasa da bu kadarı şimdilik yeterlidir. Geri kalanı ilerleyen derslerde başka konular içinde veya ayrı bir konu olarak anlatabiliriz. Şimdilik ADC hakkında yeterli bilgiyi verdiğimize inanıyoruz. Bir sonraki derste görüşmek üzere.

Kaynaklar

ATmega328P – Microchip Technology , http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf, Erişim Tarihi: 19.08.2018

The ADC of the AVR Analog to Digital Conversion, http://maxembedded.com/2011/06/the-adc-of-the-avr/, Erişim Tarihi: 19.08.2018

ADC (Analog To Digital Converter) of AVR Microcontroller, http://extremeelectronics.co.in/avr-tutorials/using-adc-of-avr-microcontroller/, Erişim Tarihi : 19.08.2018

Kapak Resmi, https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/ATmega8_01_Pengo.jpg/1200px-ATmega8_01_Pengo.jpg

UYARI!!

Gökhan Dökmetaş

"Arduino Eğitim Kitabı" ve "Arduino ve Raspberry PI ile Nesnelerin İnterneti" kitaplarının yazarı. Başkent Teknoloji ve Dedektör Merkezi'nde Ar-ge Sorumlusu. Araştırmacı-Yazar.

You may also like...

4 Responses

  1. iskender dedi ki:

    igiyle takipdeyim.. ADCW ün ADCH ile ADCL birleşiminden bahsettiniz. Sanırım Atmel datasheed inde bir kaç adet daha High ve low değerlikli baytlar var aynısını bunlarada uygulayabilirmiyiz. Yoğunluktan olsa gerek return ADCW yaptığınıza göre Fonksiyonda uint16_t read_adc(uint8_t channel){ ile başlamısı gerekirdi. Gerçi denemedim sadece okuyorum..

    Registerlerin çalışma önceliğini bilmiyorum. while(ADCSRA & (1<<ADSC)); satırında ADCSRA registeri yoklandığında (değeri sorgulandığında diyelim) AD convert işlemi clock luk işlem mi yapıyor? Toplamda 25clock ile ilk dönüştürme tamamlanıyorumuş sanıırm.

    Şöyle sormaya çalışayım. while(ADCSRA & (1<<ADSC)); ile dönüştürmenin beklenmesi yerine atıyorum delay_ms(1000); ile beklensede çevrim işi gerçekleşmiş olur mu? Yoksa illa ADCSRA registeri yoklanarak convert işlemini dürtmek gerekiyormu?

    Register komutları işlenmesi ile yazdığımız komutların işlenmesi aynı clock palsi ile paralelmi çalışıyor..

    • Gökhan Dökmetaş dedi ki:

      Şu anlık incelediğim kodlarda sadece ADCW şeklinde ADC için kullanılmış. Zaten çoğu işlem I2C, SPI, UART gibi yerlerde 8-bit üzerinden yapılmaktadır. Gözden kaçan yer düzeltildi.
      while(ADCSRA & (1<<ADSC)); ADSC bayrak bitini denetlemeye yarar sadece. Buraya delay koysan da eğer ADC'nin kesin tamamlanacağı kadar uzunsa sıkıntı olmaz. Fakat bu işi sağlama almak için daha iyi.
      Bu her komut satırının bir saat çevriminde çalışmasını C dili olduğu için iddia edemeyiz.

  2. ali taştan dedi ki:

    Hocam benimde benzer bir sorum olacak.

    “while(ADCSRA & (1<<ADSC)); ADCSRA yazmacındaki ADSC bayrak biti çevirim bitince bir (1) konumuna geçer. O yüzden bunun bir olmasını bekleyene kadar mikrodenetleyiciyi döngüye sokuyoruz. "
    Burada
    işlemci ADC için gerekli ayarlamaları yaptı ve ölçme işlemini başlattı. Ölçme işlemi belirli bir zaman alacak haliyle.
    Bu süre içerisinde işlemci başka komutlar işleyemez mi ? Farklı bir yöntemle bayrak biti kontrol edilemezmi ?
    teşekkürler.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.