Picproje Elektronik Sitesi

DERLEYİCİLER => PIC C => Konuyu başlatan: ygunbt - 09 Aralık 2008, 13:47:36

Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 09 Aralık 2008, 13:47:36
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]  
Başlık: PIC16F877 ADC için yardım
Gönderen: Tagli - 09 Aralık 2008, 15:19:47
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.
Başlık: PIC16F877 ADC için yardım
Gönderen: Erhan YILMAZ - 09 Aralık 2008, 17:00:30
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
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 09 Aralık 2008, 22:43:48
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.
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 09 Aralık 2008, 22:56:19
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.
Başlık: PIC16F877 ADC için yardım
Gönderen: Tagli - 09 Aralık 2008, 23:37:27
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.
Başlık: PIC16F877 ADC için yardım
Gönderen: cemilkendir - 10 Aralık 2008, 22:41:37
#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
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 11 Aralık 2008, 03:18:05
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..
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 12 Aralık 2008, 10:37:14
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..
Başlık: PIC16F877 ADC için yardım
Gönderen: Erhan YILMAZ - 12 Aralık 2008, 16:12:16
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)
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 14 Aralık 2008, 18:19:35
çok teşekkür ederim tamirci_erhan
Başlık: PIC16F877 ADC için yardım
Gönderen: arslan74 - 15 Aralık 2008, 13:21:11
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
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 19 Aralık 2008, 00:18:41
[/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
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 23 Aralık 2008, 09:13:30
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
Başlık: PIC16F877 ADC için yardım
Gönderen: arslan74 - 23 Aralık 2008, 09:34:12
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.
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 24 Aralık 2008, 05:05:56
ç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ı?
Başlık: PIC16F877 ADC için yardım
Gönderen: arslan74 - 24 Aralık 2008, 08:52:04
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.
Başlık: PIC16F877 ADC için yardım
Gönderen: ygunbt - 27 Aralık 2008, 12:02:43
teşekkürler arslan74 çok faydalı oldu yönlendirmen.
Başlık: PIC16F877 ADC için yardım
Gönderen: sagamen - 27 Aralık 2008, 22:12:25
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 );
}
//-------------------------------------------------------------------//
//-------------------------------------------------------------------//