Hi, ich möchte ein Event loggen (wenn Spannung über Schwellwert). Dazu wollte ich den Comparator benutzen: der Interrupt des Comparators soll dann einen Timer starten. Der Timer bekommt seinen Takt vom internen Oszillator (16MHz) / 4 und Prescale 16 sollte also mit 250Hz laufen. Kann man das ganze irgendwie im Hintergrund laufen lassen, so dass die anderen Funktionen des PIC nicht beeinträchtigt werden oder muss ich bei jedem Timerüberlauf die Sekunden per Software berechnen und hochzählen? Danke
mit dem Bit TMR1ON kannst Du z.B. den Timer1 starten und stoppen. TMR1ON setzt Du, wenn der Comparator Deine Bedingung erfüllt.
Diotor schrieb: > Kann man das ganze irgendwie > im Hintergrund laufen lassen, so dass die anderen Funktionen des PIC > nicht beeinträchtigt werden oder muss ich bei jedem Timerüberlauf die > Sekunden per Software berechnen und hochzählen? Wie von meinem Vorredner gesagt machen und dann für den Timerüberlauf auch einen Interrupt ...
Danke für die Antworten, so wie ich das Versteh wäre die Umsetzung folgende: PSEUDOCODE while(!ComparatorInterrupt); TMR1ON if(TMR1Interrupt) ... somit könnte ich also den Zähler umsetzen, aber der PIC kann in dieser Zeit z.B. kein I2C Protokoll sprechen. Darum wollte ich fragen ob der Zähler hardwaremäßig im Hintergrund laufen kann, sprich parallel laufen kann.
das Ganze mal in Pseudocode ohne Interrupt (die Register für den Comparator habe ich jetzt mal nicht rausgesucht, weiss ich nicht auswendig). Der Timer muss gf. noch den Startwert 0 erhalten.
1 | do until comparator ; wait for comparator |
2 | loop |
3 | |
4 | clear_bit PIR1, TMR1IF ; Timer 1 flag bit rücksetzen |
5 | set_bit T1CON, TMR1ON ; Timer 1 starten |
6 | |
7 | do until PIR1, TMR1IF ; wait for Timer 1 Overflow |
8 | loop |
Hi, usuru schrieb: > das Ganze mal in Pseudocode ohne Interrupt (die Register für den > Comparator habe ich jetzt mal nicht rausgesucht, weiss ich nicht > auswendig). Der Timer muss gf. noch den Startwert 0 erhalten. > >
1 | > |
2 | > do until comparator ; wait for comparator |
3 | > loop |
4 | > |
5 | > clear_bit PIR1, TMR1IF ; Timer 1 flag bit rücksetzen |
6 | > set_bit T1CON, TMR1ON ; Timer 1 starten |
7 | > |
8 | > do until PIR1, TMR1IF ; wait for Timer 1 Overflow |
9 | > loop |
10 | > |
11 | > |
Das würde aber genau das bedeuten was der TE nicht will... Die Blockade des sonstigen Programmablaufs. Diotor schrieb: > somit könnte ich also den Zähler umsetzen, aber der PIC kann in dieser > Zeit z.B. kein I2C Protokoll sprechen. Darum wollte ich fragen ob der > Zähler hardwaremäßig im Hintergrund laufen kann, sprich parallel laufen > kann. JA - das kann der PIC. Wie von anderen schon geschrieben - Du musst mit Interrupt arbeiten. Ich habe aber trotzdem noch nicht ganz kapiert was du vorhast... Also klar ist: Der PIC überwacht eine Spannung, überschreitet diese den Grenzwert, dann soll der Zähler gestartet werden... Aber was soll dann passieren? Also was willst du nun auswerten? Die Zeit die seit diesem Ereigniss verstrichen ist? DAs ist AUCH für den folgenden Code von Bedeutung... Aber hie rmal ohne Garantie auf korrekten Syntax wie ich das gerade im Kopf habe. (Arbeite durchaus mit mehreren Prozessoren und habe keine Lust jetzt genau nachzuschauen...) #irgendetwas Codeähnliches double zaehl void main(void) { // Hier steht das Hauptprogramm while(1) { void interrupt isr(void) { if (TMR1IF) // Hat der Timer 1 den Interrupt ausgelöst? { zaehl++ TMR1IF = 0; // Timer interrupt zurücksetzen } if (weitere Interrupabfrage) // { ... ... ... } } Jetzt wird nach dem Start des Timer 1 bei jedem überlauf ein Interrupt ausgelöst. während der Interruptbearbeitung wird der Zähler zaehl um eins erhöht. Willst du dann irgendwann die Zeit wissen die seit der Auslösung vergangen ist musst du "(zaehl*256)/250= Zeit in Sekunden" berechnen. Zwischen den einzelnen Interrups arbeitet der PIC normal weiter. Selbst wenn du die Interruptbearbeitung kurzzeitig blockierst belibt dein Zählergebniss sogar noch richtig solange die Pause nicht länger als eine Überlaufperiode ist... Aber vorsicht: ICh habe gerade mit heftigen Kopfschmerzen und Fieber zu kämpfen. ggf. schreibe ich hier auch gerade Quatsch... Gruß Carsten
Ja genau will einfach die Zeit wissen wann die Spannungsspitze war. Ist Interrupt ein Schlüsselwort oder wie muss ich den Code verstehen, bzw wie wird die Interruptroutine aufgerufen?
Diotor schrieb: > Ja genau will einfach die Zeit wissen wann die Spannungsspitze war. > Ist Interrupt ein Schlüsselwort oder wie muss ich den Code verstehen, > bzw wie wird die Interruptroutine aufgerufen? Ich bin jetzt davon ausgegangen das dir das bekannt ist, denn du hast ja oben erwähnt das der Timerstart auch über den Comparatorinterrupt geschehen soll. ICh kenne deine Vorkenntnisse jetzt nicht, also auch nicht ob du z.b etwas von der ASM Programierung der Pics verstehst... Daher hier nur die Kurzform und anschließend der Verweis auf Beispielcode samt Literatur ;-) Also, intern läuft das mit dem Interrupt ja so ab, das der µC bei einem Ereigniss welches einen Interrupt auslöst auf eine bestimmte Speciherstelle im Programmspeicher springt und den Befehl der dort steht ausführt. Bei den 16er Pics war dafür zum Beispiel 0004 üblich. Bei 18F kenne ich jetzt 08 und 18. Bei dem 18er gibt es zwei Interrupteinsprünge weil es zwei Prioritäten gibt... Weiteres unter den Links... Entweder geht nun an dieser Stelle die Interruptbearbeitung los, oder man schreibt einfach einen Sprungbefehl zu einer Abarbeitungsroutine die schlicht irgendwo im Code stehen kann. Bei ASM ist das ganz einfach gewesen, da hat man im Editor einfach mit dem Befehl ORG 004 die Speicherzelle ausgewählt und ab da losgeschrieben. (vorher von der Startadresse aber noch einen Sprung auf das Hauptprogramm gemachtm also die Interruptbehandlung übersprungen) Da war es auch noch recht übersichtlich alles direkt auf 04 folgen zu lassen. Bei C geht das nicht so ohne weiteres als C Befehl. (Zumindest habe ich es anders gelernt) Deshalb bindet man diesen einen Sprungbefehl als Assemblerbefehl ein und setzt den an die Interruptadresse. Das Sprungziel hingegen ist aber der Beginn einer C Funktion. Diese könntest du auch "unterbrechungsabarbeitungsschleifevonmirselbst" nennen, passt nur nicht zu den Konventionen, Libs und Programmstückchen zum einbinden. Daher würde ich mich an die von Microchip vorgegebene Namensgebung halten. Also zusammenfassend: 1. Die Interruptroutine ist eine von dir selbst erstellte Funktion die nicht anders ist als andere Funktionen. Allerdings müssen in dieser Funktion die Interruptflags abgefragt werden wenn man die Interrups unterscheiden will - Und auch die Flags gelöscht werden, sonst geht es gleich wieder los. 2. Rein kommt man über einen Sprungbefehl den man an einer festen Stelle im Speicher ablegen muss. Das ist das Besondere am Interrupt ! Wie es jetzt genau geht, da schaue dir mal Übungsbeispiele ("Lesson Files") an die man mit dem Pickit3 Debug Express bekommt. Diese kann man frei runterladen, dürfte für alle 18er Pics identisch sein, mit den Einsprungadressen müsstes du evtl noch mal im 13K50 Datenblatt nachschauen (meine die waren aber gleich, bin mir abe rnicht sicher -zuviele Proz in verwendung ;-) !) Zu den "Lesson Files" bekommt man noch das Begleithandbuch in dem etwas dazu erklärt ist. Die Lektionen bauen aufeinander auf, falls etwas unkla sein sollte ggf. auch mal die Lektion vorher anschauen. Du kannst sicher auch etwas Copy & Paste machen. Die Files und das Handbuch findest du hier am ende der Seite: http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en538340&redirects=pickit3 Du möchtest haben: "PICkit 3 Debug Express Lesson Files" "PICkit 3 Debug Express Lessons User's Guide" Interrupt ist Abschnitt 8, habe gerade noch einmal nachgesehen Davor mal zu schauen ist aber nicht verkehrt... Ich hoffe das hilft dir weiter ;-) Die Zeiterfassung solltest du dann selber hinbekommen. Wenn du aber doch anregungen brauchst, auf Sprut.de gibt es Beispiele für eine Uhr, sind zwar in ASM und für den 16er, aber die Grundidee kann man dann auch auf C und 18er übertragen. Geht ja nur ums Prinzip. Ausserdem möchte ich wetten im Netz findet sich auch was für C und 18er. Bei den Sprut beispielen schätze ich aber das die wirklich rudimentär sind, also nur das notwendige drin ist. Ach ja: Wie genau soll die Uhr denn sein? Soll die genauer als eine Sekunde sein musst du natürlich noch zusätzlich zum Zähler in der Interruptbearbeitung auch noch bei der Auswertung den momentanen Stand des TMR1 auslesen... Gruß Carsten
Hallo, Schoener Post, Carsten. Noch eine kurze Anmerkung zum Komparator: Das Ding ist nur bedingt schnell. Neben dem eigentlichen Propagartion Delay ist auch zu beachten, dass der Eingang ausreichend ueber dem eingestellen Referenzpegel liegt und dass dies lange genug der Fall ist. Das musst du bei deinem Signal bzw. dessen Auswertung reuecksichtigen. Mal so ein Beispiel: Ich habe einen Komparator auf 3,5V Vref eingestellt, und da ein 4 MHz Sinus drangehaengt, dessen Amplitude bei rund 3,7V lag (DC Level 2,5V). Der Komparator hat das dann, auch nach vielen Perioden, nicht erkannt. Wenn dein Signal aber deutlich langsamer ist, ist das kein Problem. Gruss, Stampede
Ich habe versucht die Interruptroutine wie folgt umzusetzen, doch es tut sich nichts.
1 | void isrh(void); |
2 | |
3 | #pragma code InterruptVectorHigh = 0x08
|
4 | void InterruptVectorHigh (void) |
5 | {
|
6 | _asm
|
7 | goto isrh |
8 | _endasm
|
9 | }
|
10 | |
11 | #pragma code
|
12 | |
13 | #pragma interrupt isrh
|
14 | void isrh(void) |
15 | {
|
16 | if (PIR2bits.C1IF) //wenn sich der Comparatorausgang aendert |
17 | {
|
18 | OpenTimer0( TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256); |
19 | TMR0H = 0xC2; |
20 | TMR0L = 0xF7; //Startwert |
21 | PIR2bits.C1IF = 0; |
22 | if(INTCONbits.TMR0IF) |
23 | {
|
24 | INTCONbits.TMR0IF = 0; |
25 | //timer0();
|
26 | }
|
27 | //
|
28 | }
|
29 | }
|
30 | |
31 | void main(void) |
32 | {....}
|
Was ist falsch?
in main() sind noch die Interrupts enabled, das hatte ich vergessen //Interrupts INTCONbits.GIE = 1; PIR2bits.C1IF = 0; PIE2bits.C1IE = 1;
pardon, vertippt: muss weg: INTCONbits.INT0IE = 1; dafür rein: INTCONbits.TMR0IE = 1;
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.