Kablosuz seri iletişimde hatanın azaltılması

Kablosuz veri iletiminde eğer elimizdeki donanım yapmıyorsa gelen veriyi ayıklamak yazılıma kalıyor, tabiri caizse biraz takla atmamız gerekebiliyor. Yaygın olarak kullanılan ask rf alıcı-verici modüller de takla gerektiren donanımlardan. Çokça konuştuğumuz gibi bu modüllerle haberleşirken verimizi göndermeden önce uyandırma işareti, öncü veri bilgilerini gönderiyorduk. Uyandırma işaretini uyuyan modülü uyandırmak diğer tabirle “turn-on time” ı geçirmek, öncü veriyi de gönderici kimliğini belirtmek için gönderiyorduk. Çünkü bu modüller kendi frekansında gelen her ask işareti yorumluyor.
Bazı uygulamalarda oluyor ki gönderdiğimiz verinin doğru anlaşılması çok önemli oluyor, veriyi yanlış anlayacağına hiç anlamasın daha iyi diyebiliyoruz. Bunu nasıl sağlarız diye düşünürken aklımdakileri denedim, sonuçlar fena değil.

Rf modüllerle veriyi sürekli gönderdiğimizi düşünelim, alıcı tarafta bu verilerin bir kısmı doğru alınırken bir kısmı yanlış alınıyor. Ama şöyle bir 5-10 elemanlık diziye baktığınızda gönderilen elemanı kestirebiliyorsunuz. Ben de dedim ki bu gelen 5-10 elemanı bir diziye dizeyim, sonra da dizi içinde en fazla geçen elemanı bulayım. Öncü veriyi yine kullanıyoruz ve arkasından “derinlik” adedince aynı veriyi gönderiyoruz, alıcı tarafta öncü veri geldikten sonra gelen “derinlik” adedince elemanı bir diziye yerleştiriyoruz, sonra da dizide en çok olan ve sayısı en az “enaz” değişkeni kadar olan veriyi bizim gönderdiğimiz veridir diye alıyoruz. Eğer öncü veri gelir de -ki siz göndermeseniz de gürültüden gelebiliyor- arkasındaki dizide “enaz” değişkeni kadar geçen eleman olmazsa fonksiyon 0 döndürüyor.

Kodda da görebileceğiniz gibi algoritmanın “derinlik” ve “enaz” adında iki temel parametresi var. Bu parametreler şunu diyor: Gelen “derinlik” tane elemanı bir diziye diz, sayısı “enaz” veya daha fazla olan elemanı seç.

Örn: ‘A’ verisini derinlik=10, enaz=3 ve öncü=’x’ olduğu durumda nasıl gönderildiğine bakalım:
rfgonder(‘A’);
TX: ªªxxAAAAAAAAAA
‘ª’ lar uyandırma işareti için-hiç kullanmayacağınız bir işaret seçebilirsiniz-, ‘x’ i ben öncü veri olarak seçtim. “derinlik” adedince ‘A’ arka arkaya gönderiliyor.

Alıcı tarafta ise en son görülen öncü veriden sonra alınan “derinlik” adedince veri diziye yerleştiriliyor. Örn alınan data şöyle olsun:
xc£#AA~A¥σAAЦ……
Bu gelen datanın en son görülen öncüden(bu örnekte zaten bir tane var) sonraki ilk 10 elemanı diziye yerleştirildi, şu anda dizide:
c£#AA~A¥σA elemanları var.
En çok geçen elemana bakıldı A, geçme sayısı 4, 3 ten büyük. Demek ki gönderilen verimiz ‘A’ dır.

Tabi bu şekilde veriyi daha güvenli iletirken hızımızı da düşürmüş oluyoruz.

Bu fonksiyon genel ve basit bir fonksyion, C ile yazıldı ve seri haberleşen herhangi iki modül arasında kullanılabilir. Ben CCS C de PIC ler arasında rf modül haberleşmesi üzerinden kullandım.

Alıcı ve verici tarafta bulunması gereken ortak parametreler:

#define oncu 'x'
#define derinlik 10

“derinlik” değişkenini iletişim hassasiyetinize göre belirleyebilirsiniz ve algoritmanın doğru çalışması için öncü veriyi haberleşmede kullanmayacağımız bir karakter seçmeliyiz.
Verici tarafta olması gerekenler:
prototip bildirimi:

void rf_gonder(int data);

fonksyionun kendisi:

void rf_gonder(int data){
int i=0;
putc(0b10101010);//alfanumerik olmayan bir karakter
putc(0b10101010);
putc(oncu);
putc(oncu);
   for(i=1;i<=derinlik;i++){
     putc(data);

   }
}

Kullanımı:

rf_gonder(veri);

Alıcı taraf:
Ben verileri serialdata kesmesiyle aldım, şart değil, uart olmayan mikrolar için sonsuz döngü içerisinde de veri alarak bu fonksiyonu kullanabilirsiniz(o şekilde de denedim).

enaz değişkenini hassasiyetinize göre istediğiniz bir değer yapabilirsiniz, fonksiyon prototipi ve gerekli bazı değişkenler:

#define enaz 3
int diziden_sec();
int gelen,i,durum=0; //durum=0 oncu verinin beklendiği durum
int dizi[derinlik];

Gelen verileri kesme ile aldığımı söylemiştim:

#INT_RDA
void data_geldi(){
gelen=getc();
if(gelen==oncu){
   durum=1;
   i=0;
}
else if(durum==1){
   dizi[i]=gelen;
   i++;
   if(i==derinlik-1){//veriler diziye yerleşti, degerlendirelim:
      durum=0;
      if(diziden_sec()){
        putc(diziden_sec());
      }
   }
}

}

Ve fonksiyonumuz:

int diziden_sec(){ //dizide en az "enaz" kadar geçen elemanı döndürür aksi durumlarda 0 döndürür.
int max=0,a=0,b=0,temp=0,indis=0;
for(a=0;a<derinlik;a++){
   for(b=0;b<derinlik;b++){
      if(dizi[b]==dizi[a]){
      temp++;
      }
   }
   if(temp>max && temp>=enaz){
      max=temp;
      indis=a;
   }
   temp=0;

}
if(max<=1){//hata oluştu, öncü alındı ama arkasından gelen dizi anlamsız
   return 0;
}
else{
   return dizi[indis];
}
}

Ben bu algoritmayı hem basit bir devrede hem de simülasyonda denedim. Derinlik=10, enaz=3 olduğunda alıcı tarafta beklemediğim hiçbir veriyle karşılaşmadım.
Simülasyon dosyası ve alıcı.c-verici.c dosyalarını burdan indirebilirsiniz.

12 thoughts on “Kablosuz seri iletişimde hatanın azaltılması”

  1. merhaba fatih hocam benim bir sorunum var.Bu yazdığın kodlar benim işime çok yaradı gerçekten.
    Fakat küçük bir yerde sorun yaşıyorum.
    Kodları Verici kısımda 16f877A ya ve alıcı kısımda 18f452’ye modfiye ettim.
    Amacım;
    Alıcı kısımdaki kullandığın kesmeyi
    #INT_RDA
    void data_geldi(){
    gelen=getc();
    if(gelen==oncu){
    durum=1;
    i=0;
    }
    else if(durum==1){
    dizi[i]=gelen;
    i++;
    if(i==derinlik-1){//veriler diziye yerleşti, degerlendirelim:
    durum=0;
    if(diziden_sec()){
    deger = diziden_sec();
    putc(deger);
    }
    }
    }

    }
    Bende Kullanarak iletilen değişkeni deger tipinde bir değişkene atadım.
    Şimdi Putc(deger); diyince tamam virtual terminalden görüyorum ama benim istediğim bu değeri grafik Lcd’de göstermek

    Mesela bu değişkeni
    char yazi[];
    int deger;
    void main()
    { ..
    ..
    ..
    }

    while(1)
    {
    sprintf(yazi,”%d”,deger);
    glcd_text57(10, 12, 1, yaz,oni);
    delay_ms(1000);
    glcd_text57(10, 12, 1, yazi,off);
    }

    şeklinde sonsuz döngüye koyup GLCD’de görmek istiyorum fakat olmuyor.yardımcı olursanız sevinirim.
    Ayrıca kesme olmadan seriveriyi alamıyorum,
    int data_geldi();
    şeklinde return data;
    edebileceğim bir fonk çeviriyorum ama deger dönmüyor.
    sebebi ne anlamadım.Yardımcı olursan çok sevinirim.
    isterseniz devre kod simulasyon yollayabilirim.

  2. Gelen datayı almanının en iyi yolu kesme ile almak, kesme ile almazsanız CCS C deki getc() fonksiyonunu sonsuz döngü içerisinde kullanmanız gerekir ki güzel bir yöntem değil. CCS C de grafik lcd sürmeyi hiç denemedim, bilmiyorum. Aldığınız hata nedir? Kodda
    sprintf(yazi,”%d”,deger);
    glcd_text57(10, 12, 1, yaz,oni); satırlarında harf hatalarınız var. “yazi” yerine “yaz”; “on” yerine “oni” yazmışsınız. Öncelikle bu satırları düzeltebilirsiniz. Kolay gelsin.

  3. sprintf(yazi,”%d”,deger);
    glcd_text57(10, 12, 1, yaz,oni); size yazarken hatalı yazdım bu satırları,kusurabakmayin.Amacım gelen analog bilgiyi bir picte digitale cevirip diger picte glcd’de göstermek.
    işin %80nini yaptım yani AN0’dan bilgiyi pic16f877A ile analogtan digitale cevirdim daha sonra 18f452 ile okuyup güzelce aldım.

    işte bu değeri Glcd’de gösteremiyorum.

    Atiyorum analog deger 0.3435V=0b01000001=0x41= ‘A’ karakterine karşılık geliyor diyelim

    Bunu rahatça gönderiyorum ve 18f452’nin TX’inde putc(deger) diyerekte virtual terminalde görüyorum.

    Fakat bir türlü Glcd’ye modifiye edemiyorum bu değeri hiç olmazsa 0x41=65 onluk sistemde gösteremiyorum

  4. Gökhan hocam lt anlamsız, yanlışlıkla gösterilmiş. Koddaki < operatörünün sayfada hatalı gösterimi oluyor. Sayfada kullandığım kod renklendiricinin bir hatası olmalı... Orjinal kodu yazı sonundaki linkten görebilirsiniz. İyi çalışmalar.

  5. selam hocam

    hocam uzun zamandır 2 pic arası rf uygulaması yapmaya çalışıyorum. sizin örneğiniz gibi 10 larca örneği proteusta çalıştırdım gayet güzel. lakin gerçek uygulamada çalışmıyor. devreyi board üzerine kuruyorum. basit bir devre bile çalışmıyor yani veri gidince led yansın falan. dediğim gibi proteusta yazılımların hepsi çalıştı. board hiç başaramadım. ve acil olarak rf iletişimi yapmam lazım. bu konuda yardımcı olurmusunuz. nerde hata yapıyorum?

  6. Fatih hocam ben rf ile veri gönderip alıp lcd’ye yazdırmaya çalışıyorum ama kablolu olarak iki devreyi birbirine bağladığımda çalışmasına rağmen rf ile çalışmamaktadır bana bununla ilgigli ccs code gönderebilri misiniz şimdiden teşekkürler..

    1. Sitedeki RF modüller ile alakalı yazılarda sorunuzun cevabı var. Bu soru çok sorulan bir soru, picproje.org forumlarında da çok defa cevaplanmış bir soru.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir