INT_RDA KESMESİ 20MHZ 18F4520 SORUN

Başlatan Faruk53, 24 Nisan 2015, 19:04:11

Faruk53

Merhaba arkadaşlar;

18F4520 ile seri haberleşme çalışması yapmaya çalışıyorum. Amacım işlemcinin rx'ine gelen bilgiyi lcd ekrana yazdırmak ve gelen bilgiye göre işlemler yapmak. Gelecek ifade string bir ifade olacak. Önce rx den gelen bilgiyi ekrana basmayla başlayayım dedim fakat iki sorunla karşılaştım;

İlki ve beni en çok can sıkan kısmı; Bilgiyi gönderdiğimde ekrana yazmıyor. Devrenin enerjisini kesip tekrar verdiğimde ekranda yolladığım yazıyı görüyorum.
ikincisi ise; örneğin ilk yolladığım karaketer "abcde" enerji kesildi ekranda görüldü, ikinci yolladığım "123" enerji kesildiğinde ekranda görünen "123de"
yani ekran temizlenmesi yapılmıyor.
Forumda bu konuyu araştırdım ama ya bulamadım ya da gözümden kaçtı. Eğer varsa da göremediysem affola arkadaşlar.
Yazdığım kod aşağıdadır.

Not: Denemeleri docklight ile yapyorum.Similasyonda çalışıyor.
Şimdiden teşekkür ederim. İyi çalışmalar herkese.


#include <18f4520.h>

//#include<string.h>

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


#use delay(clock=20M)

#define use_portb_lcd TRUE // LCD B portuna bağlı

#include <lcd.c> // lcd.c dosyası tanıtılıyor

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


unsigned char cevap[10]; 
 
#int_rda // RX ucuna veri gelince meydane gelen kesme

void serihaberlesme_kesmesi (void)
{

disable_interrupts(int_rda); // int_rda kesmesini pasif yap
gets(cevap); // String ifadeyi al ve "cevap" adlı dizi değişkenine aktar

}

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ışı


//set_tris_C(0xff);


lcd_init(); // LCD'yi hazırla
enable_interrupts(GLOBAL); // Aktif edilen tüm kesmelere izin ver


while(true) // Sonsuz döngü
{

enable_interrupts(int_rda); // int_rda kesmesi aktif
delay_ms(150);
printf(lcd_putc,"\f%s",cevap); //LCD'yi temizle ve klavye string ifadesini LCD'de göster


}}

Murat Mert

Bunu bir denermisin.

#include <18f4520.h>
#use delay(clock=20M)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors)


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

#define use_portb_lcd TRUE // LCD B portuna bağlı

#include <lcd.c> // lcd.c dosyası tanıtılıyor
//#include<string.h>


unsigned char cevap[10]; 
 
#int_rda // RX ucuna veri gelince meydane gelen kesme

void serihaberlesme_kesmesi (void)
{

   disable_interrupts(INT_RDA); // int_rda kesmesini pasif yap
   gets(cevap); // String ifadeyi al ve "cevap" adlı dizi değişkenine aktar
   enable_interrupts(INT_RDA);
   
}

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ışı


   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

   lcd_init(); // LCD'yi hazırla

while(true) // Sonsuz döngü
{


   
delay_ms(150);
printf(lcd_putc,"\f%s",cevap); //LCD'yi temizle ve klavye string ifadesini LCD'de göster



}}
mert07

ferdem

Seri veri kesmesi normalde bir byte alır, bir byte geldiğinde kesmeye gider. Kesme içinde string almak istediğinizde ortalık karışıyor, karmaşa orada...
Önerim; bu uygulamayı öncelikle bir byte için deneyin, sonra kesme ile aldığınız byte ları diziye dizerek string oluşturursunuz, stringi LCD ye basabilirsiniz. Forumda örnekler vardır.

Kesme içinde data=getc(); ile datayı okuyun ve newdata=1 yapın.

Ana döngüde newdata kontrol edilsin, 1 ise LCD ye yazsın ve newdata=0 yapsın. Böyle bir deneyin, tek byte üstünden gidin.

JOKERAS

Selam,

Lcd clear yaptıktan sonra lcd'yi update edin.
Her update yapmadan önce lcd'yi silmeniz gerekli.

Birde false interrupt oluşmaması için intterrupt enable yapmadan önce
interrupt flag'ini temizleyip intrrupt'ı aktif edip deneyin.


omereliusuk

baudrate düşük tut. lcd o kadar hızlı değil.

lcd_init(); // LCD'yi hazırla
enable_interrupts(GLOBAL); // Aktif edilen tüm kesmelere izin ver
....
#
int veri_uzunluğu=5;
int veri_sayisi=0;
#INT_RDA
void  RDA_isr(void)
      {
veri[veri_sayisi++]=getc();
if((veri_sayisi)>veri_uzunlugu){kesme_geldi=1;veri_sayisi=0;}//toplamda 5 byte tan büyük veri geldiyse
}


while(true) // Sonsuz döngü
{

enable_interrupts(int_rda); // int_rda kesmesi aktif

if(kesme_geldi){
lcd_clear();
printf(lcd_putc,"\f%s",cevap); //LCD'yi temizle ve klavye string ifadesini LCD'de göster
}

}}

bir dene bakalım olacak mı? (hatalar olabilir.)  :-[

Faruk53

Öncelikle ilgilenip bilgilerinizi paylaştığınız için çok teşekkür ederim.
@murat mert hocam verdiğiniz kodu denedim malesef çalışmadı.

dediklerinizi dikkate alarak bi kaç düzeltme yaptım ama malesef yine sonuç alamadım. gece gece yığınla test çözdükten sonra büyük bir hevesle oturdum programın başına bi kaç deneme yaptım ama malesef olmadı  :(  lcd_update() kısmında derleyici hata verdi.
@ferdem hocam son olarak dediklerinizi uygulamaya çalıştım kodlar aşağıdaki gibi. String alımını gerçekten öğrenmek istyorum.

#include <18f4520.h>
#use delay(clock=20M)
// Denetleyici konfigürasyon ayarları
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOMCLR,NOCPD

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#byte INTCON =0X80//
#byte PIE1 = 0X10
//#byte PIR1= 0X20

#define use_portb_lcd TRUE // LCD B portuna bağlı

#include <lcd.c> // lcd.c dosyası tanıtılıyor
//#include<string.h>


//unsigned char cevap[10]; 
char data;
int1 new_data=0;
 
#int_rda // RX ucuna veri gelince meydane gelen kesme

void serihaberlesme_kesmesi (void)
{
  disable_interrupts(int_rda);
  data=getc();
  new_data=1;
   //clear_interrupt(int_rda);
  }

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ışı


  
   enable_interrupts(GLOBAL);

   lcd_init(); // LCD'yi hazırla

while(true) // Sonsuz döngü
{
 
 
 if (new_data=1)
 {
delay_ms(150);
printf(lcd_putc,"\f%s",data);
new_data=0;
 }
enable_interrupts(INT_RDA);

}}

ferdem

Kesme içinde disable_interrupts(int_rda); yazmaya gerek yok.
Ana döngüde if (new_data==1) yazılmalıydı, derleyici uyarı vermiş olmalı.
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RDA); // bir defa enable etmek yeterli, kesme içinde disable edilmesine gerek yok.
   lcd_init(); // LCD'yi hazırla

while(true){ // Sonsuz döngü
  if (new_data==1){ // yeni data geldiyse LCD ye yaz
    delay_ms(150);
    printf(lcd_putc,"\f%d", data);
    new_data=0;
  }
}


String in bir özelliği yok, byte dizisi + son eleman özel bir byte. Ekrana basarken %s nin yaptığı iş bu sonlandırma karakterine kadarki kısmı basmak, başka bir olayı yok(benim bildiğim).
gets fonksiyonunun ne yaptığı bir yerlerde vardı, while içinde karakter karakter alıyor ne zaman sonlandırma karakteri geliyor bitiriyor.
String alımı kolay, önce bir byte için çalışsın.

Faruk53

Hocam dediğiniz gibi verileri 1 byte olarak lcd'ye işlemi sayenizde gerçekleşti. desimal olarak dockligten gönderdiğim bütün karakterleri lcd de görebiliyorum. Kendim bi kaç deneme yaptım ondan sonra. Ama string olayını hala başaramadım. Kesme içinde gets(cevap) yazdığımda ve lcd ye direk olarak %s(string verileri yazar) yaptığımda kesme asla çalışmıyor.

bende şöyle bişey düşündüm. Gelen bilginin dec karşılığı örneğin 65 olsun. asci karşılığı A. bir lookup tablosu yazarak ilerlemek ne kadar doğru olur. A harfi için if döngüsü kullanarak Ekrana bastım ama Bütün harfler filan çok mu kasıntı olur. Sizce nasıl bir yol izlemeliyim?

#include <18f4520.h>
#use delay(clock=20M)
// Denetleyici konfigürasyon ayarları
#fuses hs,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOMCLR,NOCPD

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#byte INTCON =0X80//
#byte PIE1 = 0X10
//#byte PIR1= 0X20

#define use_portb_lcd TRUE // LCD B portuna bağlı

#include <lcd.c> // lcd.c dosyası tanıtılıyor
//#include<string.h>


//unsigned char cevap[10]; 
char data[2];
int new_data[5];
 
#int_rda // RX ucuna veri gelince meydane gelen kesme

void serihaberlesme_kesmesi (void)
{
 
  data[1]=getc();
  //data[2]=getc();
  new_data[1]=1;
  //new_data[2]=1;
  
  }

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ışı


  
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RDA); // bir defa enable etmek yeterli, kesme içinde disable edilmesine gerek yok.
   lcd_init(); // LCD'yi hazırla

while(true) // Sonsuz döngü
  {
  
      if (new_data[1]==1)
    {   
    delay_ms(150);
    printf(lcd_putc,"\f %d",data[1]);
    new_data[1]=0;
    }
      }
        }      
  //if döngüsüyle A harfini ekrana basmak için ;
  
  //  if (new_data[1]==1)
  //  {
  //  if (data[1]=65)
  // {
  // delay_ms(150);
  // printf(lcd_putc,"\f A");
  // new_data[1]=0;
  //  }

ferdem

#8
Lookup tablosuna gerek yok, %c, %d zaten o işi yapıyor. %d derseniz integer karşılğı, %c derseniz karakter karşılığı basar. Örneğin 65 sayısı; %d ile 65 olarak, %c ile 'A' olarak gösterilir. Anlaşıldığı üzere kesme içinde gets olayı problemli bir olay, nerede neden kullanılır ben de bilmiyorum.
string için gelen verilerin byte byte bir buffer a dizilmesi gerekir, sonuna da bir sonlandırma karakteri olursa buffer string olmuş demektir. LCD ye bas dediğinizde sonlandırma karakterine kadar basılır. Kabaca aşağıdaki gibi bir işlem gerekiyor.
seri_kesme(){
data=getc();
if(index<buf_size){
buffer[index]=data;
index++;
if(data==sonlandirma_karakteri){
index=0;
string_alindi=1;
}
}

while(1){
if(string_alindi==1){
printf(lcd_putc,\f %s, buffer); //temizle, yaz
string_alindi=0;
//burada buffer temizlenebilir
}
}

Sonlandırma karakterini hatırlamıyorum, belki 0 dır. 5 harfli bir string tanımlayıp mesela string kelime[]="Kitap". Sonra %d ile kelime[5] i basarsanız sonlandırma karakterinin sayı karşılğını görebilirsiniz.


Faruk53

#9
Hocam yardımlarınız için Allah razı olsun hakkınızı helal edin. Kodlar aşağıdaki gibi sorunsuz çalışıyor. Sıradaki işlem gelen cevaba göre karşılaştırmalar yapıp sonuçlar elde etmek. Kodlar aşağıdaki gibi ferdem hocamın yardımıyla... Tamam biter bitmez de inşallah forumda paylaşacağım. Tekrar teşekkürler hocam. İyi bir öğretmensiniz..
#include <18f4520.h>

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


#use delay(clock=20M)


#define use_portb_lcd TRUE // LCD B portuna bağlı
#include <lcd.c> // lcd.c dosyası tanıtılıyor

#use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, parity=N, stop=1,stream=USART1) 
#define BUFFER_SIZE 96
BYTE  buffer[BUFFER_SIZE];

#byte INTCON =0X80//
#byte PIE1 = 0X10

char data;
int1 string_alindi=0;
int8 index;
//char son_bit[]= "\r\n";

#int_rda // RX ucuna veri gelince meydane gelen kesme

void seri_kesme(void)
{
data=getc();
if(index<BUFFER_SIZE)
{
buffer[index]=data;
index++;
}
if(data==13)
{
index=0;
string_alindi=1;
}}

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ışı


enable_interrupts(GLOBAL); // Aktif edilen tüm kesmelere izin ver
enable_interrupts(int_rda); // int_rda kesmesi aktif
lcd_init(); // LCD'yi hazırla


while(true)
{

if (string_alindi==1)
{
printf(lcd_putc,"\f %s", buffer); //temizle, yaz
string_alindi=0;
buffer[0]=0;buffer[1]=0;buffer[2]=0;buffer[3]=0;buffer[4]=0;buffer[5]=0;buffer[6]=0;//temizle//burada buffer temizlenebilir
}             
}}

ugurer

Bu yöntemi kullandım düzgün bir şekilde çalışıyor. Fakat sürekli veri gönderecekseniz bufferları temizlemeyi unutmayın.
Alıntı yapılan: Faruk53 - 01 Mayıs 2015, 23:36:45
Hocam yardımlarınız için Allah razı olsun hakkınızı helal edin. Kodlar aşağıdaki gibi sorunsuz çalışıyor. Sıradaki işlem gelen cevaba göre karşılaştırmalar yapıp sonuçlar elde etmek. Kodlar aşağıdaki gibi ferdem hocamın yardımıyla... Tamam biter bitmez de inşallah forumda paylaşacağım. Tekrar teşekkürler hocam. İyi bir öğretmensiniz..
#include <18f4520.h>

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


#use delay(clock=20M)


#define use_portb_lcd TRUE // LCD B portuna bağlı
#include <lcd.c> // lcd.c dosyası tanıtılıyor

#use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, parity=N, stop=1,stream=USART1) 
#define BUFFER_SIZE 96
BYTE  buffer[BUFFER_SIZE];

#byte INTCON =0X80//
#byte PIE1 = 0X10

char data;
int1 string_alindi=0;
int8 index;
//char son_bit[]= "\r\n";

#int_rda // RX ucuna veri gelince meydane gelen kesme

void seri_kesme(void)
{
data=getc();
if(index<BUFFER_SIZE)
{
buffer[index]=data;
index++;
}
if(data==13)
{
index=0;
string_alindi=1;
}}

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ışı


enable_interrupts(GLOBAL); // Aktif edilen tüm kesmelere izin ver
enable_interrupts(int_rda); // int_rda kesmesi aktif
lcd_init(); // LCD'yi hazırla


while(true)
{

if (string_alindi==1)
{
printf(lcd_putc,"\f %s", buffer); //temizle, yaz
string_alindi=0;
buffer[0]=0;buffer[1]=0;buffer[2]=0;buffer[3]=0;buffer[4]=0;buffer[5]=0;buffer[6]=0;//temizle//burada buffer temizlenebilir
}             
}}


STR344

Merhaba ,
güzel paylaşım için hepinize teşekkürler.2 donanımsal uart kullanıldığında buffer kullanımı için örnek paylaşabilirmisiniz.