16f877 usart girişi neden kilitlenir

Başlatan zcemix, 16 Kasım 2008, 13:14:05

zcemix

Arkadaşlar benim sorunum şu 16f877 'nin rx olarak kullandığım pin_c7 portuna aşırı bilgi geldiğinde usart devre dışı kalıyor yada kesme devre dışı kalıyor sanırım elektriksel olarak kilitleniyor yani reset_cpu() komutu bile bunu çözemiyor.Pic'in enerjisini kesip (hatta besleme kondansatörünü boşaltıp) yeniden verdiğimde pic tekrar çalışabiliyor.Pic kitlenmiyor bunu anlamak için ana döngümün içinde output_toggle(pin_b7) komutuyla ledi yakıp söndürüyorum ne yaptıysam olmadı lütfen acil yardım.
Kod:
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=20000000)
#use fast_io(b)
#use fast_io(d)
#use fast_io(a)
#use fast_io(e)
#use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, parity=N, stop=1)
char   gelendata;
int16 tussuresi=100;
#int_rda
void serihaberlesme_kesmesi ()
{
 disable_interrupts(int_rda); // int_rda kesmesini pasif yap
 gelendata = getc(); 
  if(gelendata=='2'){output_high(pin_c1);delay_ms(tussuresi);output_low(pin_c1);}
  if(gelendata=='3'){output_high(pin_c2);delay_ms(tussuresi);output_low(pin_c2);}
  if(gelendata=='q'){output_high(pin_d1);delay_ms(tussuresi);output_low(pin_d1);}
  if(gelendata=='6'){output_high(pin_d4);delay_ms(tussuresi);output_low(pin_d4);}
  if(gelendata=='f'){output_high(pin_d5);delay_ms(tussuresi);output_low(pin_d5);}
  if(gelendata=='7'){output_high(pin_d6);delay_ms(tussuresi);output_low(pin_d6);}
  if(gelendata=='8'){output_high(pin_d7);delay_ms(tussuresi);output_low(pin_d7);}
  if(gelendata=='n'){output_high(pin_d2);delay_ms(tussuresi);output_low(pin_d2);}
  if(gelendata=='u'){output_high(pin_d3);delay_ms(tussuresi);output_low(pin_d3);}
  if(gelendata=='d'){output_high(pin_c4);delay_ms(tussuresi);output_low(pin_c4);}
  if(gelendata=='y'){output_high(pin_c5);delay_ms(tussuresi);output_low(pin_c5);}
  if(gelendata=='4'){output_high(pin_d0);delay_ms(tussuresi);output_low(pin_d0);}
  if(gelendata=='5'){output_high(pin_c3);delay_ms(tussuresi);output_low(pin_c3);}
  if(gelendata=='9'){output_high(pin_e0);delay_ms(tussuresi);output_low(pin_e0);}
  if(gelendata=='0'){output_high(pin_a0);delay_ms(tussuresi);output_low(pin_a0);}
  if(gelendata=='e'){output_high(pin_a1);delay_ms(tussuresi);output_low(pin_a1);}
  if(gelendata=='s'){output_high(pin_a2);delay_ms(tussuresi);output_low(pin_a2);}
  if(gelendata=='r'){output_high(pin_a3);delay_ms(tussuresi);output_low(pin_a3);}
  if(gelendata=='t'){output_high(pin_a5);delay_ms(tussuresi);output_low(pin_a5);}
}

void main ( )
{
   setup_psp(PSP_DISABLED);        // PSP birimi devre dışı
   setup_spi(SPI_SS_DISABLED);     // SPI 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ışı
set_tris_b(0x00);
set_tris_d(0x00);
set_tris_a(0x00);
set_tris_e(0x00);
output_d(0x00);
output_a(0x00);
output_e(0x00);
output_b(0x00);
   enable_interrupts(int_rda);
   enable_interrupts(GLOBAL);  // Aktif edilen tüm kesmelere izin ver
   while(true) // Sonsuz döngü
   {
   output_toggle(pin_b7);
   delay_ms(200);
   enable_interrupts(int_rda); // int_rda kesmesi aktif
   }
}

zcemix

Arkadaşlar şöyle birşey denedim seri port kesmesine putc(gelendata); (gelen datayı geri gönder dedim) komutunu ekledim ve similasyonda usart'ın kendi kendine sürekli kesmeye gittiğini gördüm sürekli olarak son gelendatayı geri gönderiyor yani kendi kendine kesmeyi tekrarlıyor yada hiç çıkamıyor ne biçim birşey anlamadım reset_cpu() yememesi garip  gerçek uygulamada kesmeyi tekrarlamıyor direk kilitleniyor galiba illede enerjiyi keseceksin başka türlü düzelmiyor usart ile ilgili problem yaşayan bir arkadaşım konuyla ilgisi olmasada paylaşırsa sevinirim iyi günler diliyorum..

Ziya

döngü içerisinde enable interrupt yazmana gerek yok.

döngü içerisinde 200 ms gecikme çok. Peşpeşe gelen bilgiler rxbuffer ını doldurur ve overrun error oluşur. Çaresi overrun error flagi etkinleşmiş ise peş peşe 3 defa rxbufferını boş yere okutmak ve bufferi boşaltmaktır.

interrupt içerisinde alt program veya fonksiyon (delay gibi) çağırırsanız serbest stack alanını daraltmış olursunuz.
Bu günden sonra hiç kimse sarayda, divanda, meclislerde ve seyranda Türk dilinden başka dil kullanmaya. (13 Mayıs 1277) Karamanoğlu Mehmet Bey

debi

Alıntı yapılan: "Ziya"döngü içerisinde enable interrupt yazmana gerek yok.

döngü içerisinde 200 ms gecikme çok. Peşpeşe gelen bilgiler rxbuffer ını doldurur ve overrun error oluşur. Çaresi overrun error flagi etkinleşmiş ise peş peşe 3 defa rxbufferını boş yere okutmak ve bufferi boşaltmaktır.

interrupt içerisinde alt program veya fonksiyon (delay gibi) çağırırsanız serbest stack alanını daraltmış olursunuz.


Bu işlemin nasıl yapılacağını anlatabilir misiniz?

Ziya

#bit overrun_flag = GETENV("BIT:OERR")
#byte rcreg       = GETENV("SFR:RCREG")
...

if(overrun_flag) {
  gelendata = rcreg;
  gelendata = rcreg;
  gelendata = rcreg;
}
Bu günden sonra hiç kimse sarayda, divanda, meclislerde ve seyranda Türk dilinden başka dil kullanmaya. (13 Mayıs 1277) Karamanoğlu Mehmet Bey

debi

Alıntı yapılan: "Ziya"
#bit overrun_flag = GETENV("BIT:OERR")
#byte rcreg       = GETENV("SFR:RCREG")
...

if(overrun_flag) {
  gelendata = rcreg;
  gelendata = rcreg;
  gelendata = rcreg;
}

Teşekkür ederim ziya hocam.. Peki OERR bitini kontrol edip, şayet ki 1 ise CREN bitini önce '0'a sonra '1'e çekmek bu işi çözer mi? Şayet ki çözerse benim bu koşulu ana döngüye yazmam uygun olur değil mi?


edit :: başlığı açan arkadaş gibi ben de overflow sıkıntısı çekiyorum, umarım sonuca ulaşabiliriz..

zcemix

İlginiz ve cevabınız için çok teşekkür ederim.

Dediğiniz gibi yaptım kesmeyi aktif etme işini ana döngüden aldım buraya koydum


#int_rda
void serihaberlesme_kesmesi ()
{
 disable_interrupts(int_rda); // int_rda kesmesini pasif yap
 gelendata = getc(); // seri porttan 1 karakter oku
 putc(gelendata);
 datageldi=1;
 enable_interrupts(int_rda); // kesmeyi aktif etme işini ana döngüden aldım buraya koydum
}

ve Butonlara basma işinide ana döngüye havale ettim:
while(true) // Sonsuz döngü
   {
   if(datageldi==1)
   {
  if(gelendata=='1'){output_high(pin_c0);delay_ms(tussuresi);output_low(pin_c0);}
  if(gelendata=='2'){output_high(pin_c1);delay_ms(tussuresi);output_low(pin_c1);}
  if(gelendata=='3'){output_high(pin_c2);delay_ms(tussuresi);output_low(pin_c2);}
  if(gelendata=='q'){output_high(pin_d1);delay_ms(tussuresi);output_low(pin_d1);}
  if(gelendata=='6'){output_high(pin_d4);delay_ms(tussuresi);output_low(pin_d4);}
  if(gelendata=='f'){output_high(pin_d5);delay_ms(tussuresi);output_low(pin_d5);}
  if(gelendata=='7'){output_high(pin_d6);delay_ms(tussuresi);output_low(pin_d6);}
  if(gelendata=='8'){output_high(pin_d7);delay_ms(tussuresi);output_low(pin_d7);}
  if(gelendata=='n'){output_high(pin_d2);delay_ms(tussuresi);output_low(pin_d2);}
  if(gelendata=='u'){output_high(pin_d3);delay_ms(tussuresi);output_low(pin_d3);}
  if(gelendata=='d'){output_high(pin_c4);delay_ms(tussuresi);output_low(pin_c4);}
  if(gelendata=='y'){output_high(pin_c5);delay_ms(tussuresi);output_low(pin_c5);}
  if(gelendata=='4'){output_high(pin_d0);delay_ms(tussuresi);output_low(pin_d0);}
  if(gelendata=='5'){output_high(pin_c3);delay_ms(tussuresi);output_low(pin_c3);}
  if(gelendata=='9'){output_high(pin_e0);delay_ms(tussuresi);output_low(pin_e0);}
  if(gelendata=='0'){output_high(pin_a0);delay_ms(tussuresi);output_low(pin_a0);}
  if(gelendata=='e'){output_high(pin_a1);delay_ms(tussuresi);output_low(pin_a1);}
  if(gelendata=='s'){output_high(pin_a2);delay_ms(tussuresi);output_low(pin_a2);}
  if(gelendata=='r'){output_high(pin_a3);delay_ms(tussuresi);output_low(pin_a3);}
  if(gelendata=='t'){output_high(pin_a5);delay_ms(tussuresi);output_low(pin_a5);}
  datageldi=0;
  gelendata=0;
   }
if(overrun_flag) { 
  gelendata = rcreg; 
  gelendata = rcreg; 
  gelendata = rcreg; 
}
  
   }
 



similasyonda çalıştı umarım gerçektede çalışır yarın deniycez bakalım sizede çalışmalarınızda başarılar diliyorum çok teşekkür ederim .

Ziya

Alıntı yapılan: "debi"Peki OERR bitini kontrol edip, şayet ki 1 ise CREN bitini önce '0'a sonra '1'e çekmek bu işi çözer mi? .
Gerek yok ki. üç kere okutman sorunu çözer. Datasheeti oku.
Bu günden sonra hiç kimse sarayda, divanda, meclislerde ve seyranda Türk dilinden başka dil kullanmaya. (13 Mayıs 1277) Karamanoğlu Mehmet Bey

Ziya

Alıntı yapılan: "zcemix"
#int_rda
void serihaberlesme_kesmesi ()
{
 // disable_interrupts(int_rda); // int_rda kesmesini pasif yap
 gelendata = getc(); // seri porttan 1 karakter oku
 putc(gelendata);
 datageldi=1;
// enable_interrupts(int_rda); // kesmeyi aktif etme işini ana döngüden aldım buraya koydum
}

interruptlar otomatik olarak düzenlenir, enable veya disable yapman gereksiz yere kaynak tüketimine neden olur. Zaten interrupta gider gitmez Pic otomatik olarak disable yapar. Rutin çıkışı retie komutu ile yapıldığından da otomatik olarak enable edilir. rcreg'i okutmakla rcif temizlenir. Senin ilave komut yazmana gerek kalmıyor.

İnerrupt rutini yazmana hiç gerek yok.
main()
{
...
while(1)
{ if(kbhit()
   { 
    gelendata = getc(); // seri porttan 1 karakter oku
    putc(gelendata);
    if(gelendata=='1'){output_high(pin_c0);delay_ms(tussuresi); output_low(pin_c0);}
    if(gelendata=='2'){output_high(pin_c1);delay_ms(tussuresi);output_low(pin_c1);}
    ...
    if(overrun_flag) 
     {
      gelendata = rcreg;
      gelendata = rcreg;
      gelendata = rcreg; Printf("\rOverrun hatası olustu, giderildi...\r");
     } 
    }// if(kbhit)..

} // while
} // main
Bu yeterlidir.
Bu günden sonra hiç kimse sarayda, divanda, meclislerde ve seyranda Türk dilinden başka dil kullanmaya. (13 Mayıs 1277) Karamanoğlu Mehmet Bey

zcemix

Ziya bey dediklerinizi yaptım ve CCS'nin Tools'undaki siow.exe ile test ettim sonuç gerçekten mükemmel klavyeden bir tuşa basıyorum ve hiç bırakmıyorum pic'in ilgili çıkışına osiloskopla baktığımda gerçekten tümüne cevap veriyor ve asla kilitlenmiyor cevaplarınız için çok teşekkür ederim umarım benim gibi acemiler bu konuyu görür ve faydalanır iyi günler çalışmalarınızda başarılar...

Ziya

9600 bps haberleşme hızında bir bayt yaklaşık 1 ms. de iletilir. delay_ms(tussuresi); bu sürenin iki katı gecikme sağlarsa overrun error ile karşılaşma ihtimaliniz olabilirdi. Tabi burada sizi kurtaran klavyede basılan her tuş için klavyenizin dikkate değer bir gecikme sağlaması. Eğer bu bilgiler başka bir pic ten gecikmesiz geliyor olsaydı delay_ms(tussuresi); overrun error oluşmasına sebep olabilir.
Bu günden sonra hiç kimse sarayda, divanda, meclislerde ve seyranda Türk dilinden başka dil kullanmaya. (13 Mayıs 1277) Karamanoğlu Mehmet Bey

zcemix

Aslında ben bu testi 115200 bps ile yaptım sorun çıkmadı acaba çıktıda
if(overrun_flag) 
     { 
      gelendata = rcreg; 
      gelendata = rcreg; 
      gelendata = rcreg;
     }

durumu kurtardımı bilmiyorum ama bu kadarı bile işimi gördü tabii birde picle falan deneyip en iyi sonucu almak lazım bu arada ben 115200'le denedim (herhangibir sorun çıkmadı) ama  16f877 bu hıza gerçekten çıkabilirmi yada daha üstüne..

XX_CİHAN_XX

Kristaline 15pf lik kondansatörleri bağlamazsan kitlenme yapar.
Yirmi yaşındaki bir insan, dünyayı değiştirmek ister . Yetmiş yaşına gelince , yine dünyayı değiştirmek ister, ama yapamayacağını bilir.

zcemix

Alıntı yapılan: "XX_CİHAN_XX"Kristaline 15pf lik kondansatörleri bağlamazsan kitlenme yapar.

Ben her zaman 22pf'lık kondansatörler bağlıyorum 15pf'mı olmalı

XX_CİHAN_XX

22 de olur sorun değil ben önceleri hiç bağlamadan kullanıyordum ama usart gibi seri haberleşmelerde bağlamayınca kitlenme yaptığını fark ettim.
Sen bağlamışsın o halde yazılımı incelemeye devam :)
Yirmi yaşındaki bir insan, dünyayı değiştirmek ister . Yetmiş yaşına gelince , yine dünyayı değiştirmek ister, ama yapamayacağını bilir.