RS485 haberleşmesinde kilitlenme

Başlatan onertan, 16 Mart 2021, 13:35:59

onertan

Merhaba arkadaşlar.
Masterdan slave devreye RS485 üzerinden komut gönderiyorum. Örnek devremde 'c' karakterini slave devreye gönderdim. Her basmamda sorunsuz karşı tarafa gidiyor ancak interrupt pasif konumdayken 3 ve 3 ün üstü defa Master devresinden Slave devresine komut gönderince Interrupt aktif hale geldikten sonra isteğimi yerine getirip haberleşmeyi kilitliyor. PIC döngüsünü gerçekleştiriyor bunu görebiliyorum ama bir daha RS485 ten veri almıyor.
Sanırım seri bilgi alma portuna fazla yük biniyor ve kilitliyor. Yapmam gereken şey bu portun kapasiteden fazla bilgi almamasını sağlamak diye düşünüyorum. Ayrıca İNT_rda kesmesi pasif olduğunda veri almaması gerekmiyor mu?. Ben kesmeyi pasif yaptığımda bile veri alıyor ve hafızada tutuyor. Kesmeyi aktif yapınca hafızadaki direktifleri yerine getiriyor.  Bunu nasıl engellerim. Slave devre kodu aşağıda.

#include <16f877A.h> 
#use delay(clock=20M)
#fuses HS, NOWDT, NOPUT, NOLVP, NOCPD, NOPROTECT, NODEBUG, NOBROWNOUT, NOWRT
#include <string.h>
#include <stdlib.h>

#use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, enable=pin_C5, parity=N, stop=1) 

#define VERI_IZNI pin_c5
#define VERI_ALMA_LEDI pin_c1
   

char i;
int t, d;
char gelen = 0;


#int_rda
void rs485_kesmesi()
{      

   i = getc();
   if(i == 'c')
   {
      output_high(VERI_ALMA_LEDI);  //RS485 ten veri alınca ledi yak
      delay_ms(200);
      output_low(VERI_ALMA_LEDI);   //RS485 ten veri alınca ledi söndür
      delay_ms(100);
      i = '\0';                    //i ' yi sıfırla
   }  
}



void main()
{       

   output_low(VERI_IZNI);
   enable_interrupts(GLOBAL);  

   
   
   while(1) 
   {
       
      delay_ms(100);                          //|
      output_high(pin_c0);                    //|
      for(t=0; t<50; t++)                     //|
      {                                       //| 
         delay_ms(100);                       //|      Kodun bu bölümünde
      }                                       //|   RS485'ten bilgi almasın
      output_low(pin_c0);                     //|
      delay_ms(10);                           //|
      output_high(pin_c2);                    //|
      delay_ms(10);                           //|
      enable_interrupts(GLOBAL);      //|
      enable_interrupts(int_rda);     //|
                                      //|
      for(d=0; d<50; d++)             //|
      {                               //|     Sadce Kodun bu parçasında    
         delay_ms(100);               //|   RS485 ten bilgi alsın istiyorum
      }                               //|
      output_low(pin_c2);             //|
      delay_ms(50);                   //|
      disable_interrupts(GLOBAL);     
      disable_interrupts(int_rda);    
   }         
}

tunayk

Overrun error flag aktif oluyor, ve daha fazla alım yapmıyor.
İşlemcinin 2 byte bufferi var ve bunlar okunmadan 3. Byte gelirse bu hata aktif olur ve bişey almaz.
Çözüm basittir. Siz programda işinizi bitirip veri almaya hazır hale gelince, öncelikle bufferı birkaç kez okuyup eski alınanları temizleyin. Hata flaglarını sıfırlayın ve kesmeyi aktif edin.
Kesmenin kapalı olması alımı engellemez. Engel istiyorsanız portu komple kapatmak gerek ama buna ihtiyaç yoktur. Hataları temizler yola devam edersin.

ferdem

Basit adımlara bölerek problemi tespit edebilirsiniz. En yalın halde başlayın:
#include <16f877A.h> 
#use delay(clock=20M)
#fuses HS, NOWDT, NOPUT, NOLVP, NOCPD, NOPROTECT, NODEBUG, NOBROWNOUT, NOWRT
#include <string.h>
#include <stdlib.h>

#use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, enable=pin_C5, parity=N, stop=1) 

#define VERI_IZNI pin_c5
#define VERI_ALMA_LEDI pin_c1
  

char i;
int t, d;
char gelen = 0;


#int_rda
void rs485_kesmesi()
{      

  i = getc();
output_toggle(VERI_ALMA_LEDI); 
}



void main()
{      

      enable_interrupts(GLOBAL);      //|
      enable_interrupts(int_rda);

  
  while(1) 
  {
      
      delay_ms(100);                          //|
      output_high(pin_c0);                    //|
      delay_ms(100);                      //|                                                  //| 
      output_low(pin_c0);                    //|
    
  }        
}
sonra kesmeyi güncelleyin:
#int_rda
void rs485_kesmesi()
{      

   i = getc();
   if(i == 'c')
   {
      output_toggle(VERI_ALMA_LEDI);  //RS485 ten veri alınca ledi yak

   }  
}
Bu adımlarda herhangi bir problem oluyor mu?

onertan

Merhaba,
Yardımlarınız için teşekkür ederim. Dün gece araştırmam esnasında bir uygulamada RS232 fonksiyonuna 'errors' terimini eklediklerini gördüm. Alınan hataları resetleyip devam ediyormuş. Seri haberleşme bildirim satırını şu hale getirdim. 

" #use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, enable=pin_C5, parity=N, stop=1, errors) " 

Bu şekilde denediğimde artık veri iletişiminde donma olmadığını gördüm. tunayk ' nın dediği gibi aktif olan Overrun error flag ' ı pasif ediyoruz sanırım. Veya hataları hiç görmemesini sağlıyoruz. İkisinden biri olmalı. Sorun çözüldü ama tunayk'nın önerisinin de mantığını öğrenmek isterim. BUffer'ı birkaç kez okuyup hata flaglarını temizleme işlemini nasıl yapabilirim. bana basit bir kod satırıyla gösterir misin.

tunayk

Doğru yolu bulmuşsun zaten.   :)

CCS C Help der ki;

ERRORS
 Used to cause the compiler to keep receive errors in the variable RS232_ERRORS and to reset errors when they occur, and RS232_BUFFER_ERRORS when transmit or RECEIVE_BUFFER are used.

Bu parametreyi vermişsen, hata oluştuğunda sıfırlanır ve hata bilgisi RS232_ERRORS değişkenine kopyalanır.

Birkaç kez buffer okumaktan kastedilen, birkaç kez i=getc(); yi çağırmandır.

if(rcv_buffer_full()) c = getc(); gibi.

Biraz helpe bakmak iyidir, fikir verir. İngilizcesi zayıf olan için Google amca bedava hizmet veriyor :)