Tiny AVR 1 Serisi- ADC

 Birçok modelde iki adet olan ADC birimi bu seride de 10 bit çözünürlüğe sahip. Eskilerle tüm özellikleri aynı değil. Olay sistemi dışında sonuçları belirli aralıklarla sınırlayabildiğimiz çerçeve modu var.

ADC


ADC birimine analog girişler (AINx) ve dahili girişler bağlanabilir. Referans voltajı VDD, VREFA ve INT REF seçilebilir. ADC biriminde ölçümün nasıl yapacağı örnekleme sayısı, gecikmesi gibi ayarlamalar yapılabilir. Sonuçların toplanarak verilmesi gibi seçenekler sunar. Bu ayarlamaları yaptığımız registerleri açıklayarak ilerlemek daha doğru olacak.

CTRLA registerinde bulunan ENABLE ile ADC birimi çalışmaya başlar. Bu bit "0" ise birim enerji harcamaz ve sayacı sıfırlanır. FREERUN ile ilk ölçüm komutu sonrası sürekli olarak çevrim devam eder. RESSEL ile birimin 10-8 bit arası çözünürlük seçimi yapılır.
CTRLB registerinde bulunan SAMPNUM ile sonuçların toplanarak yazılması sağlanabilir.
CTRLC de bulunan PRESC sistem saatinin bölme oranını ayarlayarak çalışma frekansını belirleriz. ADC birimi bu seride 50kHz ile 1.5MHz arası frekansta çalışmaya uygundur. REFSEL ile referans kaynak seçimi yapılır. SAMPCAP referans voltajına bağlı olarak seçim yapılır. 1V üstünde "1" yapılmalıdır.
CTRLD INTDLY ile ADC birimi başlatılırken oluşacak gecikme ayarlanır. ASDV ile ardışık çevrimler arası gecikme değerleri değişken olacak şekilde ayarların. Bu bit "1" yapıldığında SAMDLY birer birer artar. Bu artış 0x00 ile 0x0F arasında sürekli devam eder. Bu sabit frekanslı örneklemeyi önleyerek sinyalden rastgele örnekler almaya yarar. SAMPDLY ile örnekleme arasındaki gecikme belirlenir.
Bir ADC çevrimini gösteren bu şemada başlatma ve örnekleme gecikmesini görebiliriz.

CTRLE ile eski serilerde olmayan bir özellik ayarlanabilir. WINCM ile tablodaki seçenekler arasından seçim yapılır. Çerçeve modu diyeceğim bu seçenekte belirlediğimiz değerlerle çevrim sonu bulunan sonuç karşılaştırılır. Tabloda bulanan seçeneklere göre yapılan bu karşılaştırma sonunda WCMP kesme bayağı "1" olur. Bu seçenekler şu şekilde olabilir.  Sonuç belirlenen çerçeve değerlerinin arasında/dışında veya alt değerin altında, üst değerin üstünde şeklindedir.
SAMPCTRL ile örnek uzunluğunu belirleyebiliriz. SAMPDLY kısmındaki çevrim şemasında görüldüğü şekilde işler. SAMDLY ve SAMPLEN birlikte kullanımı sonunda ön görülemeyen gecikmeler olabilirmiş. Bu konuda bir hata bildirimi var fakat ben denediğimde sorun yaşamadım.
MUXPOS ADC biriminin ölçüm yapılacak olan girişi seçtiğimiz registerdir. Tablodan ADCx birimine bağlı pin seçilir.
COMMAND registerinde bulunan STCONV biti "1" yapıldığında ADC çevrimi başlar.
EVCTRL ADC birimi olay sistemine bağlı olarak çevrime başlayabilir. Bunun için kullanıcı olarak tanımlanmalı ve STARTEI "1" yapılmalıdır.
INTCTRL ve INTFLAGS iki register aynı isimde iki bit bulundurur. Kesmeleri açmak ve oluşan kesmeleri kontrol etmek için bu registerler kullanılır. Kesme bayrağı için INTFLAGS registerinde ilgili bit "1" yapılır.
Bunların dışında sonuç RES, çerçeve modu eşik değerleri WINLT,WINHT bulunur. Çevrim sonucu için RES okunur. Yukarıda bahsettiğim çerçeve modu için gerekli değerler WINLT,WINHT ye yazılır.

CALIB ADC biriminin çalışma frekansı 1.5MHz üstünde ise DUTYCYC "0" yapılmalıdır. Varsayılan değer "1" dir.

Uygulama

İlk olarak ADC birimini kullanmak için gerekli yapılandırmayı yapıyorum. Yapacağım iki uygulamadan biri her çevrimde yoklama yöntemiyle çevrimin bitmesini bekleyecek. Diğerinde ise ölçmeye olay sisteminden buton sinyali ile başlayacak ve kesme sonunda okuma yapılacak.

/*
 * attiny1614_adc.c
 *
 * Created: 27.03.2024 16:57:28
 * Author : haluk
 */ 
#include <avr/io.h>
#include <stdio.h>
#include "tiny1_uart.h"
#include <util/delay.h>
uint16_t adc=0;
char sonuc[10];

int main(void){
  CPU_CCP=CCP_IOREG_gc;
  CLKCTRL_MCLKCTRLB=(0<<CLKCTRL_PEN_bp);//20mhz
  uart_basla(Bd115200);
  ADC0.CTRLA|=ADC_RESSEL_10BIT_gc;// adc 10 bit
  ADC0.CTRLB|=ADC_SAMPNUM_ACC1_gc;//örnekleme sayısı 2
  ADC0.CTRLC|=ADC_REFSEL_VDDREF_gc|ADC_PRESC_DIV32_gc|ADC_SAMPCAP_bm;//referans vdd, prescaler 32 625kHz
  ADC0.CTRLD|=ADC_INITDLY_DLY16_gc|ADC_SAMPDLY_3_bm;//başlatma gecikmesi 16, örnekleme gecikmesi 3
  ADC0.SAMPCTRL|=ADC_SAMPLEN_2_bm;//örnekleme uzunluğu 2
  ADC0.MUXPOS|=ADC_MUXPOS_AIN1_gc;//adc pin seçimi adco ain1 pa1
  //ADC0.CALIB|=ADC_DUTYCYC_DUTY50_gc;//1.5MHz üstünde
  ADC0.CTRLA|=ADC_ENABLE_bm;//adc0 enable
  ADC0.COMMAND=ADC_STCONV_bm;//ölçüm başlatma  boş ölçüm 
    while (1)  {   
    ADC0.COMMAND=ADC_STCONV_bm;//ölçüm başlatma
    while (!(ADC0.INTFLAGS&ADC_RESRDY_bm));//sonuç bayrağı bekle
    ADC0.INTFLAGS|=ADC_RESRDY_bm;//bayrak temizlendi
    adc=ADC0.RES;//sonuç okundu
    sprintf(sonuc,"adc: %u\n",adc);
    uart_dizi(sonuc);
    _delay_ms(100);
    }
}
Event sistem PB7 ile çevrim başlatma
/*
 * attiny1614_adc_int.c
 *
 * Created: 27.03.2024 17:25:12
 * Author : haluk
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "tiny1_uart.h"
#include <util/delay.h>
volatile uint16_t adc=0;
volatile uint8_t flag=0;
char sonuc[10];

ISR(ADC0_RESRDY_vect){
  ADC0.INTFLAGS|=ADC_RESRDY_bm;//bayrak temizlendi
  adc=ADC0.RES;  
  flag=1;
}
int main(void){
  CPU_CCP=CCP_IOREG_gc;
  CLKCTRL_MCLKCTRLB=(0<<CLKCTRL_PEN_bp);//20mhz
  uart_basla(Bd115200);
  PORTB.DIRCLR=PIN7_bm;//pb7 giriş butona basıldıkça okuma yapar
  PORTB.PIN7CTRL=PORT_PULLUPEN_bm;//pull up
  EVSYS.ASYNCCH1=EVSYS_ASYNCCH1_PORTB_PIN7_gc;
  EVSYS.ASYNCUSER1=EVSYS_ASYNCUSER1_ASYNCCH1_gc;  
  ADC0.CTRLA|=ADC_RESSEL_10BIT_gc;// adc 10 bit
  ADC0.CTRLB|=ADC_SAMPNUM_ACC1_gc;//örnekleme sayısı 2
  ADC0.CTRLC|=ADC_REFSEL_VDDREF_gc|ADC_PRESC_DIV32_gc|ADC_SAMPCAP_bm;//referans vdd, prescaler 32 625kHz
  ADC0.CTRLD|=ADC_INITDLY_DLY16_gc|ADC_SAMPDLY_3_bm;//başlatma gecikmesi 16, örnekleme gecikmesi 3
  ADC0.SAMPCTRL|=ADC_SAMPLEN_2_bm;//örnekleme uzunluğu 2
  ADC0.MUXPOS|=ADC_MUXPOS_AIN1_gc;//adc pin seçimi adco ain1 pa1
  ADC0.EVCTRL=ADC_STARTEI_bm;//event sistem başlatma  
  ADC0.INTCTRL|=ADC_RESRDY_bm;
  ADC0.CTRLA|=ADC_ENABLE_bm;//adc0 enable 
  sei();    
    while (1)  {
    if(flag==1){
      flag=0;
      sprintf(sonuc,"adc: %u\n",adc);
      uart_dizi(sonuc);     
    }   
    }
}


Hiç yorum yok:

Yorum Gönder