16f877 ADC okuma ve LCD'ye yazma.

Başlatan CoşkuN, 12 Şubat 2006, 16:02:44

CoşkuN

Son günlerde PIC  ve C bilgimi ilerletebilmek adına Proteus'ta bazı denemeler yapıyorum.Önce Hitech'in LCD dosyalarını kullanarak basit LCD denemeleri yaptım.Sonra bazı sayısal değerleri LCD'ye yazdırmak için bu sayısal değerleri ASCII'ye dönüştürmem gerekti.Araştırıp bunla ilgili bir fonksiyon buldum ve LCD fonksiyonları içine ekledim.
Şimdi de ADC ile ilgili çalışıyorum.İlk soracağım şey ADC sonuçlarını elde ettiğimiz ADRESL,ADRESH yazmaçlarındaki değerleri nasıl toplayarak adc sonuç değerini elde edeceğiz.Oradaki matematiği tam anlayamadım.Şu tür örnekler gördüm ama neden 8 kere sağa kaydırıyoruz:
        unsigned long adc;
   adc=ADRESL+(ADRESH<<8)  ( Sağa yatık farzediyoruz sonucu)
Bir diğer hususta yine elde edilen sayısal değerin ekrana yazdırılması.Örneğin 0-5 volt arası değerleri ekrana yazdıracağım.Ancak ekrana sayısal değer yazdıran komut byte olarak düzenlenmiş.Onu yeniden düzenleyerek long yazdıracak şekle getirdim.Fonksiyonlar şu şekilde:

char num_to_char(unsigned char val   // sayıyı hex karakter koda çevirir
{
   char c;
   if (val < 10)
   {
     c=val+'0';
   }
   else
   {
     val=val-10;	   
     c=val + 'A';
   }
   return(c);
}

void lcd_dec_byte(unsigned char val) // byte değeri karakter olarak yazdır
{
   unsigned char d;
   char c;
   d=val/100;
   c=num_to_char(d);
   lcd_putch(c);
   
   val=val%100;
   d=val/10;
   c=num_to_char(d);
   lcd_putch(c);   	
   
   d=val % 10;
   c=num_to_char(d);
   lcd_putch(c);
}   
Benim uyarladığım fonk:
void lcd_dec_long(unsigned long val) // long değeri karaktere çevirir
{
   unsigned char d;
   char c;
   d=val/1000;
   c=num_to_char(d);
   lcd_putch(c);

   
   val=val%1000;
   d=val/100;

   c=num_to_char(d);
   lcd_putch(c);   	
   
   val=val%100;
   d=val/10;
	   lcd_putch('.');
   c=num_to_char(d);
   lcd_putch(c);   	

   d=val % 10;
   c=num_to_char(d);
   lcd_putch(c);
}  


Gerekli ayarlamaları yaptıktan sonra programın ana gövdesi şu:
while(1){
	lcd_goto(1);
	ADGO=1;
	while(ADGO==1);
	adc=ADRESL+(ADRESH<<8);
	adc2=adc/2.025;	
	lcd_dec_long(adc2);
	lcd_puts("Volt");
	


	}

Bu şekilde girişteki voltaja göre değeri LCD'de görebiliyorum.Ufak hata payları oluyor ama.Örneğin 3 voltta 3.03,4'te 4.03,4.50 'de 4.54 görüyorum.
Yani sonuçta sormak istediğim işi bir şekilde hallettim ama birazcık deneme-yanılma yoluyla oldu.İşin teorisinin de kafamda oturmasını istiyorum.Dilerseniz bütün kodları ve isis modelini de yükleyebilirim buraya.

hsaglam

anladığım kadarıyla 16f877 kullanarak projeyi yapmışsınız. gecenlerde bende böyle bir uygulama yaptım. 16f877 'de 10 bitlik adc bulunmaktadır. bu adc'nin lsb'sini ADRESL, msb sini yani üst 2 bitini de ADRESH registerleri içindeki bilgi oluşturmaktadır. bu on bit 1 olduğunda 1023 değeri belirtmiş oluğunuz değişkene aktarılır. Yanılmıyorsan siz bunu adc değişkenine aktarmışsınız. ADRESH bilgisini 8 kere kaydırmakla okunan değerin msb'sini elde etmiş oluyorsunuz.
Yanlız adc değişkeninin içeriği giriş 5 volt olduğunda 1023 değerini alır. Yani girişe 0-5 volt versiğinizde adc'nin içeriği ona göre değişir. Sıra geldi gerçek voltaj değerini hesaplamaya; 5/1023=4,88758 mV yani sizin bit çözünürlüğünüz bu yüzden de değerleri tam olarak okuyamadığınız olabilir.
adc değerini float 4,88758 değeriyle çarpar başka bir değişkene aktarırsınız gerçek voltajın değeri float olarak o değişkene aktarılır. Sonucu int'e çevirip sprintf fonksiyonu ile bir karakter katarına atıp onu da lcd de görüntüleyebilirsiniz (mV olarak)
İnşallah yardımcı olmuşumdur. Kolay gelsin

SpeedyX

int c[5];
void CevirGitsin(long h) {
   int i;
   for (i=0;i<5;i++) {
     c[i]=h%10;
     h-=c[i];
     h/=10;
     lcd_putch(num_to_char(c[i]));
   }
}

x=65535;
CevirGitsin(x);

Böyle birşeyde olabilir mi?

CoşkuN

Bu kod benim yukarıda kullandıklarımı döngü haline getirip daha kısaltıyor sanırım.

arslan74

 unsigned char deger[5] = {0,0,0,0,0};	
  unsigned int adc_val;




void main (void){

    adc_val = read_adc();
    adc_val = convert2mV(adc_val);	
    itoa(adc_val);

}





unsigned int read_adc(void){

	unsigned int val;

	GODONE = 1;
	
	while(GODONE)
		;
		
	val = ADRESL;
	val += ((unsigned int)ADRESH * 256);
	
	return val;
}




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;
}


void itoa(unsigned int value){
	
	deger[0]=value/10000;
	
	value = value -(deger[0]*10000);

	deger[1]=value/1000;

	value = value -(deger[1]*1000);

	deger[2]=value/100;

	value = value -(deger[2]*100);

	deger[3]=value/10;

	value = value -(deger[3]*10);

	deger[4]=value;
		
}