Jump to content
Devre Forum
  • Kaydol
şenol eker

İki mikrodenetleyici arasında haberleşme

Önerilen İletiler

İki mikrodenetleyici arasında haberleşme konusunda çok fazla "sıkıntı" çekildiğini görüyorum. Bu yüzden bu makaleyi yazmaya karar verdim.

Haberleşme isterse iki kıta arasında olsun isterse aynı pcb üzerindeki iki çip (PIC/AVR/STM) arasında olsun, haberleşmedir. ADSL modemden Wi-Fi'ye hatta modern telefon görüşmelerine kadar, tüm haberleşme "paketler" halinde yapılır. Çünkü en kolay ve düzgün olanı bu.

"Paket" dediğimiz adı üstünde, bir bütün. Peki neden bilgileri buradan ard arda gönderip karşıdan da ard arda almıyoruz?
Örneğin:
Birinci_mesaj
İkinci_Mesaj
3_Mesaj
Bunları ard arda gönderirsek, her bir mesajın nerede başlayıp nerede bittiğini bilemeyiz. Bu yüzden her bir mesajın başına / sonuna bir "işaret" koymalıyız. Örneğin işaret olarak * koymayı düşünelim.
Peki, mesajın içinde * varsa ne olacak?
Biz verileri doğrudan gönderiyorsak, her bir byte 0 ile 255 arasında değer alabilir. Dolayısı ile "başka amaçla kullanılmayan" diye bir şey yok. (ESC ile bu mümkün ama kafamızı karıştırmayalım; yolu yok diyelim) O halde nasıl ayıracağız bu mesajları?
Cevap, "paketleyerek". (packet)
Cevap, "zarfa koyarak", (envelope)
Cevap, "çerçeveye koyarak" (frame)
Öncelikle bir "protokol" kurmalıyız kafamızda. Protokol dediğimiz, neyi nasıl yapacağımızın tarifi.
Örnek olarak bir protokol uyduralım:
En başta bir "preamble" olsun. Paketin buradan başladığını biliriz. Preamble 0x55 0xAA olsun örneğin. (Bu sayının seçilme sebebi, binary olarak 01010101 10101010 şeklinde olması, bir ve sıfırlar ardışık)
Ardından yükümüzün (payload) kaç byte olduğunu verelim. Sabit bir şey göndereceksek buna gerek olmayabilir.
Sonra asıl göndereceğimiz veri. Yani "payload", yük.
En sonda da istersek bir kontrol toplamı (CRC) gönderebiliriz. Bir terslik olursa hatalı veri alınmasın diye.
Evet, "çerçeve"mizin yapısı bu olacak. Şimdi bunu yazalım da güzel görünsün:
 

Byte  İçerik        açıklama
00    0x55          Preamble ilk byte
01    0xAA          Preamble 2. byte
02    len           yük uzunluğu
03    payload(1)    yük
..    payload(..)   yük
len+2 payload(len)  yük son byte
len+3 CRC           yük CRC toplamı

Tabii bu bir kural değil. CRC koymayabiliriz örneğin, eğer aradaki iletişim çok sağlıklı ise ve hatalı bilgi gitmesi sistemimizde büyük sıkıntıya yol açmayacaksa. Çünkü pakete ilave edeceğimiz her byte, iletişim hızımızı düşürecek.

Örneğin uzunluğumuz sabit olabilir. O zman onu da kullanmayabiliriz. Örneğin 16 bitlik bir integer sayı gönderiyor olabiliriz. Bu durumda uzunluk sabittir. Verinin çok hızlı olmasını istiyorsak, örneğin preamble de 1 byte olabilir. Bu durumda paketimiz şöyle olacak:

Byte İçerik Açıklama
00   0x55   Preamble
01   yük-1  Yükün büyük byte'ı
02   yük-2  Yükün küçük byte'ı

Sonraki gönderide verinin nasıl gönderilebileceğine bakacağız.

(Devam Edecek)

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş

Verileri karşı tarafa gönderirken, basit bir veri yapımız varsa, doğrudan seri porttan gönderebiliriz. Örneğin bir tane integer sayı ve tekn byte premable göndereceksek:

SendChar (0x55);
SendChar (veri & 0xFF);
SendChar ((veri>>8) & 0xFF);

şeklinde gönderebiliriz. (Verimizin adı "veri" ve preamble 0x55)

Ama görece karmaşık bir verimiz varsa, bir veri yapısı içinde gönderebiliriz. Bir örnek olarak isim, soyisim ve boy bilgilerini göndermek isteyelim. Şüphesiz ki bunu da yukarıdaki gibi yapabiliriz. Yani tek tek gönderebiliriz. Ama çok genel olsun diye "tam tekmil" bir yapı verelim, İstemediğiniz yerleri çıkartabilirsiniz.

Önce bir union type tanımlayacağız. Hem gönderirken kolaylık olsun diye her byte'ı ayrı ayrı; hem de kullanımda kolaylık olsun diye uygun değişkenler şeklinde.

typedef union
{
  struct
  {
    char bytes[36];
  };
  struct
  {
    char preamble[2]
    char isim[16];
    char soyad[16];
    char boy;
    char checksum;
  };
}veri_type;
veri_type veri;

Sonra değerlerimizi koyacağız:

veri.preamble=0x55aa;
veri.isim=....
veri.soyad=....
veri.boy=180;

Daha sonra eğer kullanacaksak checksum hesaplayacağız:
 

veri.checksum=0;
for (i=2;i<35;i++) //preamble ve checksum hariç
{
  veri.checksum+=veri.bytes[i];
}



artık verimizi yollayabiliriz.

for (i=0;i<36;i++)
{
  SendChar(veri.bytes[i]);
}


Hepsi bu :)
 

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş

Peki gönderilen bu veriyi nasıl alabiliriz?

 Bunun en kolay yolu kesme kullanmak aslında. Ama kesme kullanmadan da yapabiliriz. İlk örneğimize göre yapacaksak:

while (GetChar<>0x55); //0x55 gelmesini bekliyoruz
veri=GetChar;
veri=veri + GetChar<<8;

İkinci örneğe göre yapacaksak:

typedef union
{
  struct
  {
    char bytes[34];
  };
  struct
  {
    char isim[16];
    char soyad[16];
    char boy;
    char checksum;
  };
}veri_type;
veri_type veri;
....
Bekle:
if (GetChar!=0x55) goto Bekle
if (GetChar!=0xAA) goto bekle
veri.checksum=0;
for (i=0;i<33;i++)
{
  veri.bytes[i]=GetChar;
  veri.checksum=veri.bytes[i];
}
veri.checksum-=GetChar;
if (veri.checksum!=0) goto Bekle;

Umarım anlaşılmıştır.
Eğer kesme içinde yapacaksak, bu sefer de sonlu durum makinesi kurmamız gerekir.

char state=0;
char tmp;
....
void Serial_ISR(void)
{
  tmp=GetChar;
  switch (state)
  {
    case 0:if (tmp==0x55)state=1;
      break;
    case 1:if (tmp==0xAA){state=2;}else{state=0;}
  break;
  case 33:
  default:
  if (state>33)
  {
    state=0;
  }else{
    veri.checksum=tmp;
    for (tmp=0;tmp<33;tmp++)
    {
      veri.checksum-=veri.bytes[tmp];
    }
    if (checksum==0)VeriGeldi=1;
    state=0;
  }
  }
  ResetIF;
}

Peki programımızda, bir "veri geldiğini" nereden biliriz?
"VeriGeldi" adlı bayraktan anlayacağız bunu da.
Sonlu durum makinesinin nasıl çalıştığını, ne olduğunu bilmiyorsanız, önce bunu öğrenmenizi öneririm.
Ayrıca yukarıdaki kodlar bir C lehçesi için yazılmadı, olayı anlatmak için yazıldı ve test edilmedi. Dolayısı ile copy+paste yapmanız için değildir, öğrenmeniz içindir. Zaten ben prensip icabı balık vermeye karşıyım.

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
Misafir
Bu konuyu yanıtla

×   Yapıştırdığınız içerik biçimlendirme içeriyor.   Biçimlendirmeyi Temizle

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Önceki içeriğiniz geri yüklendi.   Editör içeriğini temizle

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Yeni Oluştur...

Önemli Bilgilendirme

Facebook / Twitter / Google hesabınızla kolayca kaydolup cevap verebilir, soru sorabilir, istekte bulunabilirsiniz.
Devam etmeniz, forum kurallarını kabul ettiğiniz anlamına gelir.            Forum Kuralları