İki pic arasında Rs232 ile float veri gönderip alma hakkında yardım!

Başlatan eren.guven, 09 Aralık 2014, 19:57:53

eren.guven

Merhaba arkadaşlar,

Bu soru hakkında daha önce açılan başlıklar var fakat ben bir sonuç göremedim. Yapan oldu yaptım demiş ve bırakmış örnek kodları paylaşmamış.


Benim sorum şöyle. Sıcaklık nem gibi bir float data bilgisini bir picten  diğer bir pice atıcam. 

printf("%f ", bilgi) komutu ile bilgi float verisini gönderebiliyorum.  Fakat bu bilgiyi alacak komutlar benim bildiğim iki tane char datası için getc() ,  string ifadeler için ise gets(), Bu gönderdiğim datayı nasıl alıp lcd'ye yükleyeceğim. 4-5 gündür uğraşıyorum  bir çözüm bulamadım.
Örnek olarak bilgi=20.3 verisini nasıl bir picten diğer bir pice atabilirim. Yardımcı olursanız çok sevinirim. Saygılar.


ismailhtc

gönderen picten float değerini  integere çevirip göndersen, alıcı devresindende integer değerini alıp floata çevirsen olmaz mı?

mesela 20.3 değerini 10 ile çarp 203 olur. bununu alıcı picte 10'a böl 20.3 elde etmiş olursun.

yani sorunu yanlış anlamadıysam böyle yapılabilir derim.

Salih

Bu konuda forumda çok net bir çözüm olmadığı için kendimin hazırladığı
ve denediği programları aşağıya veriyorum.
Denemek isteyenler için proteus dosyasınıda veriyorum.

Verici devresi.

#Include  <16F877.h>
#Fuses XT
#OPT 1
#Use Delay(clock=8000000)
#use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,errors)

float s1=145.0;
int8 *a1;
int8 x1,x2,x3,x4;

Void Main()
{
   Setup_psp(PSP_DISABLED);
   Setup_spi(SPI_SS_DISABLED);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T1_DISABLED,0,1);   
   Setup_adc_ports(NO_ANALOGS);
   Setup_adc(ADC_OFF);
   Setup_CCP1(CCP_OFF);
   Setup_CCP2(CCP_OFF);   
   Port_B_Pullups(True);   
   Delay_ms(10);
   
      While(True)
      {       
        if (input(Pin_B0))
           {
               s1 = s1 + 1.25;
               a1  = &s1;
               x1 = *a1;a1++;
               x2 = *a1;a1++;
               x3 = *a1;a1++;
               x4 = *a1;
               putc(x1);// Float sayıyı 4 bayta ayırdıktan sonra gönderiyoruz.
               putc(x2);
               putc(x3);
               putc(x4);
               while(input(Pin_B0));
           }             
      }
}


Alıcı devresi

#Include  <16F877.h>
#Fuses XT
#OPT 1
#Use Delay(clock=8000000)
#use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,errors)
#include <Lcd.c>

float s1=0.0;
int8 *a1;
int8 x1,x2,x3,x4;

Void Main()
{
   Setup_psp(PSP_DISABLED);
   Setup_spi(SPI_SS_DISABLED);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T1_DISABLED,0,1);   
   Setup_adc_ports(NO_ANALOGS);
   Setup_adc(ADC_OFF);
   Setup_CCP1(CCP_OFF);
   Setup_CCP2(CCP_OFF);   
   Port_B_Pullups(True); 
   Lcd_init();
   Delay_ms(10);
   
      While(True)
      {       
               x1 = getc();
               x2 = getc();
               x3 = getc();
               x4 = getc();
        
                 a1  = &s1;
               *a1 = x1;a1++;
               *a1 = x2;a1++;
               *a1 = x3;a1++;
               *a1 = x4;
                      
         printf(lcd_putc,"\fs1=%.5f",s1); 
      }
}


deneme programı

https://dl.dropboxusercontent.com/u/20087162/Pic_Program/Pointerler.pdsprj

eren.guven

Gönderdiğiniz kod çalışmıyor. Link formatını da açıkcası anlayamadım. başka yardımcı olabileceğiniz bir yol var ise çok sevinirim.

Make8 komutuyla bu işlemi yapmaya çalıştım. Örneğin göndermek istediğim sayı 45.8, ama aldığım sayı 1202. Gönderme yöntemi şöyle:

double n=45.8;
int16  a;
int8 b ;
int8 c ;

while(1){
  // if(!input(pin_a0) && input(pin_a1) ){
    putc('R');
    delay_ms(50);
    putc('T');
     delay_ms(50);
     a=10*n ;
     b=make8(a,1);
     c=make8(a,0); 
   
   printf("%u",b);
    delay_ms(50);
   printf("%u",c);

   
   delay_ms(1000);


Gökhan BEKEN

Alıntı yapılan: ismailhtc - 10 Aralık 2014, 18:23:55
gönderen picten float değerini  integere çevirip göndersen, alıcı devresindende integer değerini alıp floata çevirsen olmaz mı?

mesela 20.3 değerini 10 ile çarp 203 olur. bununu alıcı picte 10'a böl 20.3 elde etmiş olursun.

yani sorunu yanlış anlamadıysam böyle yapılabilir derim.
8 bitlik bir değişkene bu yöntem ile maksimum 25,5 değerini yazabilirsiniz, çünkü 255'i aşarsa 0'a dönecektir.
Eğer 30,5 sayısını 10 ile çarparsanız 305 olur, bunu 8 bitlik bir değişkene atarsanız 105 elde edersiniz. Bu hiç istenmeyen bir durumdur.

Yöntemler:
Sayıyı ya string olarak gönderip sonuna \r ekleyin, ya da sayıyı 3 byte halinde gönderin, sayının başına bir paket başlangıcı koyun bu bir özel karakter olsun mesela '~' yani tilda veya '$' yani dolar olsun. 2.byte ise sayının tam kısmı olsun. 3. byte ise virgüllü kısım olsun.
Örneğin 26,8 sayısı göndermek için,
gonderilecek[3]={'$',26,8}
yapın.

Alırken ise $ karakterini kontrol edeceksiniz, bu karakteri gördüğünüz zaman peşinden gelen 2 byte'ın ilk byte'ı tam, ikincisini yazmadan önce virgül yazacaksınız.
Özel mesaj okumuyorum, lütfen göndermeyin.

musti463

denemelerini proteus da yapıyorsan. Yapma. Devresini breadboard üzerine kur öyle dene çünkü ISIS de sıkıntı oluyor.
Mustafa Emir SADE

Salih

Boşuna vakit kaybetme. Kendi yazıp denediğim programları gönderdim. Proteus 8.1 ver. çalışan deneme devresinide gönderdim.
Öncelikle protues 8.1 programını kur ve gönderdiğim devreyi çalıştır. Çalıştığını göreceksin.

eren.guven

Alıntı yapılan: meftun - 12 Aralık 2014, 23:24:41
8 bitlik bir değişkene bu yöntem ile maksimum 25,5 değerini yazabilirsiniz, çünkü 255'i aşarsa 0'a dönecektir.
Eğer 30,5 sayısını 10 ile çarparsanız 305 olur, bunu 8 bitlik bir değişkene atarsanız 105 elde edersiniz. Bu hiç istenmeyen bir durumdur.

Yöntemler:
Sayıyı ya string olarak gönderip sonuna \r ekleyin, ya da sayıyı 3 byte halinde gönderin, sayının başına bir paket başlangıcı koyun bu bir özel karakter olsun mesela '~' yani tilda veya '$' yani dolar olsun. 2.byte ise sayının tam kısmı olsun. 3. byte ise virgüllü kısım olsun.
Örneğin 26,8 sayısı göndermek için,
gonderilecek[3]={'$',26,8}
yapın.

Alırken ise $ karakterini kontrol edeceksiniz, bu karakteri gördüğünüz zaman peşinden gelen 2 byte'ın ilk byte'ı tam, ikincisini yazmadan önce virgül yazacaksınız.

Merhaba,

float sayıyı printf ile gönderip string olarak gets komutu olarak almayı denemiştim. printf komutunda \r ile gönderilmesi gerektiğini okumuştum. O kadar çok şey denedim ki bu yöntemi de denemiştim ama olmamıştı. En son okulda hoca string ile kesin alırsın dedi veriyi gönderip enter gelmesini bekler dedi \r'nin oradaki işi enter yani satır başı yapmak. Bende bunun üzerine yoğunlaşıp en basit komutlar üzerinde demeler yaptım.

Veriyi gets(); komutu ile aldım.  Meğersem çok basit bir olaymış rf haberleşme rs232'yi kullanmak. Fakat proteus insanı çıldırtabiliyor.

Rf ile uğraşacaklara benim bazı önerilerim var.En azından sıfırdan bakacaklara. Bilen zaten 10 dakikada yapar.

Yeni başlayacak olan arkadaşlar ilk önce veriyi doğru mu gönderiyoruz onu kontrol etmemiz lazım. "RS232 Seri İletişim Uygulaması" adı altında google'da aratın. Oradan hazır proteus dosyası da olan bir uygulama var. Orada 16f877 vericisine göndereğiniz  komutu yükleyin. Bakalım yüklediğiniz doğru gözükecek mi? Özellikle string olarak almak istiyorsanız  hep alt alta yazması lazım verileri.

Daha sonra baud oranı önemli. Benim devrede 600 ile veri atıyor. 300 veya 9600 yapıyorum çalışmıyor.  Sonra mesela delay_ms(); ile komuta gecikmeler ekledim. Herhalde bazı yerlere o gecikmenin gelmemesi lazım(yada delaydan değil ben  öyle sandım) .Bazı yerlerde de tabiki delay_ms(); gerekli.

En son olarak da ccs-c compiler'ın bir garipliği var.Onuda belirtmek isterim. genelde alıcı ve verici dosyasını aynı aynda açtığımda ve compile ettiğimde üzerinde çalıştığımız C kaynak dosyası değişirken hex dosyası değişmiyor. Yani tarihlere saate bakarak compile edip etmediğimizi proteusta dosyayı pic'e yüklerken kontrol etmekte fayda var. Belki sırf bu yüzden çalışan kodu compiler etmediği için önceleri çalışmadı sanmış olabilirim.

Ben internette herkesin bildiği kodları hazır olan lm35 sensörünü 16f877a'a okuyup rs232 ile 16f628a'a atıp oradan da lcd'ye yazdıran bir örnek yaptım. Çok da güzel çalıştı.Komutları aşağıda paylaşıyorum.

Göndericide;

unsigned long int bilgi; // İşaretsiz 16 bitlik tam sayı tipinde değişken tanımlanıyor
float voltaj,sicaklik; // ondalıklı tipte değişkenler tanıtılıyor
.
.
.
.
while(1){
putc('Y);
    delay_ms(50);
    putc('Z');
    delay_ms(50);
   
    bilgi=read_adc(); // ADC sonucu okunuyor ve bilgi değişkeni
    voltaj=(0.0048828125*bilgi)*1000; // Dijitale çevirme işlemine uğrayan sinyalin mV olarak gerilimi hesaplanıyor
    sicaklik=(voltaj/10); // Her 10mV'ta 1 derece artma
   
    printf( "%f\r",sicaklik);
}

Alıcıda ise ;

int a;
char x[10];
.
.
.
while(1){
   
   if(getc()=='Y'){
      a=getc();
   }
      if(a=='Z'){
         
   gets(x);
   lcd_send_byte(0,0x01);
   printf(lcd_putc,"sicaklik= %s ",x);
   delay_ms(50);
  }

-------------------------------------------------------


Herkese teşekkür ederim arkadaşlar umarım yardımcı olmuştur.


Salih

@eren.guven,
bence kulağını tersten tutmuşsun ve işi uzatmışsın.
Benim yaptığım çözüm daha optimaldır.
Ama yinede sen bilirsin.

eren.guven

Alıntı yapılan: salih - 13 Aralık 2014, 15:57:34
@eren.guven,
bence kulağını tersten tutmuşsun ve işi uzatmışsın.
Benim yaptığım çözüm daha optimaldır.
Ama yinede sen bilirsin.

Hocam ben sizin gönderdiğiniz programı çalıştıramadım. Gönderdiğiniz dosya .pdsprj uzantılı  bunu proteusta açamadım. Kodları alıp kullandım oda çalışmadı gönderilen veri anlamsız oluyor.

Salih

Alıntı yapılan: eren.guven - 14 Aralık 2014, 18:28:01
Hocam ben sizin gönderdiğiniz programı çalıştıramadım. Gönderdiğiniz dosya .pdsprj uzantılı  bunu proteusta açamadım. Kodları alıp kullandım oda çalışmadı gönderilen veri anlamsız oluyor.

Proteus 8.1 versiyonu dosyasıdır. Onun için gerekli versiyonu kurarsan deneyebilirsin. Belki gözünden kaçmıştır.
Alıcı ve verici PIC leri Çalışma frekansı 8 Mhz olarak ayarlıydı.

Gökhan BEKEN

Benim dediğim yöntemi bir çok projemde kullanıyorum hiç sorun yaşamadım. Mesela paket başlangıcı olarak 2 karakter kullanmış olsaydık,
Gönderici 57,4 sayısını göndermek istiyorsa
unsigned char tamKisim=57;
unsigned char ondalikliKisim=4;
SendUart("&~");
SendUart(tamKisim);
SendUart(ondalikliKisim);

alıcı tarafından kesme içerisinde şöyle birşey yazmamız gerekirdi:

unsigned char eskiVeri = 0; //global
unsigned char yeniVeri = 0;	
unsigned char tamKisim = 0;
unsigned char ondalikliKisim = 0;
void UartInterrupt(void){ //kesme fonksiyonu
                sp->Read(veri, 0, 1); //gelen 1byte'lık veriyi alıyoruz
                eskiVeri = yeniVeri; //bir önceki veriyi kaydediyoruz.
	        yeniVeri = veri[0];
                if (yeniVeri == '~' && eskiVeri == '&')//paket başlangıcı kontrol ediliyor
		{
                        unsigned char asilVeri[2]; 
			sp->Read(asilVeri, 0, 2); //paketin içeriği alınıyor

			tamKisim = asilVeri[0];
			ondalikliKisim = asilVeri[1];

			sp->DiscardInBuffer(); //buffer'i temizle
		}
}
Özel mesaj okumuyorum, lütfen göndermeyin.

Salih

@meftun,
benim verdiğim örnek de olduğu gibi float sayıyı baytlarına ayırıp
göndermek daha kolay ve optimal değilmi?

Gökhan BEKEN

@salih hocam zaten aynı yöntem ama ufak farklar var.
Sizin yöntem sağlık çalışmaz çünkü paket başlangıcı olarak ayırtedici birşey kullanmamışsınız. Sürekli sayı gönderdiğinizde sayıların sıralaması karışır.
Bunun dışında bir eksiklik daha var, bu işleri interrupt içerisinde yapmak şart olmasa da gereklidir. Ana fonksiyon içerisinde başka işler yapılacaksa kesme en iyisi.
Özel mesaj okumuyorum, lütfen göndermeyin.

Salih

Alıntı yapılan: meftun - 14 Aralık 2014, 22:10:36
@salih hocam zaten aynı yöntem ama ufak farklar var.
Sizin yöntem sağlık çalışmaz çünkü paket başlangıcı olarak ayırtedici birşey kullanmamışsınız. Sürekli sayı gönderdiğinizde sayıların sıralaması karışır.
Bunun dışında bir eksiklik daha var, bu işleri interrupt içerisinde yapmak şart olmasa da gereklidir. Ana fonksiyon içerisinde başka işler yapılacaksa kesme en iyisi.

Sana katılıyorum. Bende uygulamalarım da data paketi ve haberleşme kesmesi kullanırım.
Ben sadece float sayıyı baytlarına ayırma ve basit bir deneme devresi ile denemeyi amaçladım.