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.
#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) { …….. }
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; } }
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){} }
Den Timer muss du auch einschalten. T0CONbits.TMR0ON = 1 ; //Timer ON Auch noch das: T0CONbits.T0CS = 0; //PIC-Takt als Quelle für Timer0
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.
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); }
Die Version in ASM ist aber nicht dasselbe wie die Version in C, oder?
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; }
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?
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...
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.
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.
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.
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 $.
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); }
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.
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)
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."
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-
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.