Hallo, ich (Anfänger) bin beim Programmieren an einen Punkt gekommen, wo ich feststellen muss, dass meine Interrupt-Routine (TMR0 Interrupt) nicht mehr ordnungsgemäß funktioniert. Wenn ich einen gewissen stupiden Schritt (irgendwelche flags setzen um LED zum Leuchten zu bekommen) in einem Unterprogramm rauslasse funktioniert wieder alles. Vorab ich habe und muss alle Programmteile im Interrupt laufen lassen. Gibt es eine bestimmte Grenze wo in der Routine so viele Befehle drinnen sind, dass der Interrupt nicht mehr richtig funktionieren kann? So was ähnliches wie einen "worst-case" ? Danke im Voraus Gruß Wolf
Es würde helfen, wenn Du den Programmcode posten würdest. Idealerweise auf das Minimum abgespeckt, um das Problem aufzuzeigen, und in beiden Versionen (also die die nicht funktioniert und die mit dem Unterprogramm, die funktioniert). Hast Du das Ganze in Hardware getestet und/oder mit dem Simulator? Sind die Banks korrekt ausgewählt? Ist die Interrupt-Routine so lang, dass sie noch immer läuft wenn der nächste TMR0 Interrupt kommt?
Das kannst du dir doch selber ausrechnen, bzw. abzählen. Die Timer werden doch mit dem selben Takt getaktet wie die Befehle abgearbeitet werden. Wenn also der Prescaler des Timer0 auf 1:1 steht, läuft der Timer0 nach genau 256 Befehlen über und erzeugt einen Interrupt. Bei Prescaler 2:1 entsprechend 512 Befehle usw. Wenn deine Interruptroutine mehr wie 256 (512, ...) Befehle abarbeiten muss dann trifft ein neuer Interupt ein, bevor der alte beendet wurde. Du solltest die ISR so kurz wie möglich machen und den Rest in der Hauptroutine. Im Simulator siehst du übrigens wunderbar wie viele Befehle zwischen zwei Haltepunkten abgearbeitet werden. Sven
Und dann noch die Zeit für Interruptaufruf, reti und evtl. Sicherungen diverser Register. Kenne aber den PIC nicht, um zu wissen, wieviel Takte das konkret kostet. Eine ISR sollte jedenfalls nicht in die Nähe von 100% Prozessorzeit kommen :-) Auch möglich sind evtl. stackprobleme.
Danke für die schnelle Antwort! @Severino R. wenn der TMR0 Interrupt kommt schalte ich ihn wieder aus, also kann kein anderer Interrupt in die Quere kommen, banks etc. sind in der Initialisierung alle richtig ausgewählt. Aber das mit dem Simulator klingt interessant, aber da habe ich noch nicht so die große Ahnung, ich habe schon versucht damit zu arbeiten aber irgendwie habe ich es noch nicht geschafft mit Interrupts zu simulieren, da muss doch irgendwie der Interrupt simuliert ausgeführt werden, kann man das irgendwo einstellen ? ich arbeite momentan mit dem MPLAB IDE v8.10. Einfacher wäre es richtig debuggen zu können aber leider geht das wohl mit diesem PIC nicht, nur simulieren !? Gruß
Wolf Retlaw wrote: > banks etc. sind in der Initialisierung alle richtig ausgewählt. Und später beim Ansprechen von Registern? > Aber das mit dem Simulator klingt interessant, aber da habe ich noch > nicht so die große Ahnung, ich habe schon versucht damit zu arbeiten > aber irgendwie habe ich es noch nicht geschafft mit Interrupts zu > simulieren, da muss doch irgendwie der Interrupt simuliert ausgeführt > werden, kann man das irgendwo einstellen ? ich arbeite momentan mit dem > MPLAB IDE v8.10. Setze einen Breakpoint am Anfang Deiner ISR, und Du wirst sehen, dass das Programm dort stoppt!!! > Einfacher wäre es richtig debuggen zu können aber leider geht das wohl > mit diesem PIC nicht, nur simulieren !? Wenn das Problem beim Simulator nicht auftritt, wird Debuggen mit dem ICD2 (das meintest Du doch, oder?) erst interessant. Wenn das Problem beim Simulator auch auftritt, solltest Du mit dessen Hilfe den Fehler suchen. Im Simulator läuft der Timer synchron zu den Einzelschritten; beim ICD2 läuft der Timer halt weiter, wenn das Programm angehalten wird. Es gibt einen speziellen PIC12F683, der PIC12F683-ICD. Der hat zusätzliche Pins, um mit den ICD2-Signalen die knappen Pins nicht zu blockieren. Der PIC12F683-ICD ist montiert auf einem kleinen Print "Header-Print" von Microchip erhältlich: Artikel AC162058. Auf dem Header-Print befindet sich auch der RJ-12 Anschluss, und der Print hat auf der Unterseite Stifte im DIL8-Layout, um ihn an Stelle des PIC12F683 in die Schaltung zu stecken.
@Severino R. wow danke dir, und Ja ich habe ICD2, wusste gar nicht dass es einen speziellen PIC gibt! der wird aber bestimmt einiges kosten g Habe übrigens meinen Fehler gefunden, zuviele Calls haben ein Problem im Stack ausgeführt schäm Aber der Thread hat trotzdem einige neue Informationen locken können :-) Gruß Wolf
Mit einem ICD2 kannst du auch direkt im PIC debuggen. A ber der Simulator ist für solche kleineren Probleme ganz gut. Du gehst halt einfach Schritt für Schritt durch. Wenn der Timer einen Interupt auslößt, springt das Programm automatisch auf Adresse 4 und arbeitet dann weiter. Wenn du nicht 256 mal klicken willst, kannst du auch das Timer0 Register einfach mit z.Bsp 255 beschreiben und dann weiter klicken. Probier einfach ein bisschen rum. Gerade als Anfänger kann man da wunderschön die meisten Sachen simmulieren. Du hast jedes Register im Blick und kannst eigene Werte eingeben. Mit dem Stimulus Controller kannst du auch externe Ereignisse simulieren z.Bsp. das an RB0 eine L/H-Flanke auftritt oder das Über die Serielle ein bestimmtes Bitmuster eingelesen wird. Alles noch ganz ohne Hardware. Also wenn ich das richtig interpretiere benötigt der PIC nach dem Interuptereignis 5 Befehlszyclen bis er den Befehl auf Adresse 4 abgearbeitet hat, genauso dann wieder bei einem RETFIE. Dann kommen natürlich noch bis zu 10 Befehlen wo man die Register rettet und das Interupt-Ereignis abfragt (die 16F PICs kennen nur eine Interuptadresse, deshalb muss man als erstes feststellen welcher Interupt aufgetreten ist). Am Ende wieder das selbe. Da können schon mal 20-30 Befehle drauf gehen, bevor du in deiner Routine bist. Ein Interupt kommt dir innerhalb der ISR normalerweise sowiso nicht in die Quere, da der PIC das GIE-Flag deaktiviert sobald er in die ISR springt. Damit sind alle Interupts abgeschaltet, solange die ISR läuft. Allerdings können trozdem Ereignisse auftreten, welche das entsprechende Bit wieder enabeln. Sobald die ISR verlassen wird und es trat zwischendurch ein Ereignis auf springt der PIC sofort wieder in ISR und arbeitet den Interupt ab. Also angenommen deine ISR benötig 1000 Befehle, dann würde der Timer0 mit Prescaler 1:1 in dieser Zeit 3x das T0IF setzen. Damit gehen dir die Interupts verloren und dein Programm arbeitet nicht korrekt. Stell dein Prog doch mal hier ein, dann können wir mal drüber schauen. Eventuell gest du die Sache ja falsch an. Gruß Sven
Wolf Retlaw wrote: > @Severino R. wow danke dir, wusste gar nicht dass es einen speziellen > PIC gibt! der wird aber bestimmt einiges kosten *g* Wenn das Ding hilft, Zeit zu sparen... Kostenlos gibt es das Teil nicht, aber es ist ja ein Entwicklungswerkzeug, das man dann nicht in der fertigen Schaltung belässt, sondern wieder benutzen kann. Bei Farnell EUR 18.00 > Habe übrigens meinen Fehler gefunden, zuviele Calls haben ein Problem im > Stack ausgeführt schäm Wow! mehr als sieben CALLs in einer ISR!!!
So schön wie das ist mit den Unterprogrammen, aber bei einer Stacktiefe von 8 muss man schon aufpassen und es nicht übertreiben mit den Calls. Ein Call benötigt auch zwei Befehlszyklen und das Return dann auch wieder. Für ein Unterprogramm mit 2-3 Befehlen also unnötig. Dann doch lieber wieder copy and paste... Sven
Sven Stefan wrote:
> Dann doch lieber wieder copy and paste...
Oder ein MACRO.
Ja, du definierst ein paar Zeilen Code als Macro und rufst dann im Programm an der Stelle das Macro auf, wo du den definierten Programmcode einfügen willst. Ist eigentlich nur ein optischer Trick um den Quellcode übersichtlicher zu gestalten. Der Compiler fügt beim Übersetzen genau den Quellcode an der Stelle ein wo du das Macro aufrufst. Du sparst damit also keinen Speicherplatz. Bsp:
1 | ;Macro definieren |
2 | Bank0 macro |
3 | bcf STATUS,RP0 ;Bank 0 |
4 | bcf STATUS,RP1 |
5 | endm |
6 | |
7 | ;Macro aufrufen |
8 | Bank0 |
An der Stelle wo du das Macro aufrufst werden vom Compiler beim übersetzen die beiden Befehlszeilen eingefügt. Im Quellcode steht aber nur Bank0 als Befehl. Sven
@ Wolf: Falls Du MACROs nicht kennst: Du kannst auch "Argumente" verwenden, also eine Art Parameter, welche jedoch (anders als bei z.B. Funktionsaufrufen in Hochsprachen) zur Assemblierzeit (und nicht erst zur Laufzeit) ersetzt werden. Deshalb müssen die Argumente Konstanten sein. Näheres im Manual von MPASM sowie z.B.: http://www.fernando-heitor.de/component/option,com_smf/Itemid,121/topic,1245.0/
Ok, vielen Dank an euch! Heute habe ich wieder einiges gelernt :-)
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.