Forum: Mikrocontroller und Digitale Elektronik PIC 18F2550 Interrupts in C18


von Andy L. (nemai)


Lesenswert?

Hallo,

kann mir jemand sagen, wie ich auf nem PIC 18F2550 Interrupts in C in 
C18 ans Laufen bringen kann? Das Hauptproblem ist der Sprung in die 
Interruptroutine.. wie geb ich das in C18 an?

Mfg.

von skorpionx (Gast)


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)
 {
……..

}

von Andy L. (nemai)


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;
  }
}

von morph1 (Gast)


Lesenswert?

bitte lies das handbuch zum c18, da steht das drinnen

von Andy L. (nemai)


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){}
}

von skorpionx (Gast)


Lesenswert?

Den Timer muss du auch einschalten.
  T0CONbits.TMR0ON = 1 ;    //Timer ON

Auch noch das:

  T0CONbits.T0CS = 0;     //PIC-Takt als Quelle für Timer0

von skorpionx (Gast)


Lesenswert?


von Andy L. (nemai)


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.

von skorpionx (Gast)


Angehängte Dateien:

Lesenswert?

Lese das...

von Andy L. (nemai)


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);
}

von Severino R. (severino)


Lesenswert?

Die Version in ASM ist aber nicht dasselbe wie die Version in C, oder?

von Andy L. (nemai)


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;
}

von Severino R. (severino)


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?

von skorpionx (Gast)


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...

von Adam @. (bookwood77)


Lesenswert?

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.

von Andy L. (nemai)


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.

von Adam @. (bookwood77)


Lesenswert?

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.

von Severino R. (severino)


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 $.

von Andy L. (nemai)


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);
}

von Adam @. (bookwood77)


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.

von Andy L. (nemai)


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)

von Adam @. (bookwood77)


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."

von Andy L. (nemai)


Lesenswert?

ADAM ICH LIEBE DICH! ^^

Nein im Ernst, sie waren tatsächlich als Analogeingänge konfiguriert, 
dummer Fehler, der ein selber und paar andere einige Nerven kostet.

Es funktioniert perfekt.

Vielen Dank ;)

-Case closed-

von Oli M. (h2obrain)


Lesenswert?

woah! das ist ja voll 2.0!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.