Dijitalden analoga dönüşüm sağlayan DAC 12 bitlik analog veriler oluşturur. PWM (pulse width modulators) olarak alınan dijital sinyalleri analog sinyallere dönüştürür. STM32'de dönüştürülen bu analog sinyaller sinüs veya üçgen dalgalarıdır, gürültü sinyali de oluşturulabilmektedir. 8 veya 12 bitlik modlarda sağa veya sola dayalı olarak çalıştırılabilmektedir. 2 kanal (channel 1 ve channel 2) bağımsız veya senkron olarak çalışabilmektedir. DAC olarak kullanılabilecek pinler kartta PA4 ve PA5'tir ve pinler analog input olarak atanır.
DAC'lerde yanda görüldüğü gibi mantığı voltage divider olan bir R-2R devresi (R-2R Ladder) bulunmaktadır. Örneğin yandaki DAC 4 bitliktir çünkü VA, VB, VC, VD olmak üzere 4 giriş bulunmaktadır. Burda kullanılan opampda empedansı düşürmek için kullanılmaktadır.
DAC çıkışındaki volt Vout=(Vref*D)/2^n şeklinde hesaplanır. Örneğin 12 bit çözünürlüğe sahip DAC için Vref=3.3V (STM32’nin analog besleme voltajı) Vout=3,3*4095)/(4096)~3.29 V olur. DAC’ler APB1 clock hattına bağlıdır ve clock sinyalini bu hat üzerinden almaktadırlar.
Bu uygulamada da PA4'e ve PA5'e bağlanan pinlerden DAC olarak kullanılmıştır. Potansiyometre ile 12 bitlik 0 ile 4095 arasında okuma yapıldıktan sonra belirlenen değerlere göre ledlere sinyal gönderilmiştir.
Malzemeler:
Led
Jumper kablolar
STM32VL Discovery
Potansiyometre
Devre Şeması ve Kod:
#include "stm32f10x.h" // Device header
#include "stm32f10x_dac.h" // Keil::Device:StdPeriph Drivers:DAC
void gpioConfig(); // pinlerin ayarlanmasi
void dacConfig(); //DAC'nin ayarlanmasi
void adcConfig(); // ADC'nin ayarlanmasi
void delay();
uint16_t readADC(); //ADC çevrim yaparken calisacak fonksiyon
uint32_t deger;
int main(){
gpioConfig();
dacConfig();
adcConfig();
while (1){
deger= readADC(); //analog okuma yapiliyor
for (int i=0; i<4095; i++ ){
if (deger== 0 && deger < 2048){ //deger 0-2048 arasinda ise
DAC_SetChannel1Data(DAC_Align_12b_R,i); // channel1 yani PA4 set ediliyor. led yaniyor
}
if (deger==2048 && deger<4095){ //deger 2048-4095 arasinda ise
DAC_SetChannel2Data(DAC_Align_12b_R,i); // channel2 yani PA5 set ediliyor, led yaniyor
}
}
}
}
void gpioConfig(){
GPIO_InitTypeDef GPIOInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // A portunun clock hatti aktif ediliyor çünkü PA4 ve PA5 kullanilacak ledler icin
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); // potansiyometre için kullaniiacak C portunun clock aktif ediliyor
GPIOInitStructure.GPIO_Mode=GPIO_Mode_AIN; // DAC için kullanilan pinler Analog input mode'da çalisiyor
GPIOInitStructure.GPIO_Pin=GPIO_Pin_5 | GPIO_Pin_4; // pin 4 ve pin 5
GPIOInitStructure.GPIO_Mode=GPIO_Mode_AIN; // potansiyometreden ADC okumasi yapiacak, analog input olarak belirlendi
GPIOInitStructure.GPIO_Pin=GPIO_Pin_0; // potasniyometre pin 0'a bagli
GPIO_Init(GPIOA,&GPIOInitStructure); // A portundaki ayarlamalar bildirildi
GPIO_Init(GPIOC,&GPIOInitStructure); // B portundaki ayarlamalar bildirildi
}
void dacConfig(){
DAC_InitTypeDef DACInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE); // DAC kullanmak icin APB1 clock hatti aktif edilmeli
DACInitStructure.DAC_LFSRUnmask_TriangleAmplitude=DISABLE; // olusan dalganin volt degeri
DACInitStructure.DAC_OutputBuffer=ENABLE; //Empedansi düsürmekicin. R-2R devresinde oplamp var onun aktif inaktif edilmesiyle ilgili
DACInitStructure.DAC_Trigger=DAC_Trigger_None; //DAC için trigger kullanilmadi
DACInitStructure.DAC_WaveGeneration=DAC_WaveGeneration_None; // üretilen dalganin tipi su an için önemli degil none seçildi
DAC_Init(DAC_Channel_2,&DACInitStructure); // DAC channel 2 için ayarlama yapildigi bildirildi PA5 Channel 2'ye bagli
DAC_Cmd(DAC_Channel_2,ENABLE);
DAC_Init(DAC_Channel_1,&DACInitStructure); // DAC channel 1 için ayarlama yapildigi bildirildi PA4 Channel 1'e bagli
DAC_Cmd(DAC_Channel_1,ENABLE);
}
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 devam ediyorsa burda kalsin. EOC
return ADC_GetConversionValue(ADC1); // çevrim bitince sonucu döndür
}
void delay( uint32_t time ){
while (time--);
}
Comments