seri port kesmesinden alınan deger baska degiskene esitlenince saçmalıyor.

Başlatan burak ozturk, 10 Temmuz 2013, 17:12:33

burak ozturk

çıkamadığım bir döngü içerisine girdim :) şöyleki;

seri port kesmesinin içinde

#int_rda   // RX ucuna veri gelince meydane gelen kesme
void serihaberlesme_kesmesi ()
{
   int c;
   disable_interrupts(int_rda); // int_rda kesmesini pasif yap
   c=getchar();
   putc(c,gps);
   }


yada

#int_rda   // RX ucuna veri gelince meydane gelen kesme
void serihaberlesme_kesmesi ()
{
   int c;
   disable_interrupts(int_rda); // int_rda kesmesini pasif yap
   c=getchar();
   nmea[i]=c;
   
   if (isdigit(c))
   
   {
    putc(c,gps);

   }


şeklinde seri porttan gelen bilgiyi geri bastıgımda üstteki kodda birebir seri porttan gelen degeri, alttakinde ise nmea kodun içindeki sayıları terminal programında görebiliyorum, bu yuzden seri port kesmesine düzgün girip çıktıgımı düşünüyorum.ancak ;

#int_rda   // RX ucuna veri gelince meydane gelen kesme
void serihaberlesme_kesmesi ()
{
   int c;
   disable_interrupts(int_rda); // int_rda kesmesini pasif yap
   c=getchar();
   nmea[i]=c;
   
  if (isdigit(c))
   
   {
    val=c;
    putc(val,gps);

   }


yukarıdaki gibi c yi val değişkenine atıp seri porttan basarsam orjinal degeri yerine 0x00 değeri görüyorum.

kafam gayet karışmış durumda.seriden gelen bilgi ascii(0-255 arası) olarak düşünüyorum.bunu int diziye atip,işime yarar kısmını farklı değişkene atmaya çalışıyorum olmuyor,gelen bilgiyi char stringe yazdırıp , atoi ile int e dönüştürmeyi deniyorum yine olmuyor, isdigitle bari rakamları ayıklayıp iş yapayım diyorum başka değişkene attıgımda olayın rengi değişmiş oluyor ki bir türlü çıkamadım işin içinden. :)

kodumun tümü;

/******************************************************

*******************************************************/

#include <16f877.h>     
#include <stdlib.h>
#include <ctype.h>

// Denetleyici konfigürasyon ayarları
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD

#use delay (clock=20000000) 

#use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, parity=N, stop=1, STREAM=gps, ERRORS) 
                                                                  

int data1[10]={0x3f,0x6,0x5b,0x4f,0x66,0x6d,0x7d,0x7,0x7f,0x6f};                                                                  
int val;                                                                  
unsigned int son[];
int   nmea[];
int i=0;
int z=0;


#int_rda   
void serihaberlesme_kesmesi ()
{
   int c;
   disable_interrupts(int_rda); 
   c=getchar();
   nmea[i]=c;
   
  if (isdigit(c))
   
   {
    val=c;
    putc(val,gps);
   }
   
   
         if(nmea[i]=='$')
        {
        output_toggle(pin_a1);
        i=0;
        break;
        } 

         i++;


       
   

}




/********* ANA PROGRAM FONKSİYONU********/

void main ( )
{
   setup_psp(PSP_DISABLED);        // PSP birimi devre dışı
   setup_timer_1(T1_DISABLED);     // T1 zamanlayıcısı devre dışı
   setup_timer_2(T2_DISABLED,0,1); // T2 zamanlayıcısı devre dışı
   setup_adc_ports(NO_ANALOGS);    // ANALOG giriş yok
   setup_adc(ADC_OFF);             // ADC birimi devre dışı
   setup_CCP1(CCP_OFF);            // CCP1 birimi devre dışı
   setup_CCP2(CCP_OFF);            // CCP2 birimi devre dışı
   //display_init(0); 

   output_low(pin_b5); // RC5 çıkışı ilk anda sıfırlanıyor
   enable_interrupts(GLOBAL);  // Aktif edilen tüm kesmelere izin ver

   while(1) // Sonsuz döngü
   {
      enable_interrupts(int_rda); // int_rda kesmesi aktif      
 
   }
   
}   
   
   
   
happy coding.

MrDarK

İnterrupt içini çok geniş tutmamakta fayda var. Yapmaya çalıştığın işi anlıyorum

$GPRMC kodlarını çekeceksin akan tüm datadan doğru mudur ? Char formatında nmea dizi oluştur 100 - 200 karakter veya altı olabilir sonra ana main içinde sürekli dizi içindeki aramak istediğin kodu gir.

Genelde ben bu şekilde kullanıyorum kesme içinde sadece gelen veriyi dizi içine atarım ana döngüdede kelime kelime sorgu yapıp doğru kod geldiyse işlem yaparım.
Picproje Eğitim Gönüllüleri ~ MrDarK

rree

     Amaç nedir anlamdım ama benim yazdığım bir seri Rx data toplayıcısı işini görürümü?
Aşağıdaki program Satır sonu işaretini gördükten sonra enter işareti gelene kadar dataları diziye atar.
Enter işaretinden sonra gtemp den bilgiyi global diziyi atar ve data geldi bilgisini 1 yapar.
Eğer enter işareti gelene kadar rxdatası 0 ise boşluk karekteri yerleştirir. Bu da string işlemler için önemli.
Başka nokta enter işaretini gödükten sonra  dizideki string ifade olabilmesi için sonuna null yani sıfır yerleştririr.
   
#int_RDA
void  RDA_isr(void) 
{int8 Rx1Dati,i;
    Rx1Dati=Getchar(Uart_1);
   
   if(Rx1Dati!=0x0A)
      {
         
         if (Rx1Dati==0x0D) 
             {  
                RxDataTemp[Rxj]=0; // '0' karekteri ekle
                For (i=0;i<=29;i++)
                   {
                      RxDataGlb[i]=RxDataTemp[i]; // Datayı aktar
                      RxDataTemp[i]=0;
                   }    
                RxDataGlb[29]=0;// Taşma olmasın
                Rxj=0;
                Rx1DataGeldi=1;
                GsmStatusAL();
                
             }
             else
             {  
                if(Rx1Dati==0)
                  {
                    RxDataTemp[Rxj]=' '; //Eğer sıfır ise boşluk yap
                  }
                  else
                  {
                    RxDataTemp[Rxj]=Rx1Dati; // Datayı Tempe Al
                  }
                
               
               Rxj=Rxj+1;
             } 
      }
   
}   

   



burak ozturk

hocam cevapladığınız için sağolun.

aslında çekmeye çalıştıgım cümle $GPRMC ye göre son derece basit ;


$WIMWV,059.0,T,00.6,M,A*1C

tam olarak bu ; çok basit diyerekten atladığım olayda afallamış durumdayım.

dediğiniz gibi sadece gelen datayı nmea içerisine atıp oradan ayıklamayı denedim ancak muhtemel tür dönüşümlerinden mütevellit değişken içine giren datam değişiyor.

bayağı ugraştım birde farklı yollardan virgül sayıp dataları içeri alaraktan deneyeyim belki çalışır . gelişmeleri tekrar bildiririm kolay gelsin.

rree hocam mesajınızı yanıt yazarken gördüm sizin kodları anlamaya çalışıp deneyeyim , cevap için teşekkürler.

mesaj birleştirme:: 11 Temmuz 2013, 01:10:33

Alıntı yapılan: rree - 11 Temmuz 2013, 00:26:37
     Amaç nedir anlamdım ama benim yazdığım bir seri Rx data toplayıcısı işini görürümü?
Aşağıdaki program Satır sonu işaretini gördükten sonra enter işareti gelene kadar dataları diziye atar.
Enter işaretinden sonra gtemp den bilgiyi global diziyi atar ve data geldi bilgisini 1 yapar.
Eğer enter işareti gelene kadar rxdatası 0 ise boşluk karekteri yerleştirir. Bu da string işlemler için önemli.
Başka nokta enter işaretini gödükten sonra  dizideki string ifade olabilmesi için sonuna null yani sıfır yerleştririr.
   
#int_RDA
void  RDA_isr(void) 
{int8 Rx1Dati,i;
    Rx1Dati=Getchar(Uart_1);
   
   if(Rx1Dati!=0x0A)
      {
         
         if (Rx1Dati==0x0D) 
             {  
                RxDataTemp[Rxj]=0; // '0' karekteri ekle
                For (i=0;i<=29;i++)
                   {
                      RxDataGlb[i]=RxDataTemp[i]; // Datayı aktar
                      RxDataTemp[i]=0;
                   }    
                RxDataGlb[29]=0;// Taşma olmasın
                Rxj=0;
                Rx1DataGeldi=1;
                GsmStatusAL();
                
             }
             else
             {  
                if(Rx1Dati==0)
                  {
                    RxDataTemp[Rxj]=' '; //Eğer sıfır ise boşluk yap
                  }
                  else
                  {
                    RxDataTemp[Rxj]=Rx1Dati; // Datayı Tempe Al
                  }
                
               
               Rxj=Rxj+1;
             } 
      }
   
}   

   


hocam amacım aslında verinin neden değiştiğini anlamak, o kadar çok ugraştım ki cümleyi almayı çalışmayı bırakıp karakterin başka değişkene atıldığında neden değiştigini bulmaya çalışıyorum.yukarıdaki kodlar ondan size manasız gelmiş olabilir. sizin kodları inceliyorum hocam, cevabınız için tekrar teşekkürler.
happy coding.

hasankara

gps_veri_oku() {
veri=getch(); if(getch_bitti){getch_bitti=0;
gprmc_yakalama(); gps_veri_oku_bitti=1; }
 }
//_/__/___/____/_____/______/_______/________/_________/__________/
gprmc_yakalama(){
 
switch (mlt_gprmc_kontrol){
/* $GPRMC anahtar denetlemesi yapilir.*/
case 0: if(veri==*"$") {mlt_gprmc_kontrol=1;}
 else {mlt_gprmc_kontrol=0;} break;
case 1: if(veri==*"G") {mlt_gprmc_kontrol=2;}
 else {mlt_gprmc_kontrol=0;} break;
case 2: if(veri==*"P") {mlt_gprmc_kontrol=3;}
 else {mlt_gprmc_kontrol=0;} break;
case 3: if(veri==*"R") {mlt_gprmc_kontrol=4;}
 else {mlt_gprmc_kontrol=0;} break;
case 4: if(veri==*"M") {mlt_gprmc_kontrol=5;}
 else {mlt_gprmc_kontrol=0;} break;
case 5: if(veri==*"C") {mlt_gprmc_kontrol=6; v_sayac=0;}
 else {mlt_gprmc_kontrol=0;} break;
/* $GPRMC anahtari goruldukten sonra, gelen veriler
sirasiyla kayit altina alinir.*/
case 6: gprmc_sayac++;
 if(veri==44){v_sayac++;gprmc_sayac=0;}
 else if(v_sayac==1&&gprmc_sayac<7)zaman[gprmc_sayac]=veri;
 else if(v_sayac==3&&gprmc_sayac<11)north[gprmc_sayac]=veri;
 else if(v_sayac==5&&gprmc_sayac<12)east[gprmc_sayac]=veri;
 else if(v_sayac==9&&gprmc_sayac<7)tarih[gprmc_sayac]=veri;

 if(v_sayac>9){mlt_gprmc_kontrol=0; gprmc_yakalama_bitti=1;} break;
 
default: mlt_gprmc_kontrol=0; break;}
}


bende bu şekilde verileri anlık olarak yakalamıştım. gps_veri_oku(); çok sık denetleyince veri atlama olmuyordu, zaten veri atlayacak duruma sokunca programı, artık veri almamaya başlıyordu.

gps_veri_oku() {
veri=getchar(); gprmc_yakalama();
 }


şeklinde değişikliği yaptıktan sonra interrupt içinde gps_veri_oku(); çağırdığında istediğin kısımları ayıklayabilirsin.

bir de gprmc_yakalama(); içerisinde if(veri==*"$") gibi istediğin anahtar kelimeyi sıralayabilirsin.

if(v_sayac==1&&gprmc_sayac<7)zaman[gprmc_sayac]=veri; burada da 1. virgülden sonraki 6 karakteri zaman[] dizisine aktar anlamına geliyor istediğin şekle göre düzenlemelerini yapabilirsin.

if(v_sayac>9) burada ise 9. virgülden sonra veri yakalama işleminin bittiği kontrol ediliyor. bunun yerine özel bir karakterde sonlanmasını istiyorsan atıyorum * gibi if(veri==*"*") kontrolüyle de sonlandırabilirsin. dilersen başka bir yerde gprmc_yakalama_bitti bitini kontrol ederek istediğin verilerin alınıp alınmadığını da takip edebilirsin.

değişkenleri unsigned char şeklinde, gprmc_yakalama_bitti ise bit şeklinde hazırlık ta tanımlayabilirsin.

AsHeS

Bende bu aralar bu işle uğraşıyorum benim izlediğim yol ise şöyle GPS modülü başlangıcı $ karakteriyle sonlandırmay '\n' '\r' karakterleriyle yapıyor.Veriyi byte byte okuyorum RCREG üzerinden $ ile başlayıp \n ile biten karakter dizisine yazdırıyorum bu işlemin ardından main bloğu için bir bayrak tanımlayıp uart kesmesini kapatarak gelen veriyi tespit ediyorum.string kütüphanesini dahil etmemek için string karşılaştırmanın(strncmp yerine) bir çakmasını kullanıyorum o da şöyle
unsigned char strcomp(unsigned char *str2, unsigned char *str1, unsigned char
    numofchr)
{
    unsigned char i;
    for (i = 0; i < numofchr; i++)
    {
        if (str1[i] == '\0' || str2[i] == '\0')
            break;
        else if (str1[i] != str2[i])
            break;
    }
    if (i == numofchr)
        return 1;
    else
        return 0;
}

yukarıda ki fonksiyon yardımıyla gelen karakter katarını karşılaştırıyorum.
    while (1)
    {
        if (datarcptd ==1)//Veri alındı mı ?
        {
            if(strcomp("$GPGGA",gps_data,6))
                sendcrdnat();//Koordinatı gönder
            GIE=1;//Kesmeyi aç
            datarcptd=0;//veri alındı bayrağını sıfırla
        }

    }

Main döngümde yukarıda ki gibi umarım yardımcı olur size.

burak_489

ccs c de kesme alt programinda ilgili kesmeyi disable etmwnin geregi varmidir yani kesme alt programda iken yine kesme olursa tekrar basa mi doner yoksa ccs c kesme alt programa girdiginde kendisi kesmeyi kapatip bitise geldiginde tekrar mi aciyor.

hasankara

genel kesme açık olduğu sürece bayrak temiz değilse kesmeden çıkamazsın. kesme fonksiyonu içinde çok vakit harcatmaman gerekir. en azından bir sonraki kesme gelmeden evvel fonksiyondan çıkabilecek kadar hızlı işlem yapması gerekir. bu hususa önem gösterirsen kesmeyi iptal etmene gerek kalmaz. fonksiyon içerisi şiştiğinde, kesmeyi iptal etmek bile çözüm olmaz çünkü gelen veriler üst üste binince seri porttan daha veri okumamaya başlıyor reset atman gerekebiliyor. veya seri portu açıp kapatarak da belki yeniden veri almaya başlayabilirsin ancak böyle olsa bile bir sürü veri kaçmış olabilir.

sadogan

Alıntı yapılan: burak_489 - 13 Temmuz 2013, 09:39:05
ccs c de kesme alt programinda ilgili kesmeyi disable etmwnin geregi varmidir yani kesme alt programda iken yine kesme olursa tekrar basa mi doner yoksa ccs c kesme alt programa girdiginde kendisi kesmeyi kapatip bitise geldiginde tekrar mi aciyor.
Kesme alt programında ilgili kesmeyi disable etmek olmasa olmaz deyildir ama intterupt ile ilgili flag ları
temizilediği için olası sorunlardan kurunursunuz.
Ancak ilgili interrupt u ISR den çıkarken tekrar enable etmelisiniz main rutinde deyil.
Interrupt rutinde işlemlerinizi yaparken farklı bir  interrupt gelir ise stack a pc nin adresi yazılarak
ilgili interrupt servise alınır işlem sonu isr den çıkaren pc ye önceki isr nin adresi yüklenerek kaldığı yerden devam eder.
Aynı interrupt gelir ise aynı alt programı kullanacağı için işler karışır. Ama seri port da bu ihtimal in
olması mümkün görünmüyor. Taki isr içerisine uzun kodlar yazmadığınız, delay gibi zaman geçiren
fonksiyonlar olmadığı sürece.

burak_489

peki usb kullansak seri port yerine hiz ve guvenli iletim her ikisi de artar mi