merhaba arkadaşlar.
acemi bir PIC kullanıcısı olarak PIC C ile bir ADC uygulaması yapmak istedim.
uygulamam da (resimdeki gibi) RA0 analog girişine 2,5V tan küçük bir deger uygulandıgında RB0 a bağlı ledin yanmasını istedim. ama çalışmadı.
analog girişe uygulanan deger 10 bit le ifade edilir diye biliyorum, yani
1024 5V a karşılık gelir. bu bağlamda 2,5V 512 ile ifade edilir diye düşündüm. acaba nerede hata yaptım?
yardımlarınız için şimdiden çok teşekkür ederim.
bunlara ek olarak PIC C için ADC kodlarını, döküman bulamadığım için internetteki uygulamalardan öğrenmeye çalıştım. ama yeterli olmadı sanırım.
elinde kodlarla ilgli döküman olan varsa eklerse çok sevinirim.
#include <pic.h>
main (void)
{
// Değişken tanımlama
double gerilim;
// Port konfigürasyonu
TRISB=0; // PORTB çıkış
TRISA=1; // RA0 analog giriş
// ADC ayarları
ADCON1=0x8E; // AN0 analog giriş
ADCON0=0x41; // A/D aktif
for(;;)
{ // A/D çevrimi başlat
ADCON0=0x45;
// Dönüşümün bitmesini bekle
while((ADCON0&4)!=0);
// Dönüşüm sonucunu kaydet
gerilim=ADRESH;
gerilim=256.0*gerilim+ADRESL;
} // Ölçümü tekrarla
RB0=0;
for(;;)
{
if(gerilim<512) RB0=1;
else RB0=0;
}
} // Programın sonu
(//%5BURL=http://www.yukle.tc%5D%5Bimg%5Dhttp://img219.yukle.tc/images/5714adc_deneme.JPG)[/URL][/img]
Nerdeyse ASM kodu gibi olmuş :). Bu dili bilmiyorum ama belki de A/D dönüşümü için hazır fonksiyonlar vardır onları kullanmayı bir dene.
ADRESH'nın büyük 6 biti 0'dan farklı olabilir mi acaba? Bazı register'lar PIC çalışmaya başladığı zaman garip değerler alıyor ve A/D dönüşüm sağa dayalı ayarlanmışsa (ki sen bu şekilde kullanıyorsun) dönüşüm ADRESH'nın büyük 6 bitini etkilemiyor sanırım. Eğer öyle ise bu sonucu etkileyecektir. 256 ile çarpma işleminden önce söz konusu büyük 6 biti basit bir AND işlemi ile sıfırlayabilirsin.
Programı çalıştırdığında gözlemin ne oluyor? LED hiç mi yanmıyor?
Ekleme: Bu arada aklıma geldi de A/D dönüşüm öncesinde kanalı seçtikten sonra bir süre beklemek gerekir (bu süre için datasheet'e bir bak). Buna "acquisition time" deniyor. Senin kodunda bu beklemeyi göremedim. Hazır fonksiyonları kullanırsan sanırım bu beklemeye gerek kalmayacaktır (bekleme hazır fonksiyonların içine dahil edilmiştir).
Düzeltme: Büyük 6 bit konusunda yanılmışım. Bunlar zaten 0 oluyormuş. Datasheet'te A/D dönüştürücü kullanılmazken bu iki byte'lık alanın istenildiği gibi kullanılabileceği yazıyormuş, aklımda yanlış kalmış olay.
Dostum A/D modülünü kullanman zorunlu değilse bu uygulamayı comparator modulü ile daha basit yaparsın comparatoru ayarlayıp dahili referans üreteç moduülünü açarak vrefi 2.5 volta ayarlarsın comparator çıkışını tersleyip kullanırsın. 2.5volta kadar çıkış 1 olur 2.5 voltu aşınca çıkış 0 olur Datasheetten bir incelel bu işlem için comparator modülü daha mantıklı çözüm
Teşekkürler tamirci_Erhan tavsiyen için. Comparatordan bahsettiğin iyi oldu.
PIC de acemiyim bilmiyordum bu özelliği olduğunu. Çalışmamın ileriki aşamalrın da LCD de gerilim değerlerinide görmem gerekiyor, o yüzden ADC işime yarar sanırım.
Teşekkürler Tagli.
Devreyi çalıştırdığımda LED sürekli olarak karasız bir şekilde yanıp sönüyor. Pot dan RA0'a uyguladığım gerilimi değiştirsem dahi sonuç değişmiyor. Belki sorun dediğin gibi ADRESH' a kaydederken olabilir.Datasheet'i birazdaha inceleyim iyisimi.
Acquisition time'dan kaynaklanıyor olması daha muhtemel. Ama dediğim gibi, büyük ihtimalle A/D dönüşümü için hazır fonksiyon vardır, bu fonksiyon(lar)ı kullanman daha iyi olur.
#include <pic.h>
main (void)
{
// Değişken tanımlama
double gerilim;
// Port konfigürasyonu
TRISB=0; // PORTB çıkış
TRISA=1; // RA0 analog giriş
// ADC ayarları
ADCON1=0x8E; // AN0 analog giriş
ADCON0=0x41; // A/D aktif
for(;;)
{ // A/D çevrimi başlat
ADCON0=0x45;
// Dönüşümün bitmesini bekle
while((ADCON0&4)!=0);
// Dönüşüm sonucunu kaydet
gerilim=ADRESH;
gerilim=256.0*gerilim+ADRESL;
if(gerilim<512)
RB0=1;
else
RB0=0;
} // Ölçümü tekrarla
}
ben ccs c kullanıyorum aslında ama mantık hatası var programında sonsuz iki for döngüsü kurmuşsun
ilkinden yani adc ölçümünden asla çıkmayacağı için ledleri ayarlama döngüsüne girmeyecekdir
yukarıdaki gibi bir denermisin
Teşekkürler CemilKendir.
ADC kısmına odaklandığım için programdaki mantık hatası hiç dikkatimi çememiş.
dediğin doğru , ikinci for u kaldırınca düzgünce çalıştı devre.
ilginiz için hepinize tekrar teşekkür ederim arkadaşlar..
bir de arkadaslar VREF+ ve VREF- nin kullanımını anlayamadım.
bu iki referans girişleri RA0 ile birlikte mi kullan malıyım yoksa ayrı da kullana bilirmiyim?
ve de ne işime yarar bu girişler? bunlarla ilgili örneklere baktım ama anlayamadım,
yönlendire bilceğiniz örnek uygulama varsa paylaşırsanız mutlu olurum,
şimdiden tesekkür ederim..
Dostum vref -vref referans voltajı girişleridir pic analog bilgiyi dijitale bu değerleri referans alarak çevirir. bu değer picin beleme gerilimi olabileceği gibi ilgili ayalar yapılınca picin vref -vref girişlerindende sağlanır yani picin besleme gerilimini kullanırsan örnek olarak 5 voltluk gerilimi dijitale çevirince dijital 1024 2.5 voltu çevirince 512 gibi değerler elde edilir yaklaşık olarak 16f877 de referans girişlerini kullanmak için tabloyu inceleyebilirsin tablo biraz kısıtlıdır fakat 16f88 16f887 gibi yeni çıkan denetleyicilerde bu girişlerinin kullanımı daha esnektir. Datasheetleri inceleyebilirsin 16f887 pin bağlantıları 877 ile aynıdır 877nin gelişmiş versiyonudur.
(http://img241.imageshack.us/img241/5387/adcal9.jpg)
çok teşekkür ederim tamirci_erhan
Alıntı yapılan: "tamirci_erhan"Dostum vref -vref referans voltajı girişleridir pic analog bilgiyi dijitale bu değerleri referans alarak çevirir. bu değer picin beleme gerilimi olabileceği gibi ilgili ayalar yapılınca picin vref -vref girişlerindende sağlanır yani picin besleme gerilimini kullanırsan örnek olarak 5 voltluk gerilimi dijitale çevirince dijital 1024 2.5 voltu çevirince 512 gibi değerler elde edilir yaklaşık olarak 16f877 de referans girişlerini kullanmak için tabloyu inceleyebilirsin tablo biraz kısıtlıdır fakat 16f88 16f887 gibi yeni çıkan denetleyicilerde bu girişlerinin kullanımı daha esnektir. Datasheetleri inceleyebilirsin 16f887 pin bağlantıları 877 ile aynıdır 877nin gelişmiş versiyonudur.
Merhaba,
Ufak bir düzeltme eklemek istiyorum. PIC 10bit ADC sahib o yüzden en fazla '0b1111111111' sayisini gösterebilir oda 1023 eder. Yani Vref 5Volt ise 5 V olduğunda 1023 görürsünüz.
Selamlar
[/quote]
Merhaba,
Ufak bir düzeltme eklemek istiyorum. PIC 10bit ADC sahib o yüzden en fazla '0b1111111111' sayisini gösterebilir oda 1023 eder. Yani Vref 5Volt ise 5 V olduğunda 1023 görürsünüz.
Selamlar[/quote]
tskürler arslan74 ilgin için
Tekrar merhaba arkadaşlar
bu örneği internetten bakarak oluşturmuştum. o yüzden anlayamadığım kısımları hala var.
dönüşümün bitmesini beklemek için aşağıdaki ifade yazılmıştı.
while((ADCON0&4)!=0);
bu ifade sanırım GO/DONE biti ile alakalı, ama tam anlayamadım.
ne anlama geliyor ?
birde ADC 10 bit ile çevirim yapıyor biliyorum ama kafam aşağıdaki ifade de karıştı
gerilim=ADRESH;
gerilim=256.0*gerilim+ADRESL;
birde burda yardımcı olursanız sevinirim.
yardımlar için şimdiden teşekkür ederim
Sana çalışan örnek kod yolluyorum.
Bunu al doğrudan kullan.
unsigned int
read_adc(void){
unsigned int val;
ADIF = 0; //Clear ADIF bit
ADGO=1; // initiate conversion on the selected channel
while ( ADGO || !ADIF )
continue;
val = ADRESL;
val += ((unsigned int)ADRESH * 256);
return val;
} //
unsigned int adc_read (void){
unsigned int i;
ADIF = 0; //Clear ADIF bit
ADGO=1; // initiate conversion on the selected channel
while ( ADGO || !ADIF )
continue;
DelayUs(100);
// i = ADRESL + (ADRESL<<8); // return 8 MSB of the result
p = (char*)(&i);
*(p++) = ADRESL;
*p = ADRESH;
return i;
}
bu iki fonksiyondan birini kullanabilirsin. ikiside çalışıyor. İki, farklı kodlama mantığı ile hazırlanmıştır.
Öncesinde ADC ayarlaman lazım.
/***********************************************************************
ADC ayarları
***********************************************************************/
CHS2 = 0;
CHS1 = 0;
CHS0 = 0;
ADCS1 = 1;
ADCS0 = 1;
ADFM = 1; //0 = Left justified. 6 Least Significant bits of ADRESL are read as Â0'.
PCFG0 = 0;
PCFG1 = 1;
PCFG2 = 0;
PCFG3 = 0;
ADON = 1;
/**********************************************************************/
ADC değeri volta dönüştürmek istiyorsan o zaman aşağıdaki kodu kullanabilirsin. Ancak Burada referans olarak 1024 alınmıştır. Dolaysıyla 5Volt olduğunda 4.99 Volt elde edersin.
unsigned int
convert2mV(unsigned int adc){
unsigned int val,temp;
// U[mV] = ((5*adc - 5*adc/64) - 5*adc/128)
temp = val = (5*adc);
val -= temp >> 6;
val -= temp >> 7;
return val;
}
Program içinde söyle bir cağrı yapabilirsin.
adc_val = adc_read();
adc_val = convert2mV(adc_val);
yada
adc_val = convert2mV(adc_read());
Çalışmalarınızda başarılar.
çok teşekkür ederim arslan74 ilgine.
benim kavrayamadığım nokta while((ADCON0&4)!=0); ifadesiydi.
bu ifade " GO/DONE biti sıfıra eşit değilse " anlamına mı geliyor ? aynı zamanda & operatörünün anlamı nedir?
birde ADRESH ve ADRESL kaydedicilerini anlayamadım.
yani adc 10 bitlik çeviri yapıyor ama bu kaydediciler 8 er bitlik.
elde ettiğimiz 10 bitlik degerimiz bu kaydedicilere nasıl yazılıyor?
yani 5 biti ADRESH'a, diger 5 biti de ADRESL'a mı? yazılıyor
adc de 10 bitlik çevrim yapılıyorsa neden iki tane 8 bitlik kaydediciye kayıt ediliyor?
mesela birtane ADRES adında 10 bitlik bir kaydedici kulanılamaz mıydı?
Merhaba,
Ben daha önce bu konuları ayrıntılı anlatan eğitim yazısı hazırladım. Onları incelemenizi tavsie ediyorum.
linki aşağıda.
http://picproje.org/index.php/topic,19320
Selamlar,
Not: Ayrıca başka konularda eğitim konuları hazırladım. Önce onları inceleyin sonra anlamadığınız konular var ise o zaman soru sorun.
teşekkürler arslan74 çok faydalı oldu yönlendirmen.
merhaba belki başka fikirler verebilir ccs c olarak kucuk bir demo
Alıntı Yap
/////////////////////////////////////////////////////////////////////////
//// CCS PICC COMPILER ////
/////////////////////////////////////////////////////////////////////////
// main.c //
#TYPE short=8, int=16, long=32
#if defined(__PCM__)
#include <16F873A.h>
#fuses HS,NOLVP,NOWDT,NOPUT,NOBROWNOUT,NOPROTECT
#use delay(clock=10000000)
#ZERO_RAM
#endif
#include "main.h"
///////////////////////////////////////////////////////
//***** main program *****//
main()
{
SET_TRIS_A( IOBITS_A );
SET_TRIS_B( IOBITS_B );
SET_TRIS_C( IOBITS_C );
setup_adc (ADC_CLOCK_INTERNAL);
set_adc_channel( 0 );
do{
value = read_adc();
for(i = 0; i <= 23; ++i){
write_expanded_outputs(tablo8);
//write_expanded_outputs(tablo8[1]);
GONDER;
delay_ms(read_adc());
}
for(i = 23; i > 0;){
--i;
write_expanded_outputs(tablo8);
//write_expanded_outputs(tablo8[1]);
GONDER;
delay_ms(read_adc());
}
} while ( TRUE );
}
//-------------------------------------------------------------------//
//-------------------------------------------------------------------//