Hallo ich nutze den ccs c Compiler v4.128 und habe für einen Zeitmesser ein gängiges Beispiel hergenommen. Das Beispiel funktioniert auch wunderbar, nur wenn ein EXT mit einem Timer0 Überlauf zusammentrifft, dann kommt es zu einem falschen Ergebnis. #int_TIMER0 void TIMER0_isr(void) { Counter0 = Counter0 + 1; } #int_EXT void EXT_isr(void) { anzahl0 = (Counter0 * 65536) + get_timer0() ; if (anzahl0 < 100000) { output_high(PIN_C0); } else { output_low(PIN_C0); } set_timer0(0); Counter0 = 0; } void main() { while(TRUE) { } } Ich weiß theoretisch, daß Interrupts nacheinander abgearbeitet werden, warum also kommt beim zeitnahen Zusammentreffen des EXT und des Timer0 Überlaufes zu einem Fehler und was kann man dagegen machen? Der Fehler sieht so aus, daß wohl der Counter nicht hochgezählt ist aber der get_timer0() noch recht niedrig ist, also übergelaufen ist. Auch ein disable_interrupts entweder im ext oder timer0 Interrupt brachte kein Ergebnis. Vielen Dank im Voraus für eure Ratschläge
pic_ler schrieb: > Der Fehler sieht so aus, daß wohl der Counter > nicht hochgezählt ist aber der get_timer0() > noch recht niedrig ist, also übergelaufen ist. Das wird wahrscheinlich daran liegen, dass der Timer überläuft, während der PIC die EXT_isr(void) abarbeitet. Der Timer geht automatisch wieder auf 0, der PIC kann Counter0 erst erhöhen, sobald er die EXT_isr(void) fertig hat. Nam könnte es lösen, wenn man nicht mit dem EXT Interrupt, sondern mit dem Input Capture arbeitet. Das funktioniert so: Bei einer Fallenden, Seigenden, oder bei jeder 2., 4. Oder 16. steigenden Flanke (einstellbar) am CCP Pin wird ein Interrupt ausgelöst und gleichzeitig (per Hardware) der Wert von Timer1 ins CCPRx kopiert. Du hast in diesem Register also den Timerwert exakt zum Zeitpunkt der Flanke am CCP Pin stehen. Du musst jetzt dafür sorgen, dass, wenn die Interrupts zur gleichen Zeit auftreten, die ISR des CCP-Interrupt vor der des Timer-Interrupt ausgeführt wird.
:
Bearbeitet durch User
Hallo Max danke für Deine Antwort, ich bin Anfänger in der PIC-Programmierung und mit CCP habe ich noch garnichts gemacht. Deine Erklärung mit dem Überlauf klingt verständlich. Wenn ich das also richtig verstehe ist das so, daß der Timer unabhängig läuft und einen Überlauf verursachen kann auch wenn ich z. B. gerade in die EXT-Routine einsteige und das programm erst nach der Abarbeitung in den int_Timer0 springt. Gibt es keine andere Lösung als mit CCP? Wie könnte ein Pseudocode für den CCP aussehen? Vielen Dank :)
pic_ler schrieb: > Wenn ich das also richtig verstehe ist das so, > [...] > int_Timer0 springt. Ja der Timer arbeitet komplett unabhängig vom Programm, wenn er einmal gestartet wurde. pic_ler schrieb: > Wie könnte ein Pseudocode für den CCP aussehen? Welchen PIC genau verwendest du?
pic_ler schrieb: > Gibt es keine andere Lösung als mit CCP? Neue Idee:
1 | void EXT_isr(void) |
2 | {
|
3 | timerwert=get_timer0() |
4 | anzahl0 = (Counter0 * 65536) + timerwert; |
5 | if(INTCONbits.T0IF && timerwert < 30) |
6 | anzahl0=anzahl0+65536; |
7 | |
8 | if (anzahl0 < 100000) |
9 | {
|
10 | output_high(PIN_C0); |
11 | }
|
12 | else
|
13 | {
|
14 | output_low(PIN_C0); |
15 | }
|
16 | set_timer0(0); |
17 | Counter0 = 0; |
18 | }
|
Jetzt wird geprüft, ob ein Timerinterrupt stattgefunden hat, das noch nicht bearbeitet wurde. In diesem Fall wird 65536 zu anzahl0 addiert. zu INTCONbits.T0IF: Wie man bei deinem Compiler einzelne bits abfragt musst du wissen, mein Code ist für den C18
:
Bearbeitet durch User
Hallo die Lösung ist prima, sie trifft genau den Punkt. Wie ich das Bit abfrage muß ich natürlich noch rausfinden, aber ich weiß jetzt, was ich machen muß. Tausend Danke für die schnelle und hervorragende Hilfe :)
pic_ler schrieb: > Wie ich das Bit abfrage muß ich natürlich noch > rausfinden, aber ich weiß jetzt, was ich machen > muß.
1 | if((INTCON&0b00000100)&&(timerwert < 30)) |
So sollte es ziemlich sicher funktionieren.
pic_ler schrieb: > set_timer0(0); > Counter0 = 0; Warum setzt Du den Timer auf null? Da mußt Du Dich nicht wundern, wenn ab und zu nach der EXT_ISR, Scheinbar einen Timer-ISR verloren geht, Du löscht es ja damit!
pic_ler schrieb: > } > set_timer0(0); > Counter0 = 0; > } Das T0IF solltest du auch auf 0 setzten, sonst hast eventuell du ein Interrupt zu viel.
Hallo Max und Teo danke für eure Hilfe und Beiträge. Die Umsetzung wird natürlich etwas Zeit in Anspruch nehmen, aber ihr habt auch sehr zum Verständnis über den Interrupt-Ablauf und Handling beigetragen.
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.