Hallo ich habe ein Programm geschrieben, in dem ein LED blinken lassen , und der Timer0 zählt die Anzahl von Bliken, wenn der Anzahl der Blinken den wert 6 Erreicht löst diese Timer ein Interrupt diese Interrupt schaltet ein andere LED ein. Wenn ich mein Pic mit der Testplatine anschließe blinkt nur der erste LED ständig und es wird keine Interupt glöst? kann mir Jemand helfen! #include <P16F88.inc> LED equ 0 LED1 equ 1 Wait1 equ 0x25 Wait2 equ 0x26 W_TEMP equ 0x30 STATUS_TEMP equ 0x31 PCLATH_TEMP equ 0x32 org 0x0000 ;bsf STATUS, RP0 ; bcf OSCTUNE, 0x00 Oscillator Initialisierung ;__CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_OFF & _PWRTE_ON & _WDT_OFF & _EXTRC_IO ;__CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF __CONFIG _CONFIG1, _PWRTE_ON & _WDT_OFF goto MainInit Interrupt MOVWF W_TEMP ;Copy W to TEMP register SWAPF STATUS, W ;Swap status to be saved into W CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0 MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register MOVF PCLATH, W ;Only required if using page 1 MOVWF PCLATH_TEMP ;Save PCLATH into W CLRF PCLATH ;Page zero, regardless of current page ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bcf STATUS, RP0 bsf PORTA, LED1 ; LED Leuchten ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVF PCLATH_TEMP, W ;Restore PCLATH MOVWF PCLATH ;Move W into PCLATH SWAPF STATUS_TEMP, W ;Swap STATUS_TEMP register into W ;(sets bank to original state) MOVWF STATUS ;Move W into STATUS register SWAPF W_TEMP, F ;Swap W_TEMP SWAPF W_TEMP, W ;Swap W_TEMP into W bcf STATUS, RP0 bcf INTCON, TMR0IF ; Interrupt-Flag löschen bsf INTCON, GIE ; enable Interrupt (macht RETFIE aber auch allein) retfie MainInit bsf STATUS, RP0 movlw 0x00 movwf ANSEL movlw B'10100000' ; Timer0 für Pin RA4 wählen movwf OPTION_REG bsf INTCON, TMR0IE ; Timer0 interrupt erlauben bsf INTCON, GIE ;Interrpt erlauben bcf TRISA, LED bcf STATUS, RP0 ;Bank 0 movlw d'250' ; TImer ab 250 zählt movwf TMR0 bsf PORTA, LED ;LED leuchtet call Warten ;zum Unterprogramm; bcf STATUS, RP0 bcf PORTA, LED ;LED leuchtet nicht call Warten ;zum Unterprogramm; goto MainInit Warten ;Wartezeit initialisierung movlw 0x25 movwf Wait2 loop2 movlw 0x25 ;Wartezeit initialisierung movwf Wait1 loop decfsz Wait1,1 goto loop decfsz Wait2,1 goto loop2 retlw .0 end
Mal ins blaue: Deine Interruptroutine fängt nicht auf der Adresse 0x04 an. Da fehlt ein org 0x04 vor der Interruptroutine. Sven
Weiterer Fehler, bsf INTCON, GIE ; enable Interrupt (macht RETFIE aber auch Innerhalb dem Interrupt erlaubst du so nested Interrupts, hast aber keine SW, welche nested Interrupts bedienen kann, nichts fuer Anfaenger. Weiters ist die Config auskommentiert, also koennte dir auch der WDT reinpfuschen. Andere sache, schau nochmals im Datasheet nach, wie man den Prescaler auf WDT rumaendert, denn sonst kann ein Reset daraus resultieren, solltest du das falsch machen.
Weiterer Fehler, du setzt für LED1 nicht das TRIS als Ausgang, also wird dir LED1 nicht funktionieren. Zudem invertierst du es nicht, also schaltest du es nur ein. Ist das mit dem WDT geklärt ?
Hallo, ich habe mein Programm korrigiert, aber es leuchtet die zweite LED immer noch nicht , ich habe der Register OPTION_REG geändert in dem der Timer mit interne Takt arbeitet, das hat funktioniert, aber mit externe Takt (erste LED)funktioniert es nicht, bitte kann mir jemand helfen, das wäre nett #include <P16F88.inc> LED equ 0 LED1 equ 1 Wait1 equ 0x25 Wait2 equ 0x26 W_TEMP equ 0x70 STATUS_TEMP equ 0x31 PCLATH_TEMP equ 0x72 org 0x0000 __CONFIG _CONFIG1, _PWRTE_ON & _WDT_OFF goto MainInit Interrupt org 0x04 bsf STATUS, RP0 bcf INTCON, GIE bcf INTCON, TMR0IE bcf INTCON, TMR0IF MOVWF W_TEMP ;Copy W to TEMP register SWAPF STATUS, W ;Swap status to be saved into W CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0 MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register MOVF PCLATH, W ;Only required if using page 1 MOVWF PCLATH_TEMP ;Save PCLATH into W CLRF PCLATH ;Page zero, regardless of current page ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bsf STATUS, RP0 bcf TRISA, LED1 bcf STATUS, RP0 bsf PORTA, LED1 ; LED Leuchten call Warten bcf PORTA, LED1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVF PCLATH_TEMP, W ;Restore PCLATH MOVWF PCLATH ;Move W into PCLATH SWAPF STATUS_TEMP, W ;Swap STATUS_TEMP register into W ;(sets bank to original state) MOVWF STATUS ;Move W into STATUS register SWAPF W_TEMP, F ;Swap W_TEMP SWAPF W_TEMP, W ;Swap W_TEMP into W bcf STATUS, RP0 bcf INTCON, TMR0IF ; Interrupt-Flag löschen movlw 0xFA ; TImer ab 250 zählt movwf TMR0 retfie MainInit bsf STATUS, RP0 movlw 0x00 movwf ANSEL movlw B'11100000' ; Timer0 für Pin RA4 wählen movwf OPTION_REG bcf STATUS, RP0 ;Bank 0 movlw 0xFA ; TImer ab 250 zählt movwf TMR0 bsf STATUS, RP0 bcf TRISA, LED bcf STATUS, RP0 ;Bank 0 bsf PORTA, LED ;LED leuchtet call Warten ;zum Unterprogramm; bsf STATUS, RP0 bcf STATUS, RP0 bcf PORTA, LED ;LED leuchtet nicht call Warten ;zum Unterprogramm; bsf INTCON, TMR0IE ; Timer0 interrupt erlauben bsf INTCON, GIE ;Interrpt erlauben goto MainInit Warten ;Wartezeit initialisierung movlw 0x25 movwf Wait2 loop2 movlw 0x25 ;Wartezeit initialisierung movwf Wait1 loop decfsz Wait1,1 goto loop decfsz Wait2,1 goto loop2 retlw .0 end
org 0x04 Interrupt ; das kommt nach dem ORG, sonst ist der Label falsch MOVWF W_TEMP ; save W SWAPF STATUS, W ; save STATUS MOVWF STATUS_TEMP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; int_tmr0 btfsc INTCON, TMR0IE ; check if tmr0 is enabled btfsc INTCON, TMR0IF ; check if tmr0 is triggered goto int_done ; goto to next interrupt check goto $+1 ; time adjust for prescaler movlw -244 ; -256+(12/PRESCALER) ; TImer ab 250 movwf TMR0 btfss PORTA,LED1 bsf PORTA,LED1 btfsc PORTA,LED1 bcf PORTA,LED1 bcf INTCON, TMR0IF ; Interrupt-Flag löschen ; !!! call Warten ; macht man nicht in einer Interrupt int_done ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SWAPF STATUS_TEMP, W MOVWF STATUS ; restore W and STATUS SWAPF W_TEMP, F SWAPF W_TEMP, W retfie MainInit movlw ~3 movwf PORTA bsf STATUS, RP0 clrf ANSEL movwf TRISA movlw B'11100000' ; Timer0 für Pin RA4 wählen movwf OPTION_REG bcf STATUS, RP0 ;Bank 0 movlw -250 ; TImer ab 250 zählt movwf TMR0 bsf INTCON, TMR0IE ; Timer0 interrupt erlauben bsf INTCON, GIE ;Interrpt erlauben Main call Warten bcf PORTA, LED call Warten ;zum Unterprogramm; bsf PORTA, LED call Warten ;zum Unterprogramm; goto Main Warten ;Wartezeit initialisierung movlw 0x25 movwf Wait2 loop2 movlw 0x25 ;Wartezeit initialisierung movwf Wait1 loop decfsz Wait1,1 goto loop decfsz Wait2,1 goto loop2 retlw .0 end
vielen Dank chris, ich habe dein Programm auf meinen Pic gebrennt, aber es hat nicht funktioniert, dei LED blinkt 161 mal dann blikt er nicht mehr (bleibt am leuchten) und die LED1 blinkt nicht.
Danke Chris das ist nochmal den Code, #include <P16F88.inc> LED equ 0 LED1 equ 1 Wait1 equ 0x25 Wait2 equ 0x26 W_TEMP equ 0x70 STATUS_TEMP equ 0x31 PCLATH_TEMP equ 0x72 org 0x0000 __CONFIG _CONFIG1, _PWRTE_ON & _WDT_OFF goto MainInit org 0x04 Interrupt ; das kommt nach dem ORG, sonst ist der Label falsch MOVWF W_TEMP ; save W SWAPF STATUS, W ; save STATUS MOVWF STATUS_TEMP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; int_tmr0 btfsc INTCON, TMR0IE ; check if tmr0 is enabled btfsc INTCON, TMR0IF ; check if tmr0 is triggered goto int_done ; goto to next interrupt check goto $+1 ; time adjust for prescaler movlw -250 ; -256+(12/PRESCALER) ; TImer ab 250 movwf TMR0 btfss PORTA,LED1 bsf PORTA,LED1 btfsc PORTA,LED1 bcf PORTA,LED1 bcf INTCON, TMR0IF ; Interrupt-Flag löschen ; !!! call Warten ; macht man nicht in einer Interrupt int_done ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SWAPF STATUS_TEMP, W MOVWF STATUS ; restore W and STATUS SWAPF W_TEMP, F SWAPF W_TEMP, W retfie MainInit movlw ~3 movwf PORTA bsf STATUS, RP0 clrf ANSEL movwf TRISA movlw B'11100000' ; Timer0 für Pin RA4 wählen movwf OPTION_REG bcf STATUS, RP0 ;Bank 0 movlw -250 ; TImer ab 250 zählt movwf TMR0 bsf INTCON, TMR0IE ; Timer0 interrupt erlauben bsf INTCON, GIE ;Interrpt erlauben Main call Warten bcf PORTA, LED call Warten ;zum Unterprogramm; bsf PORTA, LED call Warten ;zum Unterprogramm; goto Main Warten ;Wartezeit initialisierung movlw 0x25 movwf Wait2 loop2 movlw 0x25 ;Wartezeit initialisierung movwf Wait1 loop decfsz Wait1,1 goto loop decfsz Wait2,1 goto loop2 retlw .0 end
Übrigens ich habe mit movlw -244 ; -256+(12/PRESCALER) ; TImer ab 250 movwf TMR0 und mit movlw -250 ; -256+(12/PRESCALER) ; TImer ab 250 movwf TMR0 versucht aber es klapptnicht Grüße
das -244, sprich 12 ist als Korrektur für die Zeit da, welche bereits für das ISR entry sowie context saving verbraucht wurden, damit der Timer wieder in 500 uS nach dem letzten mal triggert, denn sonst sind es 250+die Zeit im ISR, also ein fehler von 2.4%, der aber kumulativ ist. Das call Warten vor dem goto Main ist zu viel, das braucht es nicht. Dachte vielleicht, daß du ev. ein - vor den Timerwerten vergessen hast, was aber nicht der Fall ist. füge ev. noch das rein, ev. ist dein Radix hex LIST P=16F88, R=DEC, n=61, c=78 errorlevel 0,-305 sowie im ISR, ein movlw 1<<LED1 xorwf PORTA anstatt der vier Zeilen die LED1 testen und setzen. Was ich gerade gesehen habe, im ISR entry fehlt for int_tmr0 ein clrf STATUS, dadurch verändert sich auch das Timing, und du musst dann das folgende GOTO $+1 durch ein NOP ersetzen.
Danke, aber ich habe das nicht verstanden. LIST P=16F88, R=DEC, n=61, c=78 errorlevel 0,-305
ich habe dein Code geschrieben aber das klappt nicht. der erste LED blinkt mehr als 6 mal dann irgendwann leuchtet weiter, und LED 2 blinkt nicht. Grüße
Dann test mal das, ohne Interrupts, um den Fehler einzugrenzen. port_a equ 20 ; hidden port register kommentiere das folgende raus, und fergiss das radix dec nicht. ;bsf INTCON, TMR0IE ; Timer0 interrupt erlauben ;bsf INTCON, GIE ;Interrpt erlauben Main veränderst du folgendermaßen: Main call Warten movlw 1<<LED xorwf PORTA ; toggle led btfss INTCON, TMR0IF ; if !tmr0 expired goto Main movlw 1<<LED1 xorwf PORTA ; toggle LED1 bcf INTCON, TMR0IF ; clear tmr0 overflow goto Main Ergebniss sollte sein, LED blinkt, und LED1 sollte langsamer blinken, eigentlich wenn ich richtig geschätzt habe, LED mit 12ms ein/aus Zyklus und LED1 mit 500ms ein/aus zyklus, +-12ms bei LED1. Sollte das klappen, weiss man dann, der Fehler liegt im Interrupt code, sonst ist es irgendetwas anderes. Hast du eigntlich den clrf STATUS vor int_tmr0 eingefügt ?, sonst könnte das das Problem darstellen.
Hallo schris, ich war die ganze Zeit am probieren, diese Code funktioniert ganz gut, aber ohne Interrupt, #include <P16F88.inc> LED equ 0 LED1 equ 1 Wait1 equ 0x25 Wait2 equ 0x26 port_a equ 20 W_TEMP equ 0x70 STATUS_TEMP equ 0x31 PCLATH_TEMP equ 0x72 org 0x0000 LIST P=16F88, R=DEC, n=61, c=78 errorlevel 0,-305 __CONFIG _CONFIG1, _PWRTE_ON & _WDT_OFF goto MainInit MainInit movlw ~3 movwf PORTA bsf STATUS, RP0 clrf ANSEL movwf TRISA movlw B'11100000' ; Timer0 für Pin RA4 wählen movwf OPTION_REG bcf STATUS, RP0 ;Bank 0 Main1 movlw 0xFE ; TImer ab 250 zählt movwf TMR0 bcf INTCON, TMR0IF ; clear tmr0 overflow Main call Warten movlw 1<<LED xorwf PORTA ; toggle led btfss INTCON, TMR0IF ; if !tmr0 expired goto Main bsf PORTA, LED1 ; LED Leuchten call Warten bcf PORTA, LED1 bcf INTCON, TMR0IF ; clear tmr0 overflow goto Main1 Warten ;Wartezeit initialisierung movlw 0x25 movwf Wait2 loop2 movlw 0x25 ;Wartezeit initialisierung movwf Wait1 loop decfsz Wait1,1 goto loop decfsz Wait2,1 goto loop2 retlw .0 end Wenn ich die Interrupt code rein bringe dann blinkt der LED immer weiter und es blinkt die LED1 nicht,der Code mit Interrupt #include <P16F88.inc> LED equ 0 LED1 equ 1 Wait1 equ 0x25 Wait2 equ 0x26 port_a equ 20 W_TEMP equ 0x70 STATUS_TEMP equ 0x31 PCLATH_TEMP equ 0x72 org 0x0000 LIST P=16F88, R=DEC, n=61, c=78 errorlevel 0,-305 __CONFIG _CONFIG1, _PWRTE_ON & _WDT_OFF goto MainInit org 0x04 Interrupt bsf STATUS, RP0 bcf INTCON, GIE bcf INTCON, TMR0IE bcf INTCON, TMR0IF MOVWF W_TEMP ;Copy W to TEMP register SWAPF STATUS, W ;Swap status to be saved into W CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0 MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register MOVF PCLATH, W ;Only required if using page 1 MOVWF PCLATH_TEMP ;Save PCLATH into W CLRF PCLATH ;Page zero, regardless of current page ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bsf STATUS, RP0 bcf TRISA, LED1 bcf STATUS, RP0 bsf PORTA, LED1 ; LED Leuchten nop nop nop ;call Warten bcf PORTA, LED1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVF PCLATH_TEMP, W ;Restore PCLATH MOVWF PCLATH ;Move W into PCLATH SWAPF STATUS_TEMP, W ;Swap STATUS_TEMP register into W ;(sets bank to original state) MOVWF STATUS ;Move W into STATUS register SWAPF W_TEMP, F ;Swap W_TEMP SWAPF W_TEMP, W ;Swap W_TEMP into W bcf STATUS, RP0 bcf INTCON, TMR0IF ; Interrupt-Flag löschen movlw 0xFE ; TImer ab 250 zählt movwf TMR0 retfie MainInit movlw ~3 movwf PORTA bsf STATUS, RP0 clrf ANSEL movwf TRISA movlw B'11100000' ; Timer0 für Pin RA4 wählen movwf OPTION_REG bcf STATUS, RP0 ;Bank 0 bsf INTCON, TMR0IE ; Timer0 interrupt erlauben bsf INTCON, GIE ;Interrpt erlauben Main1 movlw 0xFE ; TImer ab 250 zählt movwf TMR0 bcf INTCON, TMR0IF ; clear tmr0 overflow Main call Warten movlw 1<<LED xorwf PORTA ; toggle led bsf PORTA, LED ; LED Leuchten call Warten bcf PORTA, LED goto Main1 Warten ;Wartezeit initialisierung movlw 0x25 movwf Wait2 loop2 movlw 0x25 ;Wartezeit initialisierung movwf Wait1 loop decfsz Wait1,1 goto loop decfsz Wait2,1 goto loop2 retlw .0 end
Kritik an Code ohne Interrupt org 0x0000 LIST P=16F88, R=DEC, n=61, c=78 da gehört ein Tab oder Leerzeichen davor. LED1 würde ich Invertieren, gleich wie LED movlw 1<<LED1 xorwf PORTA ; toggle led an stelle von bsf PORTA, LED1 ; LED Leuchten call Warten bcf PORTA, LED1 denn dann veränderst du nicht das timing von LED. Jetzt komme ich zum Code mit Interrupt Diese Zeilen sind totaler blödsinn bsf STATUS, RP0 ; Du veränderst das Statusregister im Main !!! bcf INTCON, GIE ; Das passiert automatisch bcf INTCON, TMR0IE ; wieso deaktivierst du den TMR0 Interrupt ? bcf INTCON, TMR0IF ; Das solltest du nach dem behandeln des Tmr0 int machen MOVWF W_TEMP ;Copy W to TEMP register SWAPF STATUS, W ;Swap status to be saved into W CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0 MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register Erst hier darfst du dann was verändern, da du W sowie Status des Main gespeichert hast. MOVF PCLATH, W ;Only required if using page 1 MOVWF PCLATH_TEMP ;Save PCLATH into W CLRF PCLATH ;Page zero, regardless of current page Da du keine computed Goto in deiner Interrupt Routine verwendest, sind die obigen Zeilen unnötig. Eventuell, wenn du FSR verwenden solltest, mußt du das auch sichern, aber nur als Bemerkung am Rande. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bsf STATUS, RP0 bcf TRISA, LED1 bcf STATUS, RP0 Das ist schon initialisiert, also sind die obigen Zeilen Sinnlos. hier sollte noch eine Abfrage auf tmr0if reinkommen, also btfsc INTCON, TMR0IE btfss INTCON, TMR0IF goto int_done Es kann nähmlich passieren, daß ein unerwarteter Interrupt auftritt, oder ein anderer Interrupt getriggert wird. bsf PORTA, LED1 ; LED Leuchten nop nop nop ;call Warten bcf PORTA, LED1 Die Led leuchtet für 4 uS, wäre es nicht sinnvoller, die Led einfach zu Invertieren, mit movlw 1<<LED1 xorwf PORTA Abgesehen davon, daß das Warten auskommentiert ist, ein ISR sollte nicht solange laufen. Das bcf INTCON, TMR0IF sollte hier noch reinkommen. int_done ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVF PCLATH_TEMP, W ;Restore PCLATH MOVWF PCLATH ;Move W into PCLATH SWAPF STATUS_TEMP, W ;Swap STATUS_TEMP register into W ;(sets bank to original state) MOVWF STATUS ;Move W into STATUS register SWAPF W_TEMP, F ;Swap W_TEMP SWAPF W_TEMP, W ;Swap W_TEMP into W Die obigen Befehle haben die Register für den Main Code wiederhergestellt, wieso pfuscht du dann danach noch rein, danach darf nur noch ein RETFIE kommen. !!! retfie bcf STATUS, RP0 bcf INTCON, TMR0IF ; Interrupt-Flag löschen Bei deinem Code hast du TMR0IE gelöscht, also wird kein weiterer Interrupt generiert. movlw 0xFE ; TImer ab 250 zählt movwf TMR0 Das kommt am Anfang des INT_TMR0, denn du musst auch die im Interrupt bereits verarbeiteten Befehle kompensieren, damit du ein konstanten TMR0 Interrupt hast. Du lädst den Wert mit 250 und hast einen prescaler von 2, also hast du den nächsten Interrupt in 12 Befehlen/uS. Deine Interruptroutine ist ja größer, du wirst dann nie mehr in den Main kommen. Ich dachte, du möchtest den Timer in 500uS haben, deshalb hatte ich movlw -250 ; beachte das Minus, movwf tmr0 geschrieben, sowie 12 Instruktionszyklen / prescaler abgezogen, um den Timingfehler zu kompensieren. Daraus ist dann ein -244 geworden, mit den zusätzlichen Nops, damit kein Timingfehler generiert wird, und somit der Interrupt jede 500 uS ausgelöst wird.
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.