PIC 18F2550 Interrupts in C18

Gast #1201684
Lesenswert?

#define MICROCHIP_C18 (1)

#if    MICROCHIP_C18
  void isr(void); //interrupt 1
  #pragma code high_vector=0x08
  void interrupt_at_high_vector(void)
  {
   _asm GOTO isr _endasm
}

#else
  void isr(void) interrupt 1;  //SDCC

#endif

………….

#if  MICROCHIP_C18
  #pragma interrupt isr
  void isr(void) //interrupt 1
#else
  void isr(void) interrupt 1  //SDCC
#endif
{
 if (INTCONbits.T0IF)
 {
……..

}
OP #1201931
Lesenswert?

Komisch, das funktioniert nicht... oder hab ich es falsch übernommen?
So lass ich ihn laufen und setz dann irgendwann RB0(INT0) auf high, 
Resultat bleibt aus.

Mfg.

void main(void){
  TRISA = 0x00;
  TRISB = 0xFF;
  TRISC = 0x00;

  LATA = 0x00;

  INTCONbits.INT0IE = 1;
  INTCONbits.GIE = 1;

  while(1){Nop();}
}


#define MICROCHIP_C18 1

#if MICROCHIP_C18
  void isr(void); //interrupt 1

  #pragma code high_vector=0x08
  void interrupt_at_high_vector(void){
    _asm GOTO isr _endasm
  }
#else
  void isr(void) interrupt 1;  //SDCC
#endif


#if  MICROCHIP_C18
#pragma interrupt isr
  void isr(void) //interrupt 1
#else
  void isr(void) interrupt 1  //SDCC
#endif
{
  if (INTCONbits.INT0IF){
    LATAbits.LATA0 = 1;
    INTCONbits.INT0IF = 0;
  }
}
OP #1202543
Lesenswert?

Genialer Tipp, vielen Dank. War so hilfreich wie lang.

Nein im Ernst, als "Handbuch" find ich nur ein paar lauwarme PDFs, deren 
Codebeispiele ich offenbar zu blöd bin zu übernehmen.

Mittlerweile hab ich es so, aber es verweigert nach wie vor jegliche 
Funktion. (So ähnlich war ein Beispiel aus besagtem Handbuch)
Was in ASM sofort funktioniert, gestaltet sich in C offenbar zu einem 
jenseits Problem.

Es wäre schön, wenn mir jemand sagen könnte, wie der Code umzugestalten 
ist, dass bei einem Signal an RB0/INT0 RA0 high geht, ich verzweifel da 
noch dran.



#include <p18f2550.h>

#pragma config FOSC  = ECPLLIO_EC
#pragma config PLLDIV   = 4
#pragma config CPUDIV   = OSC1_PLL2
#pragma config USBDIV   = 2
#pragma config PWRT  = ON
#pragma config BOR  = OFF
#pragma config WDT  = OFF
#pragma config LVP  = OFF

void high_isr(void);

#pragma code high_vector=0x08
void interrupt_at_high_vector(void){
    _asm goto high_isr _endasm
}

#pragma code

#pragma interrupt high_isr
void high_isr (void){
  if(INTCONbits.INT0IF){
    LATAbits.LATA0 = 1;
    INTCONbits.INT0IF = 0;
    Sleep();
  }
}

void main(void){
  TRISB = 0xFF;
  TRISA = 0x00;
  INTCONbits.INT0IE = 1;
  INTCONbits.GIE = 1;
  while(1){}
}
OP #1202761
Lesenswert?

Der Timer0 Interrupt funktioniert wunderbar, aber was hat der mit den 
Interrupteingängen INT0-INT2 zu tun?

Aber es ist schon verwunderlich, wenn ich in dem geposteten Code überall 
INT0 auf TMR0 änder, wird der Interrupt korrekt ausgelöst... warum 
funktioniert das mit INT0 nicht?

Mfg.
OP #1202892
Lesenswert?

Das PIC Datenblatt kenn ich zur genüge.
Ich weiß auch, dass der Interrupt auf ASM genau so perfekt funktioniert:

HighInt: //0x08
  bcf   INTCON,INT0IF
  bsf  PORTA,0
  sleep
  retfie  FAST
Main: //0x00
  clrf  TRISA
  clrf  PORTA
  setf  TRISB
  bsf  INTCON,INT0IE
  bsf  INTCON,GIE
  END



Auf C funktioniert er analog immer noch nicht. Aktueller Stand:

void high_isr(void);

#pragma code high_vector=0x08
void interrupt_at_high_vector(void){
    _asm goto high_isr _endasm
}

#pragma code

#pragma interrupt high_isr
void high_isr (void){
  if(INTCONbits.INT0IF){
    LATAbits.LATA0 = 1;
    INTCONbits.INT0IF = 0;
    Sleep();
  }
}

void main(void){
  TRISB = 0xFF;
  TRISA = 0x00;
  LATA = 0x00;

  INTCONbits.INT0IE = 1;
  INTCONbits.GIE = 1;
  INTCON2bits.INTEDG0 = 1;
  while(1);
}
OP #1202968
Lesenswert?

Jetzt schon. ASM geht, C nicht. Warum?

  ORG  0x000000
  goto  Main
  ORG  0x000008
  bra    HighInt

HighInt:
  bcf   INTCON,INT0IF
  bsf    PORTA,0
  sleep
Main:
  clrf  TRISA
  clrf  PORTA
  setf  TRISB
  bsf    INTCON,INT0IE
  bsf    INTCON,GIE
  END




void high_isr(void);

#pragma code high_vector=0x08
void interrupt_at_high_vector(void){
    _asm goto high_isr _endasm
}

#pragma code

#pragma interrupt high_isr
void high_isr (void){
  INTCONbits.INT0IF = 0;
  PORTAbits.RA0 = 1;
  Sleep();
}

void main(void){
  TRISA = 0x00;
  PORTA = 0x00;
  TRISB = 0xFF;
  INTCONbits.INT0IE = 1;
  INTCONbits.GIE = 1;
}
#1202996
Lesenswert?

Kannst Du in C denn überhaupt RA0 setzen?

Hast Du mal den Assemblercode angeschaut, den der C-Compiler generiert?

Und (liegt wohl nicht daran, aber man weiss ja nie):
Bei den PIC18 gibt es für die Ausgabe die LAT-Register, während die 
PORT-Register für die Eingabe verwendet werden.

Wie generierst Du den Interrupt auf INT0?

Kannst Du mal mit dem Simulator prüfen, was da genau abläuft?
Gast #1203085
Lesenswert?

Assembler:
bcf   INTCON,INT0IF  //Im Befehl  wird das Flag gleich gelöscht.

C:

  if(INTCONbits.INT0IF) // Das Flag wird abgefragt und Interrupt
//wird nur bearbeitet wenn das Flag gesetzt ist.

Ein anderes Flag muss abgefragt werden...
OP #1203140
Lesenswert?

Severino R. wrote:
> Kannst Du in C denn überhaupt RA0 setzen?
>
> Hast Du mal den Assemblercode angeschaut, den der C-Compiler generiert?
>
> Und (liegt wohl nicht daran, aber man weiss ja nie):
> Bei den PIC18 gibt es für die Ausgabe die LAT-Register, während die
> PORT-Register für die Eingabe verwendet werden.
>
> Wie generierst Du den Interrupt auf INT0?
>
> Kannst Du mal mit dem Simulator prüfen, was da genau abläuft?

Ich geh davon aus, dass es gehen sollte. Habs allerdings immer mit LATA0 
gemacht. Habe RA0 nur jetzt im letzten versuch probiert.

Öhm ja, aber der macht ja aus ner Fliege nen Elefanten, da blick ich 
nicht mehr durch.

Der Interrupt auf INT0 wir generiert dadurch, dass ich irgendwann nach 
Lust und Laune den Pin über 1kOhm auf +5V setz.

Simulator? Kenne nur den MPLAB SIM Debugger und der springt irgendwie 
nicht auf Interrupts an. Auch nicht in der real funktionierenden ASM 
Version.



skorpionx wrote:
> Assembler:
> bcf   INTCON,INT0IF  //Im Befehl  wird das Flag gleich gelöscht.
>
> C:
>
>   if(INTCONbits.INT0IF) // Das Flag wird abgefragt und Interrupt
> //wird nur bearbeitet wenn das Flag gesetzt ist.
>
> Ein anderes Flag muss abgefragt werden...

Ich bin nicht in der Stimmung für Ratespielchen.
Welches denn sonst, wenn nicht das, das gesetzt wird, wenn der Interrupt 
ausgelöst wird?
Wenn du mir nicht helfen willst, dann schreib auch nichts.



Adam Home wrote:
> Christopher L. wrote:
>> Jetzt schon. ASM geht, C nicht. Warum?
>> void high_isr (void){
>>   INTCONbits.INT0IF = 0;
>>   PORTAbits.RA0 = 1;
>>   Sleep();
>> }
>
> Die Ausgänge werden mit LATA gesetzt, in deinem Beispiel
> LATAbits.LATA0 = 0.
>
> Mit PORTA werden die Eingänge eingelesen.

Jap, wie oben schon geschrieben. In ASM benutz ich meist PORTx 
(funktioniert auch wunderbar) in C immer LATx (keine Ahnung, hab ich mir 
so angewöhnt).

------------------

Ich verstehs auch generell nicht. Ein Interrupt von Timer0 z.B. 
funktioniert wunderbar wenn ich in genau dem gleichen C-Code überall 
INT0Ix auf TMR0Ix ändere (und den Timer starte).
Warum gehn nur die INTx Eingänge nicht... ?

Mfg.
#1203189
Lesenswert?

Christopher L. wrote:
> Severino R. wrote:
>> Kannst Du in C denn überhaupt RA0 setzen?
>>
>> Hast Du mal den Assemblercode angeschaut, den der C-Compiler generiert?
>>
>> Und (liegt wohl nicht daran, aber man weiss ja nie):
>> Bei den PIC18 gibt es für die Ausgabe die LAT-Register, während die
>> PORT-Register für die Eingabe verwendet werden.
>>
>> Wie generierst Du den Interrupt auf INT0?
>>
>> Kannst Du mal mit dem Simulator prüfen, was da genau abläuft?
>
> Ich geh davon aus, dass es gehen sollte. Habs allerdings immer mit LATA0
> gemacht. Habe RA0 nur jetzt im letzten versuch probiert.

Ich meinte damit: Konntest Du Bit 0 von Port A setzen, so dass Du am Pin 
des Controllers ein logisch 1 Signal messen konntest? Also hat das 
Setzen eines Pins funktioniert? Dies im Hauptprogramm, nicht in der ISR.


> Öhm ja, aber der macht ja aus ner Fliege nen Elefanten, da blick ich
> nicht mehr durch.

Mag schon sein. Weisst Du noch, wie man die .ASM Datei anschauen kann? 
Oder wie man die .LST Datei erzeugt?


> Der Interrupt auf INT0 wir generiert dadurch, dass ich irgendwann nach
> Lust und Laune den Pin über 1kOhm auf +5V setz.

Und im Ruhezustand hast Du einen Pulldown?


> Simulator? Kenne nur den MPLAB SIM Debugger und der springt irgendwie
> nicht auf Interrupts an. Auch nicht in der real funktionierenden ASM
> Version.

Ich meinte genau den. Der hält sehr wohl bei Interrupts an (jedenfalls 
bei mir).


> Ich verstehs auch generell nicht. Ein Interrupt von Timer0 z.B.
> funktioniert wunderbar wenn ich in genau dem gleichen C-Code überall
> INT0Ix auf TMR0Ix ändere (und den Timer starte).
> Warum gehn nur die INTx Eingänge nicht... ?

Wie stellst Du fest, dass der Interrupt bei Timer funktioniert?

Vielleicht auch mal die Frage nach den Versionen von MPLAB und C18...

Hast Du übrigens einen ICD2 oder einen PICkit2 zum Debuggen?

Noch was: Am Ende Deiner main() sollte das while(1); wieder 'rein, resp. 
in Assembler ein goto $.
OP #1203731
Lesenswert?

Adam Home wrote:
> Vielleicht hilft das weiter:
>
> http://ww1.microchip.com/downloads/en/DeviceDoc/80220j.pdf
> (Chapter 4, Interrupts)
>
> Eventuell läufst du in das dort beschriebene Problem. Ein work-around
> ist auch beschrieben.

So wie ich das verstehe, geht es da nur um ein Speicherproblem, das zu 
falschen Ergebnissen führt. Ich glaube nicht, dass ich da betroffen bin, 
weil ich ja nicht mit den Registern arbeite.


@Severino R.
Ja, das LAT-setzen funktioniert.
Pulldown habe ich an den INTx Eingängen nicht, da es in ASM auch ohne 
funktioniert. Aber hab es auch schon mit Pulldowns probiert, geht 
ebenfalls nicht.
MPLAB Version hab ich 8.2, C18 weiß ich nicht,.. die Neueste, 60 Tage 
Frist läuft noch.
Ich besitze weder ICD noch PicKit; nur nen simplen Sprut Brenner 5, der 
per ICSP brennt.

-------------------

Langsam verlier ich wirklich das Vertrauen in RB0-RB2..
Der Timer0 Interrupt geht, macht ein super Blinklicht, Die PORTB4-7 
OnChange Interrupts funktionieren ebenfalls (schalten den Timer ab).
Ich kann den Timer nur mit INT0 nicht wieder anschalten... ich verstehs 
nicht.

void high_isr(void);

#pragma code high_vector=0x08
void interrupt_at_high_vector(void){
    _asm goto high_isr _endasm
}

#pragma code

#pragma interrupt high_isr
void high_isr (void){
  if(INTCONbits.TMR0IF){
    if(LATAbits.LATA0){
      LATAbits.LATA0 = 0;
    }
    else{
      LATAbits.LATA0 = 1;
    }
    INTCONbits.TMR0IF = 0;
    INTCONbits.RBIE = 1;
    INTCONbits.INT0IE = 1;
    INTCONbits.GIE = 1;
  }
  if(INTCONbits.RBIF){
    LATAbits.LATA0 = 0;
    INTCONbits.RBIF = 0;
    T0CONbits.TMR0ON = 0;
    INTCONbits.GIE = 1;
  }
  if(INTCONbits.INT0IF){
    LATAbits.LATA0 = 1;
    INTCONbits.INT0IF = 0;
    T0CONbits.TMR0ON = 1;
    INTCONbits.GIE = 1;
  }
}

void main(void){
  TRISA = 0x00;
  LATA = 0x00;
  TRISB = 0xFF;

  T0CONbits.T08BIT = 0;
  T0CONbits.T0CS = 0;
  T0CONbits.PSA = 0;
  T0CONbits.TMR0ON = 1;
  INTCONbits.TMR0IE = 1;

  INTCON2bits.RBIP = 1;
  INTCON2bits.INTEDG0 = 1;

  INTCONbits.GIE = 1;
  while(1);
}
#1203771
Lesenswert?

Christopher L. wrote:
> Adam Home wrote:
>> Vielleicht hilft das weiter:
>>
>> http://ww1.microchip.com/downloads/en/DeviceDoc/80220j.pdf
>> (Chapter 4, Interrupts)
>>
>> Eventuell läufst du in das dort beschriebene Problem. Ein work-around
>> ist auch beschrieben.
>
> So wie ich das verstehe, geht es da nur um ein Speicherproblem, das zu
> falschen Ergebnissen führt. Ich glaube nicht, dass ich da betroffen bin,
> weil ich ja nicht mit den Registern arbeite.
>

Probier's aus! Ich hatte auf einem 18F4455 (mit gleichem Errata) ein 
ähnliches Problem. Einer der Capture Interrrupts hat nicht funktioniert. 
Mit dem work-around (high interrupt Routine als "low" definieren) keine 
Probleme mehr.
Der Fehler ist abhängig davon wann der Interrupt ausgeführt wird ("...If 
an interrupt occurs during a two-cycle instruction
that modifies the STATUS, BSR or WREG register..."), was durchaus 
erklären kann warum der Timer Interrupt funktioniert, PortB aber nicht, 
bzw, warum in ASM alles kein Problem ist.
OP #1203781
Lesenswert?

Ok, eigentlich ist es ja nichts weiter, als statt interrupt interruptlow 
zu benutzen.. und jetzt errate das Ergebnis ;)

/...
#pragma interruptlow high_isr
void high_isr (void){
  if(INTCONbits.TMR0IF){
    if(LATAbits.LATA0){
      LATAbits.LATA0 = 0;
/...

Timer0 Interrupt: Bingo
PortB 4-7Change Interrupt: Bingo
PortB INT0: hehe vergiss es.. (gleiches gilt auch für INT1 und INT2)
#1203827
Lesenswert?

Christopher L. wrote:
> PortB INT0: hehe vergiss es.. (gleiches gilt auch für INT1 und INT2)

Wäre ja auch zu schön gewesen...Hmmm,..wenn RB4-7 funktionieren und 
RB0-3 nicht, dann deutet einiges darauf hin das PortB in den ConfigBits 
nicht als digital input definiert ist: "..By programming the 
Configuration bit,
PBADEN (CONFIG3H<1>), RB4:RB0 will alternatively be configured as 
digital inputs on POR."

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren