interrupt işlemiyor

Başlatan smail, 27 Ocak 2014, 21:33:23

smail

merhaba arkadaşlar,

her türlü yöntemi denedim ama olmadı. interrupt işlemiyor. rb4 pinine bağlı butona basılınca interrupt ın devreye girip motorlarımın durmasını , butondan çekince ise tekrar motorlarımın dönebilmesini istiyorum. her yöntemi denedim diyebilirim. lütfen yardımcı olun..

#include <p18f452.h>
#include <pwm.h>
#include <stdlib.h>
#include <usart.h>
#include <timers.h>
#include <delays.h>
#include <stdio.h>
#include <adc.h>
#include <portb.h>

#pragma config OSC = XT, PWRT = ON, WDT = OFF, LVP = OFF, DEBUG = OFF
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF, CPB = OFF, CPD = OFF
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF, WRTB = OFF,WRTC = OFF, WRTD = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF, EBTRB = OFF

void motor (int);
void int_handler(void);
int x; 
#pragma code high_vector=0x08
void high_interrupts (void) {
    _asm GOTO int_handler _endasm
}
 
#pragma code low_vector=0x18
void low_interrupts (void) {
    _asm GOTO int_handler _endasm
}
 
#pragma code
#pragma interrupt int_handler
void int_handler(void) {
   
   if(PORTBbits.RB4 == 0)     // PORTB Change Interrupt
   {
    
    PORTDbits.RD0 = 1;
    PORTDbits.RD1 = 1;
    PORTDbits.RD2 = 1;
    PORTDbits.RD3 = 1;
    INTCONbits.RBIF = 0;
     
   } 
   if(PORTBbits.RB4 != 0)
   {
    motor(x);      
   }

   }

#pragma code

void main(void){
    TRISB = 0xff;
    PORTB = 0;
    TRISC=0x80;
    PORTC=0; 
    TRISD=0;
    PORTD=0;    
    ADCON1 = 0x0F; // All channels Digital 
       
     //Enables all interrupts & the RB port change interrupt
    INTCONbits.GIE  = 1;        // Interrupts generell erlauben
    INTCONbits.RBIF = 0;        // Interrupt on Change Flag aus
    INTCONbits.RBIE = 1;        // Interrupt on Change an den PINs
       

  
    OpenRB0INT(PORTB_CHANGE_INT_ON & FALLING_EDGE_INT);
    
    OpenUSART(USART_TX_INT_OFF &  // usart konfigürasyon ayarlarý 
			  USART_RX_INT_ON &
			  USART_ASYNCH_MODE &
			  USART_EIGHT_BIT &
			  USART_CONT_RX &
			  USART_BRGH_HIGH,207);
    OpenTimer2 ( TIMER_INT_OFF & T2_PS_1_4 & T2_POST_1_1 );  
    OpenPWM1(249); // Period
    OpenPWM2(249);   
    SetDCPWM1(0);
	SetDCPWM2(0);
    
    INTCONbits.GIE = 1;
    RCONbits.IPEN = 0;          // priority       // enable interrupt
    INTCONbits.RBIE = 1; 

    if((BusyUSART()));
    
	while(1)
    {        
            x=ReadUSART();  
            while (!DataRdyUSART());
            motor(x); 
    }
}

void motor (int x)
{
            
            if(x=='S')
            { 
             SetDCPWM1(0);
             SetDCPWM2(0);
             PORTDbits.RD0 = 0;
             PORTDbits.RD1 = 0;
             PORTDbits.RD2 = 0;
             PORTDbits.RD3 = 0;
             PORTDbits.RD6 = 1;
             PORTDbits.RD7 = 0;     
            }
         
            if(x=='F')
            {
             SetDCPWM1(498);
             SetDCPWM2(498);
             PORTDbits.RD0 = 0;
             PORTDbits.RD1 = 1;
             PORTDbits.RD2 = 0;
             PORTDbits.RD3 = 1;                       
             PORTDbits.RD6 = 1;
             PORTDbits.RD7 = 0;                           
             }
                      
          
            if(x=='V')
            {
             SetDCPWM1(498);      
             SetDCPWM2(498);
             PORTDbits.RD0 = 1;
             PORTDbits.RD1 = 0;
             PORTDbits.RD2 = 1;
             PORTDbits.RD3 = 0;
             PORTDbits.RD6 = 1;
             PORTDbits.RD7 = 0;                                
             }

            if(x=='R')
            {

             SetDCPWM1(124);	         
             SetDCPWM2(498);
             PORTDbits.RD0 = 0;
             PORTDbits.RD1 = 1;
             PORTDbits.RD2 = 0;
             PORTDbits.RD3 = 1;                       
             PORTDbits.RD6 = 1;
             PORTDbits.RD7 = 0;                 
             }
                      
          
            if(x=='L' )
            {
             SetDCPWM1(498);	         
             SetDCPWM2(124);
             PORTDbits.RD0 = 0;
             PORTDbits.RD1 = 1;
             PORTDbits.RD2 = 0;
             PORTDbits.RD3 = 1; 
             PORTDbits.RD6 = 1;
             PORTDbits.RD7 = 0;                  
            }
            
            
}



Tagli

Kodu detaylı incelemedim ama ilk bakışta göze çarpan birkaç hata, daha doğrusu usulsüz yazım var.

Öncelikle, çıkış amacıyla PORT'lara erişirken PORT değil LAT register'larını kullanmalısın. Özellikle PORT register'ları üzerinden bitlere yapılan arka arkaya erişim tehlikeli. Komutların kendilerinden önceki komutları geçersiz kılma ihtimali var. Senin kodunda arka arkaya gelen PORTDbits.RD0 = 1; PORTDbits.RD1 = 1; gibi satırlardan bahsediyorum. Bu işlemleri LATDbits üzerinden yap. Tabi bu dediğim sadece yazmalar için. Bacakları okumak gerektiğinde yine PORTD kullanılacak.

Kesme kodu içinde her kesme türü için ayrı bir if bloğu açıp, if (bayrak == 1 && izin == 1) şeklinde kontrol etmek usuldendir. Buna uymazsan, tespit etmesi güç hatalarla karşılaşabilirsin.

OpenRB0INT(PORTB_CHANGE_INT_ON & FALLING_EDGE_INT);
Aklımda çok net kalmamış olabilir ama bu satır bana yanlış gözüktü. Buradaki iki ayrı ayar, sanki iki farklı kesme türü için gibi. PORTB kesmesi hem düşen hem yükselen kenarda çalışır, yani sadece düşen kenarda çalışsın diyemezsin. İkinci ayar seçeneği sanki diğer kesme için gibi duruyor (PIC16'larda RB0 kesmesi olarak bilinen kesme, PIC18'lerde EXT0 veya INT0 gibi bir ismi vardı ve galiba 2 veya 3 adet vardı bunlardan, pek hatırlamıyorum şimdi). PORTB değişim kesmesi ile çalışırken dikkatli olmak lazım, hata yapmak kolay.

Adım adım hata ayıklama işlemi yapman gerekiyor. Öncelikle program akışının kesme kodunun içine girip girmediğine bak. Kesme olunca bir LED yakıp söndür. Ben hep öyle yaparım.

Son olarak, C18 güncelliğini yitirdi. Sana tavsiyem XC8'e geçmen. Kullanımının daha kolay olduğunu söyleyebilirim, özellikle de C18'e alışmış biri için.

Gökçe Tağlıoğlu

smail

#2
hocam bir kısım değişiklikler yaptım dediğiniz bu şekilde mi oluyor ?

"Kesme kodu içinde her kesme türü için ayrı bir if bloğu açıp, if (bayrak == 1 && izin == 1) şeklinde kontrol etmek usuldendir. Buna uymazsan, tespit etmesi güç hatalarla karşılaşabilirsin." kısmını anlayamadım bir örnek verebilirmisiniz?

#pragma code
#pragma interrupt int_handler
void int_handler(void) {
   
   if(PORTBbits.RB4 == 0)     // PORTB Change Interrupt
   {
    LATDbits.LATD0 ^= 1; 
    LATDbits.LATD1 ^= 1; 
    LATDbits.LATD2 ^= 1; 
    LATDbits.LATD3 ^= 1; 
    INTCONbits.RBIF = 0;
     
   } 
   if(PORTBbits.RB4 != 0)
   {
    motor(x);      
   }

   }

#pragma code

void main(void){
    TRISB = 0xff;
    PORTB = 0;
    TRISC=0x80;
    PORTC=0; 
    TRISD=0;
    PORTD=0;    
    ADCON1 = 0x0F; // All channels Digital 
       
     //Enables all interrupts & the RB port change interrupt
    INTCONbits.GIE  = 1;        // Interrupts generell erlauben
    INTCONbits.RBIF = 0;        // Interrupt on Change Flag aus
    INTCONbits.RBIE = 1;        // Interrupt on Change an den PINs
       

  
    OpenRB0INT(PORTB_CHANGE_INT_ON);


mesaj birleştirme:: 27 Ocak 2014, 23:33:33

hocam en son şekliyle bu şekilde yaptım fakat yine çalışmıyor . bir bakabilirmisiniz..

#include <p18f452.h>
#include <pwm.h>
#include <stdlib.h>
#include <usart.h>
#include <timers.h>
#include <delays.h>
#include <stdio.h>
#include <adc.h>
#include <portb.h>

#pragma config OSC = XT, PWRT = ON, WDT = OFF, LVP = OFF, DEBUG = OFF
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF, CPB = OFF, CPD = OFF
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF, WRTB = OFF,WRTC = OFF, WRTD = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF, EBTRB = OFF

void motor (int);
void int_handler(void);
int x; 
#pragma code high_vector=0x08
void high_interrupts (void) {
    _asm GOTO int_handler _endasm
}
 
#pragma code low_vector=0x18
void low_interrupts (void) {
    _asm GOTO int_handler _endasm
}
 
#pragma code
#pragma interrupt int_handler
void int_handler(void) {
   
   if(INTCONbits.RBIF==1 && PORTBbits.RB4 == 0)     // PORTB Change Interrupt
   {
    LATDbits.LATD0 ^= 1; 
    LATDbits.LATD1 ^= 1; 
    LATDbits.LATD2 ^= 1; 
    LATDbits.LATD3 ^= 1; 
    INTCONbits.RBIF = 0; //Clear the PORTB RBIF flag
    PORTDbits.RD5=1;  
   } 
 
   if( PORTBbits.RB4 != 0)     // PORTB Change Interrupt
   {
    motor(x);
   }
}

void EnableInterrupts (void)
 {
        INTCONbits.RBIE = 1; //Ensure PORTB interrupts enabled
        INTCONbits.RBIF = 0; //Clear the PORTB interrupt flag
        INTCONbits.PEIE = 1; //Enable peripheral interrupts (don't think i really need this one
        INTCONbits.GIE = 1; //Enable all interrupts
 }


void main(void){
    TRISB = 0xff;
    PORTB = 0;
    TRISC=0x80;
    PORTC=0; 
    TRISD=0;
    PORTD=0x80;    
    ADCON1 = 0x0F; // All channels Digital 
    
    OpenPORTB(PORTB_CHANGE_INT_ON); 
    
    EnableInterrupts(); //Setup the interrupts    
    
    OpenUSART(USART_TX_INT_OFF &  // usart konfigürasyon ayarlarý 
			  USART_RX_INT_ON &
			  USART_ASYNCH_MODE &
			  USART_EIGHT_BIT &
			  USART_CONT_RX &
			  USART_BRGH_HIGH,207);
    OpenTimer2 ( TIMER_INT_OFF & T2_PS_1_4 & T2_POST_1_1 );  
    OpenPWM1(249); // Period
    OpenPWM2(249);   
    SetDCPWM1(0);
	SetDCPWM2(0);


    if((BusyUSART()));
    
	while(1)
    {        
            x=ReadUSART();  
            while (!DataRdyUSART());
            motor(x); 
    }
}

void motor (int x)
{
            
            if(x=='S')
            { 
             SetDCPWM1(0);
             SetDCPWM2(0);
             LATDbits.LATD0 ^= 0;
             LATDbits.LATD1 ^= 0;
             LATDbits.LATD2 ^= 0;
             LATDbits.LATD3 ^= 0;
             LATDbits.LATD6 ^= 1;
             LATDbits.LATD7 ^= 0;    
            }
         
            if(x=='F')
            {
             SetDCPWM1(498);
             SetDCPWM2(498);
             LATDbits.LATD0 ^= 0;
             LATDbits.LATD1 ^= 1;
             LATDbits.LATD2 ^= 0;
             LATDbits.LATD3 ^= 1;
             LATDbits.LATD6 ^= 1;
             LATDbits.LATD7 ^= 0;                       
             }
                      
          
            if(x=='V')
            {
             SetDCPWM1(498);      
             SetDCPWM2(498);
             LATDbits.LATD0 ^= 1;
             LATDbits.LATD1 ^= 0;
             LATDbits.LATD2 ^= 1;
             LATDbits.LATD3 ^= 0;
             LATDbits.LATD6 ^= 1;
             LATDbits.LATD7 ^= 0;                              
             }

            if(x=='R')
            {

             SetDCPWM1(124);	         
             SetDCPWM2(498);
             LATDbits.LATD0 ^= 0;
             LATDbits.LATD1 ^= 1;
             LATDbits.LATD2 ^= 0;
             LATDbits.LATD3 ^= 1;
             LATDbits.LATD6 ^= 1;
             LATDbits.LATD7 ^= 0;                 
             }
                      
          
            if(x=='L' )
            {
             SetDCPWM1(498);	         
             SetDCPWM2(124);
             LATDbits.LATD0 ^= 0;
             LATDbits.LATD1 ^= 1;
             LATDbits.LATD2 ^= 0;
             LATDbits.LATD3 ^= 1;
             LATDbits.LATD6 ^= 1;
             LATDbits.LATD7 ^= 0;                
            }
            
            
}

Tagli

Kesme kodu girişi şu şekilde olmalıydı:
if(INTCONbits.RBIF==1 && INTCONbits.RBIE==1)
Yani izin biti dediğim, sonu IE ile biten kesme açma kapama (izin) biti. Bloğun içine girdikten sonra yine istiyorsan PORT durumlarına göre istediğin kontrolü yaparsın, o ayrı.

LAT bitlerini ayarlarken neden ^= kullandın? Amacın doğrudan atama yapmak değil miydi?

Benim senin programın üzerinde uzaktan hata ayıklama yapmam pek mümkün değil. Ben sadece yol gösterebilirim, hata çok bariz olmadığı sürece tespit edemem. Dediğim gibi, ilk kontrol etmen gereken şey, istediğin şartlar oluştuğunda kodun kesme bölümüne dallanıp dallanmadığını görmen. Bunu en basit şekilde bir LED yakarak gözlemleyebilirsin.
Gökçe Tağlıoğlu

yldzelektronik

@smail

Pogramını kesmeye girip girmediğini (Kesme izinlerini doğru yapılandırıp yapılandırmadığını) kontrol etmeyi dener misin?Böylece sorunun nerede olduğu daha net anlaşılır.

Kesmeye girdiğinde led yaksın veya printf debug yap.
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

Gökhan BEKEN

Bir tavsiyem var;
Bu tarz sorunlarda, kimse kodları alıp da proje oluşturup, simülasyon oluşturup, derleyip denemez.
Siz projeyi ve simülasyonun proje halini yükleyip, link verseydiniz, çok daha fazla kişi ilgilenecekti. Sorun çözüldüğünde de yararlananların sayısı çok olacaktı.
Özel mesaj okumuyorum, lütfen göndermeyin.

smail

değerli hocalarım, aşağıdaki siteye kodlar, hex ve proteus dosyalarını yükledim. ben kendi yazdığım bir yazılımla programı kontrol ediyordum. onu göndersem birde ek olarak sanal port programı yüklemeniz gerekiyordu. bende proteusa virtual terminal ekledim. virtual terminal açıkken f tuşuna basınca ileri s tuşuna basınca durması gerekiyor. en çokda takıldığım konu rb4 pinindeki buton kapalı durumdayken motorların hiç çalışmaması gerekiyor. ben kodları mplab da derledim. ilgilendiğiniz için çok  teşekkür ederim.

http://www.dosya.tc/server23/jIhILm/interrupt.rar.html

selimkoc

http://elektrokod.wordpress.com/2013/10/12/portb-change-interrupt-portb-degisim-kesmesi/

Register bazında şematik olarak anlatım ve uygulama var. Faydalı olması ümidiyle..

smail

#8
selim hocamın verdiği örneğe çok benzer biçimde yaptım. şu an sonuca sanki çok yaklaştım. butona basıldığında interrupt devreye giriyor fakat buton hala basılı durumdayken basarsam yine döngüden çıkıp motorlar dönmeye devam ediyor. ben ise buton basılı durumdayken ne olursa olsun motorlar çalışmasın istiyorum.. selim hocanın kodlarına göre düzenlediğim son kodlar şu şekilde oldu:

#pragma interrupt int_handler

void int_handler(void) {
  if(INTCONbits.RBIF) // RBIF bayrağı oluşmuşsa
  {
       INTCONbits.RBIF=0; // RBIF bayrağını sil
       
       if(!PORTBbits.RB4) 
       PORTD=0x20;
       else
       motor(x);        
  }
}

void main(void){

    TRISB = 0x10;
    INTCONbits.GIE=1; // bütün kesmelere izin ver
    INTCONbits.RBIE=1; // PORTB değişim kesmesine izin ver
    INTCONbits.RBIF=0; // RBIF bayrağını temizle
    PORTB = 0;
    TRISC = 0x80;
    PORTC = 0;
    TRISD = 0;
    PORTD = 0x80;

yldzelektronik

Buton hala basılı iken basmak nasıl oluyor?

While ile yapabilirsin.

while(portdbits.rd0); gibi.

Yada bayrak ekleye de bilirsin.
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

smail

yani şuan sadece butona basıldığı anda interrupt fonksiyonuna giriyor sonra elim hala butona basılı olmasına rağmen, yani hala if(!PORTBbits.RB4) olmasına rağmen, motorları hareket ettirebiliyorum. dediğiniz gibi while(!PORTBbits.RB4) şeklinde yazdım , bu seferde rb4 deki interrupt butonundan elimi çeksem dahi fonksiyon ordan geri çıkamadı. yani bu seferde program tamamen kilitlenip interrupt fonksiyonun içinde kaldı.

Tagli

Benim de aklıma gelen çözüm bayrak oldu. Yoksa sürekli olarak kesmede kalmak gerekir ki bu saçma. Kesme ne de olsa hem düşen hem de yükselen kenarda gelecek, bu durumda hem düğmeye basılmasını hem de çekilmesini algılayacaktır. Kesmenin yapması gereken şey bayrağın terslemekten (toggle) ibaret. Ancak, ana döngünün, bayrağı tatmin edici bir sıklıkta kontrol etmesi gerekir.

Elbette düğmenin fiziksel olarak temiz bir sinyal vermeyeceği de göz önünde bulundurulmalı ve gereken önlemler alınmalı (debounce diye aratılabilir).

Düğmenin basılı olması fiziksel olarak bir güvenlik önlemi ise, bu işe PIC'i karıştırmayıp harici bir AND kapısı kullanmak daha doğru olabilir.
Gökçe Tağlıoğlu

yldzelektronik

Ben yazarken @Tagli yanıtlamış.O halde main içinde flag kontrolü ile de yapabilirsin.Eğer main dolu değilse interruptu kapatıp flag kontrolü yapabilirsin.
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

smail

RBIF flagını kontrol ederekmi yapayım ? tam olarak ne yazmalıyım örnek kod yazabilirmisiniz? while 'ı hiç bir şekilde yutturamadım.

yldzelektronik

Alıntı yapılan: smail - 28 Ocak 2014, 17:29:49
RBIF flagını kontrol ederekmi yapayım ?

Benim önerim bu yönde idi
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.