Hallo, ich werde noch irre... Ich will Impulse von 10-80ms (in 10ms Schritten) im 100ms Abstand messen. Für die Signalerzeugung wird auch ein Mega8 verwendet. Laut Oszi haben die Zeiten eine Toleranz von ~0,2ms. Ich dachte, zum Erfassen der Zeiten ist der ICP-Pin ideal, da man die Flankenerkennung umschalten kann. Aber ich kann machen was ich will, die Timerwerte sind immer identisch und das Ergebnis ist dann logischerweise immer 0; Es soll erstmal die Zeitdifferenz zwischen steigender und fallender Flanke ausgegeben werden. Text "Impulsdauer:" wird angezeigt... Pulsdauer wird auch angezeigt, aber immer 0... Flanke1 und Flanke2 aus der ISR werden auf dem LCD mit verschiedenen Werten (beide Variablen immer gleich!) angezeigt ... Die LCD-Routine ist nur testweise drin (einfacher...) und funktioniert einwandfrei! In der ISR sind die LCD-Aufrufe nur drin, damit ich sehe, welche Werte ausgegeben werden. Ob die nun da drin sind oder nicht ist egal, der Effekt ist der selbe. Später soll dann eine 7-Segment Anzeige verwendet werden, aber bevor ich mich da weiter mache, sollte erstmal die Berechnung funktionieren... Ich hoffe Ihr könnt mir weiterhelfen, hier ist der Code: #define F_CPU 8000000UL #include <avr/io.h> #include <stdio.h> #include <util/delay.h> #include <util/SPI_LCD.h> #include <avr/interrupt.h> volatile uint16_t Flanke1; volatile uint16_t Flanke2; uint16_t Pulsdauer; int a; ISR (TIMER1_CAPT_vect) { if (TCCR1B & (1<<ICES1)) // Test auf steigende Flanke { Flanke1 = ICR1; // ICP Register = Flanke 1 TCCR1B &=~(1<<ICES1); // ICP1 auf fallende Flanke lcd_xy(0,2); lcd_Var(Flanke1); } if (!(TCCR1B & (1<<ICES1))) // Test auf fallende Flanke { Flanke2 = ICR1; // ICP Register = Flanke 2 TCCR1B |= (1<<ICES1); // ICP1 auf steigende Flanke lcd_xy(9,2); lcd_Var(Flanke2); } } int main (void) { PORTB = 0b00111110; DDRB = 0b00111110; // Port B0 als Eingang (ICP) TIMSK |= (1<<TICIE1); // ICP enable TCCR1B |= (1<<CS10)|(1<<CS12)|(1<<ICES1); // Timer1 => 1/1024 CPU-Clock, ICP steigende Flanke sei(); // Interruptfreigabe while (1) { Pulsdauer = (Flanke2 - Flanke1); // Pulsdauer ausrechnen cli(); // für LCD Ausgabe die Interrupts sperren, führt sonst zu Störungen // in den LCD-delays... lcd_xy(0,0); lcd_String("Impulsdauer:"); lcd_xy(0,1); lcd_Var(Pulsdauer); _delay_ms(100); sei(); // Interrupts wieder freigeben } return (0); }
Überleg mal, warum dein Programm immer beide if-Blöcke in der ISR durchläuft. Ein "else" an Stelle des zweiten if's dürfte das Problem lösen. Oliver
Außerdem: 1. cli und sei sind falsch positioniert. Du klammerst damit genau den falschen Bereich. 2. Welcher Controller? Z.B. Zitat Datenblatt ATmega8:
1 | After a change of the edge, the Input Capture Flag (ICF1) must be |
2 | cleared by software (writing a logical one to the I/O bit location). |
3. Die LCD-Ausgaben im Interrupt sind auch eher suboptimal. 4. Solltest du mit dem Berechnen von Pulsdauer nicht so lange warten, bis in Flanke1/2 auch was sinnvolles drin steht?
Hallo, Leute... Mit Eurer Hilfe habe ich es nun geschafft. Es sollte ein Zuordnungsgerät für 8 Leitungen werden, bestehend aus Sender und Empfänger... @ Oliver: Hauptproblem war die 2. if Abfrage in der ISR. Ich musste dann nur noch eine Variablenzuweisung hinzufügen, welche ich in 'main' abfrage. Dann hat alles funktioniert. @ Stefan E.: Nun gut, es musste natürlich gewartet werden, bis beide Messungen abgeschlosen sind. Aber dennoch ist Dein Zitat aus dem ATMEGA8 Datenblatt falsch!!! Sobald der Interrupt in der ISR aufgerufen wird, wird ICF1 automatisch gelöscht... Das richtige Zitat lautet: ICF1 is automatically cleared when the Input Capture Interrupt Vector is executed. Alternatively, ICF1 can be cleared by writing a logic one to its bit location. cli() & sei() habe ich korrigiert... Über die anderen Kommentare werde ich nicht eingehen, da Du offensichtlich meine Info dazu nicht gelesen hast. Da ich das Projekt interressant finde, werde ich das Projekt in der Codesammlung veröffentlichen... Danke und Gruß an Euch....
Axel Lemke schrieb: > @ Stefan E.: Nun gut, es musste natürlich gewartet werden, bis beide > Messungen abgeschlosen sind. Aber dennoch ist Dein Zitat aus dem ATMEGA8 > Datenblatt falsch!!! Das Zitat steht genau so wie von mir gepostet im Datenblatt (per Copy&Paste rausgeholt). Glaubst du ernsthaft, ich hätte mir den Text einfach ausgedacht? > Sobald der Interrupt in der ISR aufgerufen wird, wird ICF1 automatisch > gelöscht... > > Das richtige Zitat lautet: > > ICF1 is automatically cleared when the Input Capture Interrupt Vector is > executed. Alternatively, ICF1 can be cleared by writing a logic one to > its bit location. Lies mein Zitat nochmal genau. Es bezieht sich ja gar nicht auf das Flaglöschen nach einem Interrupt, sondern darauf, dass man nach dem Ändern der Flankenerkennung (also Bit ICES1) das Flag löschen muss. Das bedeutet implizit nichts anderes, als dass das Ändern des Bit ICES1 als Nebeneffekt ICF1 setzt (oder zumindest unter bestimmten Umständen setzen kann).
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.