Basit bir ADC uygulaması yapmaya çalışıyorum kodlarım şu şekilde
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"
#include "misc.h"
#include "stm32f4xx_flash.h"
#include "stm32f4xx_adc.h"
uint16_t adc_val[2];
uint8_t ch_index =0;
/*void SystemLibInits()
{
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
while(RCC_WaitForHSEStartUp()!=SUCCESS)
RCC_PLLConfig(RCC_PLLSource_HSE,4,168,2,7);
RCC_PLLCmd(ENABLE);
FLASH_SetLatency(FLASH_Latency_5);
FLASH_PrefetchBufferCmd(ENABLE);
FLASH_DataCacheCmd(ENABLE);
FLASH_InstructionCacheCmd(ENABLE);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(0x08!=RCC_GetSYSCLKSource());
} */
void SystemInits()
{
unsigned int i;
for (i=0;i<0x00100000;i++); // OSC oturtma ve kurtarma rutini
RCC->CFGR |= 0x00009400; // AHB ve APB hizlarini max degerlere set edelim
RCC->CR |= 0x00010000; // HSE Xtal osc calismaya baslasin
while (!(RCC->CR & 0x00020000));// Xtal osc stabil hale gelsin
RCC->PLLCFGR = 0x07405408; // PLL katsayilarini M=8, N=336, P=2 ve Q=7 yapalim
// RCC->PLLCFGR = 0x07402A04; // PLL katsayilarini M=4, N=168, P=2 ve Q=7 yapalim
RCC->CR |= 0x01000000; // PLL calismaya baslasin (Rehber Sayfa 95)
while(!(RCC->CR & 0x02000000)); // Pll hazir oluncaya kadar bekle
// FLASH->ACR = 0x00000705; // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
FLASH->ACR = 0x00000605; // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
RCC->CFGR |= 0x00000002; // Sistem Clk u PLL uzerinden besleyelim
while ((RCC->CFGR & 0x0000000F) != 0x0000000A); // Besleninceye kadar bekle
}
/*********************************ADC KESME **********************************************************/
void ADC_IRQHandler()
{
if (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==SET) {
ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
adc_val[ch_index]=ADC_GetConversionValue(ADC1);
ch_index++;
if (ch_index>1) {
ch_index=0;
}
}
}
/************************************************************************************************/
void GPIOD_Inits()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure ;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT ;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Pin=(GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_13 | GPIO_Pin_12);
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
void rcc_gpio_config()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_B_InitStructure ;
GPIO_B_InitStructure.GPIO_Mode=GPIO_Mode_AN; // Anolog input
GPIO_B_InitStructure.GPIO_Pin=(GPIO_Pin_0 | GPIO_Pin_1); //PB0 PB1
GPIO_B_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_B_InitStructure);
}
void ADC1_Inits()
{
ADC_InitTypeDef ADC_InitStructure ;
ADC_CommonInitTypeDef ADC_CommonStructure;
ADC_CommonStructure.ADC_Mode=ADC_Mode_Independent;
ADC_CommonStructure.ADC_Prescaler=ADC_Prescaler_Div4;
ADC_CommonStructure.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_5Cycles;
ADC_CommonStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;
ADC_CommonInit(&ADC_CommonStructure);
ADC_InitStructure.ADC_Resolution=ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;
ADC_InitStructure.ADC_ScanConvMode=ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion=2;
ADC_Init(ADC1,&ADC_InitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_480Cycles); //PBO
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,2,ADC_SampleTime_480Cycles); //PB1
ADC_Cmd(ADC1,ENABLE);
ADC_EOCOnEachRegularChannelCmd(ADC1,ENABLE);
ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
}
void NVIC_Inits()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=ADC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
int main()
{
SystemInits();
GPIOD_Inits();
NVIC_Inits();
rcc_gpio_config();
ADC1_Inits();
ADC_SoftwareStartConv(ADC1);
while(1)
{
if (adc_val[0]>1500) {
GPIO_SetBits(GPIOD,GPIO_Pin_15);
}
else {
GPIO_ResetBits(GPIOD,GPIO_Pin_15);
}
}
}
2 kanalın verilerini okumaya çalışıyorum ama overrun bayrağı set oluyo veriyi kaybediyorum ve program kesmeye girmiyo.Bu problemi nasıl aşabilirim ?
Hocam şuraya Açıklık Getirirmisiniz
İki ADC yimi kullanmak istiyorsunuz 2 PIN (PB0 ve PB1)den okumamı yapmak istiyorsunuz.
Evet 2 çevrim yapmak istiyorum while içinde bi tanesini okuduğuma bakmayın hocam debugdan gözlemliyorum 2 kanalıda ayrı çıkışlara bağlayıp.Sorunum çevrim yaparken overrun flagının set olması ???
Hocam Malum üç adet ADC modülü var. siz her bir pini bu ADC modüllerine bağlamışsınız.
Hiç 2. Modülü kullanmadım. Bir Modülde 2 kanal kullandım.
Evet hocam ADC1 modülünü kullanıyorum sadece .2 kanal tarayacağım ADC1 üzerinden scan ve continious conversion modda.Klein hocanın yaptığı örnekten yola cıktım. swstart bitini 1 yaptıktan sonra kesme geldikçe taranan kanalları adc_val dizisinde saklayacağım .kesme olmadan yaptım sıkıntı yok ama bu şekilde denediğimde veriyi okuyamadan program çakılıyo :-\
2 kanal continious modda kesme olmadan okuyamazsın. Daha ilk çevirimin verisini okumadan ikinci çevirimin verisi gelir Overrun bayrağı çekilir.
Interrup pending bitini temizlemeyi dener misin?
Evet o biti temizleyince stabil çalıştı program hocam teşekkür ederim.Sonradan o satırı kaldırıp derledim gene çalıştı :) garip :) Bu bitin görevi tam olarak nedir hocam ? anladığım kadarıyla kesme bekleyen biti temizlemek için kullanılıyo. mesela ovr set oldu ama kesmesi acık değil bu yüzden kesmeye gidemiyo bu biti temizlemek için kullanılıyo ?
Evet kesme bayrağını temizliyor.
Benim önerim ADC'yi DMA ile kullanman yönünde olur.
ADC çok hızlı örneklediği için, program büyüyünce ADC kesmesini işletmekten, programı işletmeye zaman bulamıyosun.
Burada benimde takıldığım noktalar var.
407 için konuşursam. 3 adet ADC modülü var neden ?
Her ADC'nin birden fazla kanalı var. Ancak bu kanalların hepsini aynı anda okuyamıyoruz. Belirli bir sıra ile peş peşe okuyabiliyoruz. Bu bir çok uygulama için yeterli.
Ama düşün ki 3 fazlı bir sürücü yapıyorsun eş zamanlı olarak tüm fazların akım veya voltaj bilgisine ihtiyacın var. Eğer tek ADC olursa kanalları sırasıyla okuyacaksın ve aldığın bilgiler eş zamanlı olmayacak. Bu da veriyi işlemenive kontrolünü zorlaştıracak.
Anladım. Eş Zamanlı Okuma Yapacağımızda Kullanabiliriz.
Hocam Yoruyorum Ama
Şu Modlardan Bahsedebilirmisiniz Biraz. Odc Okuma Modları.
Single conversion, continious conversion , scan mod ve discontinious olmak üzere 4 çevirim modu var.
Scan modunda iken:
çevirimi başlattığınızda ADC_SQRx registeri ile bildirdiğiniz sayıda kanalı , aynı register ile bildirdiğiniz sırada tarıyor. her çevirimden sonra değeri registere atıyor ve conversion tamam bayrağını çekiyor. Tüm kanallar taranana kadar işlem böyle devam ediyor.
Tüm kanallar bittikten sonra, eğer Single conversion modundaysak duruyor. Takrar için yeniden çevirim başlatmamız gerekiyor. Continious conversion modundaysak, bizim yeniden çevirimi başlatmamıza gerek olmadan , çevirim kendi kendine yeniden başlıyor.
Scan modunda değilsek :
ADC_SQRx registerinde seçilmiş ilk kanal hangisi ise o kanalın verisinialıyoruz. Başka bir kanal seçeceksek, conversion bittikten sonra ADC_SQRx registerine Her zaman aynı kanalın bilgisini kesintisiz olarak alıyoruz. Continious modda iken kanal değiştirmek istersek, çevirim bittikten sonra, çevirimi durdurup kanal değiştiriyoruz. Çevirimi tekrar başlatıyoruz.
Discontinious mod scan modu gibi. Ancak biraz farklı. Yine tarama yapılıyor. Ancak tarama alt guruplara bölünüyor.
Diyelim ki sıralamamız 1,3,2,7,9,4,2,5,8,10,11,5,6,9
taranacak kanal sayısı 4:
ADC_CR1 ->DISCNUM registerinden çevirimi her başlatmada kaç kanal taranacağını bildiriyoruz.
Örneğin bu değerimiz 2 olsun.
çevirimi başlattığımızda ilk iki kanal (1,3) taranıyor.
çevirimi tekrar başlattığımızda ikinci iki kanal (2,7)
bir sonraki çevirimde (9,4)
bir sonrakinde (2,5)
kanallar taranıyor.
ADC_SQRx registerinde tarama sayısına 4 verdiğimiz için. 4. taramanın sonunda EOC(End of conversion) bayrağı kaldırılır.
Çevirimi tekrar başlattığımızda yine ilk sıradan çevirime başlar.
Bu modda çevirimi elle mi başlatıyoruz, başka kaynaklardan mı başlatmak gerekiyor tam emin değilim. Muhtemelen DMA gibi tetikleyiciler tarafından başlatılan çevirimleri için düşünülmüş bir özellik.
Merhabalar ADC ile benimde bir sorum olacak :)
Vref+ ve Vref- voltajları ne acaba?Yani kaç volt.Bir türlü bulamadım :(
Ben sordum cevabınıda ben veriyim.
Hard dökümanı sayfa 63(hard dokumanı:Doc ID 022152 Rev 2)
Vref+ Vdd ye Vref- de Vss ye bağlı.Vdd=3.3 V Vss=0 :)
Daha doğrusu küçük kılıflarda dışarı çıkarmıyorlar , direk beslemelere bağlıyorlar. Büyük paketlerde ise dışarı çıkıyor. Şöyle de bir sonuç çıkıyor aslında , vref kullanmak istiyorsak büyük paket kullanmak zorundayız.
@EMP_Otto
Kavram Kargaşası Yaşama, Muhtemelen Yanlış Anlıyorsun Konuyu
Vref+ ve Vref- ADC modülün çalışması için gerekli olan besleme uçları değildir
Herhangi bir ölçüm yapacağında bir referansın olması gerekir. Örneğin 100m Uzak yada 100m Yakın, Ne göre Uzak Neye Göre Yakın ?
Yada 100Derece neye göre 100Derece ? cevabı Suyun Donma Noktasına Göre Celcius dur. Bu tanım Referans Tanımdır.
şimdi ADC ölçmü yapacağız
1,25V neye göre 1,25V işte burada eğer "Besleme Gerilimine Göre" dersen Ona göre Ölçüm Yaparsın. Ama Yok Vref+ ve Vref- yi kullanırsan ona göre bir değer çıkar.
Eğer VDD VSS yi ref olarak alır ve sonuçta 2,15v görürsek,
Vref+ ya 1V luk bir gerilim verdiğimizde ölçeceğimiz değer 1,15 olur.
@muhittin_kaplan
Açıklaman için cok sagol hocam.Kavram karmaşası yok çok şükür.ADC ye pic,msp430 ve arduinodan aşinalığım var :)
Saygıyla.
@Klein
Merhaba hocam.Aynı sorun bendede var sürekli overrun set oluyor.Tam olarak hangi interrupt bayrağını silmem gerekiyor acaba?
Yok mu bir yardım edecek :D
Alıntı yapılan: EMP_Otto - 02 Ağustos 2013, 17:17:28
@Klein
Merhaba hocam.Aynı sorun bendede var sürekli overrun set oluyor.Tam olarak hangi interrupt bayrağını silmem gerekiyor acaba?
overrun bayrağı çekiliyorsa, bir veriyi okumadan diğeri geliyordur. Veriyi kesme içinde veya benim önerim DMA ile okuyun.
Eğer bunları yapmak istemiyorsanız, continious mode kullanmayın. Veriyi okuyun, diğer kanaı set edip çevirimi yeniden başlatın.