PIC C ile ADC ve Casting Sorunu

Başlatan barisertekin, 03 Eylül 2011, 16:49:16

barisertekin

Arkadaşlar PIC Basic ten PIC C ye geçiş yaptım. Ufak bir problem var.

#include "16f877a.h"//Mikrodenetleyici seçilir
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,PUT//Sigortalar seçilir
#use delay (clock=4000000)//Osilatör hızı belirlenir
#use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8)
#use fast_io(b)//Bu satır ile port B için elle ayarlama yapılacağı belirtilir.

void main(void)
{
   int16 adc_value;
   
   /* adc modülü ayarlanıyor */
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(ALL_ANALOG);
   set_adc_channel(0);//analog olcumun 0. pinden olacagi ayarlandi.
                   
   disable_interrupts(GLOBAL);//Kesmeler iptal edilir
   
   while(true)
   {
      /* 1. ADC kanalını seç  ve değeri oku*/
      set_adc_channel(0);
      delay_us(10);
      adc_value = read_adc();
      adc_value=0.0048828125*adc_value;
      adc_value=5; //Bu atamayı test için yaptım.
      putc(adc_value); // putc('5') yazınca bilgisayara gönderiyor fakat putc(5) yazınca göndermiyor. putc((char)adc_value) denedim o da olmadı.
      delay_ms(500);
      putc('0');
      delay_ms(500);
   }
}

Şu cast etme işini halledersek adc çalışacak mı bakıcaz.
Program bu hali ile sürekli 0 datasını gönderiyor.

Teşekkürler.

Klein

Binary değerin ascii olarak göndermek istiyorsun. Böyle de gönderirsin ama  karşı tarafta bu değeri ASCII olarak göremezsin.

Bunun için önce ADC değerini basamaklarına ayırmalısın. Yani ADC değerin 185 ise, 1 , 8  ve 5 değerlerini ayrı ayrı bulup sonra da her bir değeri 48 ile toplayarak 3 aşamada bilgisayara göndermelisin.
a = 1;
b = 8;
c = 5; ise
putc(a+48); // Buradaki 48 ASCII tablosunda '0' karakterine karşılık gelir.
putc(b+48);
putc(c+48); şeklinde.

Bunun için hazır fonksiyonlar var. Birçok derleyiccide printf() fonksiyonu için standart çıkış aygıtı seri porttur.
Eğer sizin çıkış aygıtınız da seri portsa:
Örnek:
ADC değerin unsigned int veya unsigned char tipi bir değişkense
printf("%u",ADC);  şeklinde gönderebilirsiniz.

eğer standart çıkış aygıtı seri port değilse sayıyı önce basamaklarına ayırmamız gerekecek.
Bunun için C kütüphanesindeki standart fonksiyonlardan birisi kullanılmayacaksa

unsigned char ADC;
unsigned char buffer[3];

ADC = 185
buffer[0] = ADC % 10;
buffer[1] = (ADC / 10) % 10;
buffer[2] = (ADC / 100) %10;

putc(buffer[0]+48);
putc(buffer[1]+48);
putc(buffer[2]+48);

şeklinde gönderebilirsiniz.

Bunun yanında <stdlib> kütüphanesindeki
itoa(......); fonksiyonunu kullanabilirsiniz.

itoa(ADC,buffer,10); //  10 tabanında çevirim yapacağını bildirir.
putc(buffer[0]);
putc(buffer[1]);
putc(buffer[2]);



barisertekin

#2
Çok teşekkür ederim. Gayet açıklayıcı oldunuz.

Potansiyometre ile voltaj ölçümü yapıyorum. Ekranda 001,002,003,004 değerlerini gördüm.

Biz buffer dizisini tanımlarken 3 elemanlı tanımladık. Bize gelen veri 10 bit adc olduğundan max 1023 değeri yani buffer[4]'mü olması gerekiyor. Yada bunu runtime belirleyemez miyiz?

Bu düzenlemeyi yapınca voltaj küsüratları da gözükecek diye umuyorum.

Kodun son hali;

int16 adc_value;
unsigned char buffer[4];

while(true)
{
      adc_value = read_adc();
      adc_value=0.0048828125*adc_value;

      buffer[0] = adc_value % 10;
      buffer[1] = (adc_value / 10) % 10;
      buffer[2] = (adc_value / 100) %10;
      buffer[3] = (adc_value / 1000) %10;
     
      putc(buffer[3]+48);
      putc(buffer[2]+48);
      putc(buffer[1]+48);
      putc(buffer[0]+48);
           
      delay_ms(500);
      putc('-');
      delay_ms(500);
}

Output: 0003-0002-0001-0002-0003-0004 gibi. Küsüratlar yok.

Klein

#3
int sayılarla çalışıyorun. zetn küsuratlar yok. Sorun küsuratı gösteremiyor olman değil. Kullandığın değişkenin tamsayı değişken olması. Küsurat göstermek için Floating-point kullanman gerekir.
O zaman da basit matematik veya itoa(...) kullanamazsın.
Eğer float kullanacaksan

float ADC;
char buffer[10];

ADC = 1376.289
sprintf(buffer,"%8.3f",ADC); Nokta dahil toplam 8 hane noktadan sonra 3 hane.
sprintf(buffer,"%f",ADC); // toplam 10 hane. Tamsayı uzunluğuna göre noktadan sonraki kısım değişir. toplam uzunluk derleyiciye , kaç bit float yaptığına göre değişir.


Ekleme:
Dizi boyunu Runtime ayarlamak için dinamik hafıza yönetimi küüphanesini kullanman gerekir.
Dinamik dizi yönetim biraz risklidir. Statik dizi kullanman şimdilik daha iyi.





barisertekin

#4
Anlaşıldı. double denemiştim. Derleme hatası verince bıraktım tabi küsüratı alamayız gözümden kaçmış.

adc_value = read_adc();
adc_value=0.0048875855327468*adc_value;

sprintf(buffer,"%8.3f",adc_value);
sprintf(buffer,"%f",adc_value);
Bu 2 satırdan bir tanesini kullanmam gerekiyor sanırım.
Sprintf sadece buffer üzerinde düzenleme yapıyor. Porttan çıkış yapmıyor değil mi?


Eğer yapmıyorsa porttan çıkışı nasıl yapacağım.
Önceden;

//putc(buffer[3]+48);
//putc(buffer[2]+48);
//putc(buffer[1]+48);
//putc(buffer[0]+48);

şeklinde yapıyordum. Şimdi değişti. For düngüsü ile 10 eleman için mi yapacağım?

Kodun son hali;

float adc_value;
unsigned char buffer[10];

while(true)
{
      adc_value = read_adc();
      adc_value=0.0048875855327468*adc_value;

      sprintf(buffer,"%f",adc_value);

      putc(buffer[9]+48);
      putc(buffer[8]+48);
      putc(buffer[7]+48);
      putc(buffer[6]+48);
      putc(buffer[5]+48);
      putc(buffer[4]+48);
      putc(buffer[3]+48);
      putc(buffer[2]+48);
      putc(buffer[1]+48);
      putc(buffer[0]+48);
           
      delay_ms(500);
      putc('-');
      delay_ms(500);
}

Klein

Artık +48 yok. Çünkü dizimizin elemanları artık ASCII karakterler.

Porta gönderme yapmıyor. Son koddaki +48 kaldırısan tamamdır.

doğrudan porta göndermek için prntf("%f",ADC); dene. eğer default çıkış aygıtın seri port ise bu şekilde gönderirsin.

barisertekin

#6
Tamamdır. Fıstık gibi çalışıyor.

printf("%f",adc_value); kullandım.

"Eğer default çıkış aygıtın seri port ise bu şekilde gönderirsin." diye belirtmişsiniz. Ben böyle bir ayar yapmadım.

Eğer aynı zamanda bir LCD ekran sürüyor isem. Böyle bir ayrım yapmak gerekiyor sanırım.
O zaman bunu nasıl ayarlıyoruz?

Klein

Bildiğim kadarıyla; çıkış aygıtı runtime ayarlanmıyor. Derleyici yönergeleri ile ayarlanıyor.
tanımlar <conio.h> dosyasında diye hatırlıyorum. Yanılıyor olabilirim.

JKramer

İlgili lcd dosyasını ekledikten sonra
printf(lcd_putc,"....",...);
şeklinde.