Günlük hayatta etrafımızda gerçekleşen olaylar süreklilik arz eder yani analogtur. Bu verilerin ölçümlerde belirli yollarla dijitize edilmesi gerekir. Yani analogtan belli örnekler alarak dijitale çevirilir, bu da sinyallerle 0 ve 1’lerle işlem yapılması anlamına gelir. ADC'ler de analogtan dijitale çevrim yapan birim olarak bir mikrodenetleyicinin en önemli başlıklarından biridir.
Stm32’de ADC 3 şekilde kullanılabilir. Bunlardan biri pollingtir. Bu kullanımda dönüştürme (çevrim) süresi boyunca farklı bir işlem yapılamaz ve çevrimin bitmesi beklenir. Polling, tek ölçüm gereken ve çok hızlı ölçüm alınması gerekmeyen durumlarda kullanılır. Diğer yöntem interrupt olarak kullanmaktır. Bu yöntemde mikrodenetleyici ADC’ye komut verir ADC dönüşüm işlemlerini yaparken kendisi diğer işlemleri yapmaya devam eder, dönüştürme işleminin sonunda bir interrupt (kesme) meydana gelir ve kesme sırasında çalışacak fonksiyon çağırılır. Bu kullanımda ADC dönüştürme yaparken beklemek gerekmez. Diğer ve son kullanım ise DMA’dır. Bu kullanımda da yine mikrodenetleyici diğer işlemleri yaparken dönüştürmeye devam eder fakat interrupt kullanımından farkı DMA’da elde edilen dönüşüm verileri hafızaya kaydedilir
STM32F100xx ADC'nin bazı özellikleri şu şekildedir:
12 bitlik çözünütlüğe sahiptir bu da 2^12 -1’den 0 ile 4095 arasında analog değerleri kapsar. (Arduino'da bu 10 bittir yani 2^10-1 den 0 ile 1023 arası okuma yapılabilir.)
Blok diyagramda da dörüldüğü gibi 16 harici 2 tane de dahili kaynaktan gelen
analog sinayallerin ölçülmesine izin veren toplam 18 tane çoklanmış kanala sahiptir.
Farklı modlarda kaynaktan okuma yapabilir bunlar tek, sürekli, tarama veya süreksiz moddur. (Single, continuous, scan or discontinuous mode.)
ADC’nin okumasının sonucu sola veya sağa hizalı olacak şekilde 16 bitlik registerlarda saklanır.
End of Conversion, End of Injected conversion and Analog watchdog event sonunda interrupt gerçekleştirilebilir.
ADC dönüştürme (çevrim) zamanı 1.17 µs at 24 MHz’dir. 2.4-3.6 V ile beslenmesi gerekir.
Blok diyagramda da görüldüğü gibi dahili ve harici ADC’ler (ADCx_IN0, ADCx_IN1,….ADCx_IN15, Temp sensor, VREFINT) geldiğinde analog multiplexer ile seçilir ve Regular Channels’a gelir. Burdan da data registera iletilir. Ayrıca End Of Conversion ile interrupt kullanımı da sağlanmaktadır.
STM32'de ADC, ADON bitinin aktif duruma getirilmesiyle kontrol edilir. Timing diyagramında da görüldüğü gibi, ADON biti aktif haldeyken dönüştürme sinyali ilk geldiğinde, dönüşüme başlamadan önce tSTAB adı verilen kararlılık süresi geçmektedir. Bu süre doğru dönüşüm sağlanması için gerekli görülmüştür. Dönüşüm bitince EOC biti temizlenir, ve tekrar dönüştürme sinyali geldiğinde diğer ADC dönüşümü başlar.
ADC çevrimlerinde çözünürlük hassas sonuçlar için önemlidir. ADC için adım aralığı ADC’nin ölçebileceği en yüksek ve en düşük gerilim değerine (Vmax-Vmin)/(2^n-1) şeklinde formülle bulunur. Formülde görüldüğü üzere n yani çözünürlük değeri (bit) arttıkça adım aralığı düşmekte yani ölçüm daha hassas olmaktadır. En düşük volt değeri ADC için 0 olarak alınır. Bu uygulamada da Vmax değeri 2.98 Volt olarak potansiyometre üzerinden ölçülmüştür. 12 bitlik ADC kullanıldığı için n=12’dir. Yani bir adımda okunacak değer formülden 7,27x 10^-4 Volt olarak hesaplanır.
Bu uygulamada C portunun 0. pininden yani C0'dan potansiyometreyle ADC okuması yapılmıştır. Okunan değer 0-4095 arasındadır. Bu değer daha sonra volta çevrilmiş ve volt aralıklarına göre de ledler yanıp söndürülmüştür. Dikkat edilmesi gereken yerlerden biri C0 channel 10'a bağlıdır. Pinlere göre bağlı oldukları channellar değişiklik göstermektedir bunlar kartın user manuelinden pinout tablosuna bakılarak ayarlanabilir.
Malzemeler:
Jumper Kablolar
3 adet Led
Potansiyometre
STM32VL Discovery
Devre Şeması ve Kod:
#include "stm32f10x.h" // Device header
void gpioConfig(); // giris cikis pinlerinin ayarlanmasi fonksiyonu
void adcConfig(); // ADC'nin ayarlanmasi fonksiyonu
void delay(); // gecikme fonksiyonu
uint16_t readADC(); //ADC çevrim yaparken calisacak fonksiyon
uint16_t adcValue=0;
float voltage;
int main (){
gpioConfig();
adcConfig();
while (1){
adcValue=readADC(); //ADC'den okunan deger
voltage=adcValue*(2.98/4095); // okunan degeri tekrar volta cevirmek (adcValue*(Vmax-Vmin)/(2^n-1))
if(voltage<1.5){ //volt degeri 1.5 altindaysa B portunun 0. pini yansin sönsün
GPIO_SetBits(GPIOB,GPIO_Pin_0 );
delay(360000);
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay(360000);
}
else if (voltage>=1.5 && voltage<2.5){ //volt degeri 1.5 ve 2.5 arasindaysa B portunun 1. pini yansin sönsün
GPIO_SetBits (GPIOB,GPIO_Pin_1);
delay(360000);
GPIO_ResetBits(GPIOB,GPIO_Pin_1);
delay(360000);
}
else if(voltage>=2.5){ //volt degeri 2.5 üstündeyse B portunun 2. pini yansin sönsün
GPIO_SetBits (GPIOB,GPIO_Pin_2);
delay(360000);
GPIO_ResetBits(GPIOB,GPIO_Pin_2);
delay(360000);
}
else { // yukardaki sartlarin hicbiridegilse ledler sönüyor
GPIO_ResetBits(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2);
}
}
}
void gpioConfig(){
GPIO_InitTypeDef GPIOInitStructure; // GPIO ayarlamalari icin struct
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//Ledler icin B portu clock hatti aktif edildi
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); // Potansiyometre için C portu clock hatti aktif edildi
GPIOInitStructure.GPIO_Mode=GPIO_Mode_Out_PP; // ledler push pull output
GPIOInitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2; // 0 1 ve 2. pinler ledler icin
GPIOInitStructure.GPIO_Speed=GPIO_Speed_50MHz; // hiz ayari
GPIO_Init(GPIOB,&GPIOInitStructure); // B portu icin ayarlamalarin yapildigi bildiriliyor
GPIOInitStructure.GPIO_Mode=GPIO_Mode_AIN;// analog veri okunacak analog input
GPIOInitStructure.GPIO_Pin=GPIO_Pin_0; // C portu 0. pin ADC çevrimi yapilacak olan yer
GPIOInitStructure.GPIO_Speed=GPIO_Speed_50MHz; // input olarak ayarlandigi icin hiza gerek yok
GPIO_Init(GPIOC,&GPIOInitStructure); // C portu icin ayarlamalarin yapildigi bildiriliyor
}
void adcConfig(){
ADC_InitTypeDef ADCInitStructure; //ADC ayarlamalari icin struct
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); // ADC'nin clock hattini aktif ettik ve ADC1'i kullanildi
ADCInitStructure.ADC_ContinuousConvMode=ENABLE; //sürekli çevrim yapsin
ADCInitStructure.ADC_DataAlign=ADC_DataAlign_Right; // most significant bitin saga dayali olacagi bildirildi
ADCInitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; // trigger kullanilmiyor
ADCInitStructure.ADC_Mode=ADC_Mode_Independent; // single mod okuma yapilacagi icin independent ayarlandi
ADCInitStructure.ADC_NbrOfChannel=1; // 1 tane adc oldugu icin
ADCInitStructure.ADC_ScanConvMode= DISABLE; // multichanel ADC kullanimi yapilacaksa aktif edilir diger verilerin cevrimi yapilacagi zaman
ADC_Init(ADC1,&ADCInitStructure); // ADC'nin ayarlarinin yapildigi bildiriliyor
ADC_Cmd (ADC1,ENABLE); //ADC1 aktif ediliyor
}
uint16_t readADC(){ // ADC'nin okuma yapacagi fonksiyon
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_55Cycles5); // ADC1,C0 ADC Channel 10'a bagli,1 adet ADC okumasi yapildi, dogruluk artmasi icin kac cyle'da okuma yapilsin parametreleri
ADC_SoftwareStartConvCmd(ADC1,ENABLE); // okumanin baslayacagi bildiriliyor
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);// çevrim devem ediyorsa burda kalsin. EOC
return ADC_GetConversionValue(ADC1); // çevrim bitince sonucu döndür
}
void delay(uint32_t time){
while(time--);
}
Comentarios