RS232 ile veri alımı

Başlatan hemso, 11 Şubat 2011, 00:12:34

hemso

Merhaba arkadaşlar,

Yaklaşık 6 7 ay önce RS232 ile seri port haberleşmeli bir hesap makinesi yapmıştım. O projede bilgisayardan hyperterminal ile bir değer girip ascii kodlarını da kullanarak gercekleyebilmiştim. Ancak şu an önümde cok cabuk halledilmesi gereken başka bir RS232 projesi var. Projeyi 2 kanattan yürütüyoruz. Diğer arkadaş RFiD etiketli kartı kapıda okutuyor. Eğer kart daha önce oluşturulan vertabanında ise bilgisayara eşleşmenin başarıyla gerçekleştiğine dair 5 ya da 6 bytelık bir bilgi geliyor. Buraya kadar olan kısmı arkadaşım CSHARP programlama dili ile gerçekleştirdi. Buradan sonra benim bu bilgiyi RS232 ile bilgisayardan pic'e gönderip eğer gelen bilgi benim istediğim 5 Byte'lık bilgi ise pic'in daha önceden belirlediğim bir cıkıs portuna lojik 1 vermem gerekiyor. Yani kısacası aldığım veri onay ise pic ledi yakacak gibi düşünebilirsiniz. Şimdi benim burdaki sorunum şu: Hesap makinesi yaptığım zaman bilgisayara girilen bir karakter vardı ve getch() komutu ile bu karakteri alabiliyorduk. Ama burda basılan bir tuş olmadığı için getch fonksiyonunu kullanmam mantıksız olur sanırsam. Veriyi direk nasıl alabilirim ve kontrol olabilirim sizce. 

NOT: Gelen veri 8 er bitlik 5 paket şeklinde sırayla gelecek yanılmıyorsam. Yani mesela 0xFF, 0x01, 0x01,0x11,0x00 olsun.

hemso

Arkadaşlar projeyi böyle yapmak yerine şu duruma indirgedik. Eğer bilgisayardan 00d11 gelirse onay;00y11 gelirse ret cevabı olacak. Onay cevabı: ledin yanması,ret cevabı: ledin yanmaması olarak düşünebilirsiniz. Yazdığım kodda önce char klavye[80] diye bir şey tanımladım daha sonra gets(klavye) dedim.(bunların hepsini rs232 interruptının içinde yapıyorum.) daha sonrada işte if(klavye=="00d11") vs. diyerek programı tamamladım. Ancak program if'li olan satırda hata verdi. Sebebini anlayamadım bir türlü. Sizce hata nerede olabilir? Kod burda:

#include "C:\Documents and Settings\hemso\Desktop\CCS\abc.h"

char klavye[80];
int i;

#int_rda
void serihaberlesme_kesmesi ()
{
   disable_interrupts(int_rda);
   gets(klavye);
   
   if(klavye=="00d11")
   {
     output_high(pin_a2);
     output_high(pin_a4);
     output_high(pin_a3);
     delay_ms(1000);
     output_a(0x00);
     break;
   }
   if(klavye=="00y11")
   {
     output_high(pin_a5);
     for(i=0;i<3;i++)
     {
        output_high(pin_a3);
        delay_ms(500);
        output_low(pin_a3);
        delay_ms(200);
     }
     
     output_a(0x00);
     break;
   }
}

void main()
{
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
//Setup_Oscillator parameter not selected from Intr Oscillator Config tab

   set_tris_a(0x00);
   output_a(0x00);
   
   while(1)
   {
      enable_interrupts(int_rda);
   }

}

eseneren

CCS bilmiyorum ama  if(klavye=="00d11") tırnaklar olacak mı?
Fırat Deveci hitech (soft) kitabında SPI kutuphane hazırlamıs guzel ornegı de var 15 dakıka harcanarak etkın olarak kullanılır dıye dusunuyorum.
Seçim yapmak için durum hakkında bilgi sahibi olmak zorunda değilsin, sonucuna hazır olmak için durum hakkında kaygılanırsın.  http://bit.ly/gixfTk

hemso

Klavye string olacağı için burda bir sorun olmaz diye düşünmüştüm. Hatayı aldıktan sonra değiştireyim diye düşündüm ancak onun alt satırlarında klavye=="00y11" diye bir if li ifade var gene ama orada bir hata görünmüyor. hatta altta çıkan hatayı da yazayım. 1 warning bir de error görünüyor. Hata şöyle:

Warning 203 "rfid.c" line 54(1,1): Condition always true.
Error 44 "rfid.c" Line 12(1,1): Internal Error- Contact CCS LABEL SCR=332
1 Errors, 1 Warnings.

JKramer

Warning çok önemli değil, muhtemelen while(TRUE) şeklinde bir satır için vermiştir.

Hata içinse; derleyici sürümünü yazmamışsınız ama eski bir sürümse güncelleme yapmanız durumunda sorununuz belki çözülebilir. (rfid.c'de ilgili satır nedir, bilmiyoruz.)

mufitsozen

#5
Alıntı yapılan: hemso - 11 Şubat 2011, 01:53:12
Arkadaşlar projeyi böyle yapmak yerine şu duruma indirgedik. Eğer bilgisayardan 00d11 gelirse onay;00y11 gelirse ret cevabı olacak. Onay cevabı: ledin yanması,ret cevabı: ledin yanmaması olarak düşünebilirsiniz. Yazdığım kodda önce char klavye[80] diye bir şey tanımladım daha sonra gets(klavye) dedim.(bunların hepsini rs232 interruptının içinde yapıyorum.) daha sonrada işte if(klavye=="00d11") vs. diyerek programı tamamladım. Ancak program if'li olan satırda hata verdi. Sebebini anlayamadım bir türlü. Sizce hata nerede olabilir? Kod burda:

#include "C:\Documents and Settings\hemso\Desktop\CCS\abc.h"

char klavye[80];
int i;

#int_rda
void serihaberlesme_kesmesi ()
{
   disable_interrupts(int_rda);
   gets(klavye);
   
   if(klavye=="00d11")
   {
     output_high(pin_a2);
     output_high(pin_a4);
     output_high(pin_a3);
     delay_ms(1000);
     output_a(0x00);
     break;
   }
   if(klavye=="00y11")
   {
     output_high(pin_a5);
     for(i=0;i<3;i++)
     {
        output_high(pin_a3);
        delay_ms(500);
        output_low(pin_a3);
        delay_ms(200);
     }
     
     output_a(0x00);
     break;
   }
}

void main()
{
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
//Setup_Oscillator parameter not selected from Intr Oscillator Config tab

   set_tris_a(0x00);
   output_a(0x00);
   
   while(1)
   {
      enable_interrupts(int_rda);
   }

}

Program dili olarak C dilini kullaniyorsunuz değil mi?

O takdirde su iki if dusundugunuz seyi yapmiyor


  • if(klavye=="00d11")
  • if(klavye=="00d11")

C dilinde arrayler (karakter dizinleride dahil olmak uzere) aslinda pointer'dir. Bu yuzden siz klavye string'inin saklandigin yerin pointer'ini  (adresini) "00d11" yada "00y11" stringinin saklandigi yerin adresi ile karsilastiriyorsunuz. Buda herzaman "false" olur. (cunku literal stringler ROMda yada diger degiskenlerden ayri bir segmentda tutulurlar.

iki karakter stringini karsilastirmak icin run-time libraryden strcmp fonksiyonunu kullanmaniz gerekir.

if(1 == strcmp(klavye,"00d11") [veya daha cesursaniz if(strcmp(klavye, "00d11")    :)
  yada
if(1 == strcmp(klavye,"00y11") [veya if(strcmp(klavye,"00y11")]

seklinde.


Aptalca bir soru yoktur ve hiç kimse soru sormayı bırakana kadar aptal olmaz.

hemso

Verdiğiniz bilgiler için çok teşekkür ederim. Bu bilgiler ışığında #include string.h kütüphanesini ekleyerek strcmp fonksiyonuyla dediğiniz işlemi yaptım. Bunun üzerine attempt to create..... tarzında bir hata verdi. Bende bunun üzerine strcmp(klavye,"00d11") yapmadım. 2 adet daha string tanımlayıp bu değerleri stringin içine attım(mesela onay[10]="00d11") ve if(strcmp(klavye,onay)) şeklinde iki diziyi karşılaştırdım ve sonuç olarak hiç hata vermedi. Şimdi kod işlevini yerine getiriyormu diye proteusta deneyeceğim. Umarım beklediğim gibi olur. Tüm yardımlarınız için tekrar teşekkürler. Bu siteyi seviyorum:D

hemso

Maalesef kod şu an işlevini yerine getiremiyor.gets(klavye) dedikten hemen sonra puts(klavye) dedim rs232 calısıyomu diye kontrol edebilmek için ancak herhangi bir şey cıkmadı ekranda...

drmp

if ile yaptığın karşılaştırmayı  bytelara böl ayrı ayrı if içinde sınaya bilirsin ben olsaydım bu şekilde yapardım

hemso

programda mainin içine acaba rs232 calısıyormu diye deneme amaclı olarak printf("quaresma") yazdım ancak virtual terminal ekranında sacma sapan 3 tane harf cıktı. Önce bu sorunu halletmem gerekiyor sanırsam. Kodumun basında yazan ayarlamaları yaptıgım kütüphaneyi yazmamısım onu da belirteyim belki orada düzeltilmesi gereken bir şey vardır:

#include <16F88.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES EC_IO                    //External clock
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES IESO                     //Internal External Switch Over mode enabled

#use delay(clock=20000000)
#use rs232(baud=19200,parity=N,xmit=PIN_B5,rcv=PIN_B2,bits=8)

hemso

Bu arada yukarıdaki xmit ve rcv pinleri yani RS232 aktarımının yapıldığı pinler project wizard dan ayar yaptığımda otomatik olarak a2 ve a3 görünüyordu. Ancak picteki donanımsal olarak görünen usart pinleri(TX ve RX) B5 ve B2 göründüğü için bunları B5 ve B2 pini haline getirdim. Bundan solayı oluşmuş bir sorun da deildir heralde.

hemso

Arkadaşlar beklenti cok düştüğünden ve projenin acelesi olduğunda projenin son hali şu. Bilgisayardan d harfi gelirse ledi yakacak, l harfi gelirse yakmayacak diye düşünün. Harflerin yanlış cıkma olayını da çözdüm bu arada. Bir terslik olmasın diye de int_rda kesmesini de kaldırdım. Pic başka birşey için kullanılmayacak çünkü zaten.Kod şöyle:

#include "D:\rflab\rfid_kapi\deneme1\deneme.h"
#include "string.h"


char klavye[10];
int i;

void main()
{

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
//Setup_Oscillator parameter not selected from Intr Oscillator Config tab

   
 
   
   printf("quaresma");
   while(1)
   {
     klavye[0]=getc();
     putc(klavye[0]);
   
   if(klavye[0]==100)
   {
     output_high(pin_a2);
     output_high(pin_a4);
     output_high(pin_a3);
     delay_ms(1000);
     output_a(0x00);
     break;
   }
   if(klavye[0]==121)
   {
     output_high(pin_a0);
     for(i=0;i<3;i++)
     {
        output_high(pin_a3);
        delay_ms(500);
        output_low(pin_a3);
        delay_ms(200);
     }
     
     output_a(0x00);
     break;
   }
   }


}


Sorun şu virtual terminal ekranında benim printf ile gönderdiğim quaresma yazısı cıkıyor. ancak daha sonra  klavyeden yazdığım herhangi bir karakter ekranda yazmıyor. Burada getch ve putch yerine getc ve putc kullanmamın sebebi unexpected identifier hatası vermesiydi. Sizce sorun nerede?


hemso

Arkadaşlar sürekli yazıyorum kusura bakmayın ama size elde ettiğim gelişmeleri belirtip daha kolay bir çözüm üretebilmeniz acısından bilgilendirmek istediğimden tamamen. Şimdi anladığıma göre esas problem getchar kısmında. Çünkü proteus ta Pic'in TX ve RX pinlerine led bağladım ancak bir tek RX pinindeki led yanmaktaydı. Bunu nasıl çözebilirim?

drmp

bak arkadaş çok güzel anlatmış dostum picte 5 bytelık bir tx -rx registeri yoktur array vardır  fakat ben kodunda gelen byteları array haline sıralayan  bir yer göremedim bu yüzden 5 bytelık bilgisinin sonuncusunu yada karışık bir şey görebilirsin her neyse bu dikkat eet  bu kısım önemli kolay gelsin

ferdem

Lablarının kapısına rfid sistemi labdaki mühendis adayı öğrenciler tasarlıyor, işte bu! Ahmetcim seri data almanın en temiz yolu kesme ile almaktır, while içinde getch vs. ile almak sağlıklı olmaz. Forumda int_rda diye aratıp çıkan başlıkları okumak çoook faydalı olur. Ben o başlıklardaki bir bilgiyi buraya yapıştırarak devam ediyorum:

//picproje.org
//CCS C seri veri kesmesi örnek kullanımı
#include <16F628A.h>
#fuses NOPROTECT, NOMCLR, NOWDT, NOLVP, INTRC_IO
#use delay(clock=4M)
#use rs232(baud=9600, xmit=PIN_b2, rcv=PIN_b1)

unsigned int veri=0;
void main(){
enable_interrupts(global);
enable_interrupts(int_rda);

   while(1){
      output_high(pin_b4);
      delay_ms(1000);
      output_low(pin_b4);
      delay_ms(1000);
   }

}

#int_rda
void seri_veri_geldi(){
veri=getc();
output_toggle(pin_b0);
}


Bu kodda PIC normal seyrindeyken b4 e bağlı led flash yapıyor, veri geldiğinde değer "veri" değişkenine yazılıyor ve b0 pini toggle ediliyor, veri değişkeni global, main içinde de sorgulatabilirsin.
   while(1){
      output_high(pin_b4);
      delay_ms(1000);
      output_low(pin_b4);
      delay_ms(1000);
      if(veri=='A') //eğer A yazarsam aynıyla cevapla ;)
         putc(veri);
   }

yapıp deneyebilirsin.

Şimdi bu kod üzerinden devam etmelisin, elinde 1 byte veri geldiğinde kaçırmadan "veri" değişkenine yazan bir kod var başka ne lazım ki! Bu şekilde gelen stringleri de kontrol edebilirsin. CCS C deki gets fonksiyonu da bu mantıkla yazılmış, kütüphanesinde görebilirsin. Mesela seri data olarak gelen GPS cümleciklerinden önce $ karakterine bakan, $ geldiyse cümle GPGGA cümlesi mi diye kontrol eden int_rda rutini şöyle olabilir:
#int_rda 
void seri_veri_geldi(){ 

veri=getc(); 
output_toggle(pin_d0); 

if(veri=='$'){ // $ karakterini gördük
   index=0;
   out=0;
   record=1;
   i=0;
   return;
 
}

if(record==1){
c[index]=veri;
index++;
if(index==5) //5 byte alındıysa
record=0;
   if(c[0]=='G' && c[1]=='P' && c[2]=='G' && c[3]=='G' && c[4]=='A'){ //GPGGA cümlesi mi kontrol et
      out=1; //GPGGA cümlesi, out=1, sıradaki bytle lar lcdye gidecek
      i=0;
      record=0;
      c[0]=0;c[1]=0;c[2]=0;c[3]=0;c[4]=0; //temizle
   }   
return;   
}
//...kod devam ediyor

Bu şekilde siz de kendi int_rda rutininizi yazmalısınız.
#int_rda
void seri_veri_geldi(){
veri=getc();
putc(veri);
output_toggle(pin_b0);
}

Yazarsan klavyeden yazdığını aynen geri alırsın.


İyi çalışmalar, kolay gelsin.