Hallo, ich versuche langsame Frequenzen zu messen, und benutze dabei den externen Interrupt. Starte ich mein Programm liefer mir der Kontroller als erstes ein richtiges Ergebnis, doch alle fortlaufenden Ergebnise sind unterschiedlich und falsch. Kann mir jemand helfen. Ich versuche einfach Messungen im 10 Sekunden Takt zu erzeugen, doch irgendwie will mir das nicht gelingen. Vielen Dank für konstruktive Hilfe. #ifndef F_CPU //Definiere ATmega16L #define F_CPU 3686400UL //Quarz:3.6864 MHz #endif #include <util/delay.h> #include <avr/io.h> #include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <avr/interrupt.h> ISR(INT0_vect) { static int i=0; unsigned int j; unsigned long time; unsigned int timer[7]; unsigned char stream[40]; if(i==0) { i++; TCNT1=0; } else { GICR=0; i=0; cli(); time=TCNT1; time=57600*((float)1000000/(float)time); timer[0]=time%10; time=time/10; timer[1]=time%10; time=time/10; timer[2]=time%10; time=time/10; timer[3]=time%10; time=time/10; timer[4]=time%10; time=time/10; timer[5]=time%10; time=time/10; timer[6]=time%10; UCSRB=UCSRB | (1<<TXEN); //UART-Transmitter einschalten UCSRC=UCSRC | (3<<UCSZ0); //8-bit Datemformat;1 Stoppbits UBRRH=0; //Baudrate 19600 bei 3,6864MHz UBRRL=11; UDR=0; sprintf(stream,"\n\r%d.%d%d%d%d%d%d ",timer[6],timer[5],timer[4],timer[3],timer[2],timer[1],timer[0]); for(j=0;j<=15;j++) { while(!(UCSRA & (1<<UDRE))) //Warten bis der UART fertig { } UDR=stream[j]; } } } int main (void) { unsigned int i; TCCR1B=(1<<CS01) | (1<<CS00); //Clk auf 1/64 legen MCUCR=MCUCR | (1<<ISC01) | (1<<ISC00); //reagierend auf steigende Flanke INT0 while(1) { GICR=(1<<INT0); //lokalen Interrupt setzen sei(); //globalen Interrupt setzen for(i=0;i<=200;i++) { _delay_ms(50); } GICR=0; cli(); } return 0; }
Au Mann, wieder einer, der alles was es an rechenzeitintensiven Ausgaberoutinen gibt und noch alles Mögliche andere in einen Interrupt-Handler schmeißt und sich dann wundert, dass er Timing-Probleme kriegt. Hat sich das immer noch nicht rumgesprochen, dass ein Interrupt-Handler so kurz wie möglich zu halten ist? Mal im Ernst: Schmeiß den ganzen sprintf- und sonstigen Kram aus der ISR raus und ins Hauptprogramm. Und überlege v.a. mal, wie lange sprintf und der ganze Rest brauchen und wie viele Interrupts Dir dadurch entgehen.
>Hat sich das immer noch nicht rumgesprochen, >dass ein Interrupt-Handler so kurz wie möglich zu halten ist? Wie? Sowas geht?
Bedenke v.a., dass während der Ausgabe, die ja dummerweise in der ISR stattfindet, alles andere, auch die Frequenzmessung, auf Eis liegt. Mach die Frequenzmessung mit einem Timer-Interrupt (habs mir nicht so genau angesehen, musst also selbst entscheiden, obs mit Periodendauermessung [Capture] oder Periodenzählung [bei höheren Frequenzen] geht). Und die ganze Ausgabe ins Hauptprogramm. Dann kann der Timer-Interrupt (Compare, Overflow oder Capture, je nachdem) nämlich den ganzen Mist unterbrechen, wenn etwas wichtiges passiert. Das ganze Programm ist nicht durchdacht...
Geil! (SCNR) Sowas hab ich noch nie gesehen: Eine bedingte USART-Initialisierung in einer ISR. Wie mein Held vo KTEL im "Vierten" immer meint "Einfach groossaartig!" Manchmal glaube ich fast, dass es verboten ist, in der main irgendwas zu machen. Die main ist doch dazu da, von Interrupts unterbrochen zu werden, oder?
Ich lege mir immer ein Statusregister an, in dem ich Flags definiere. Zeitaufwändige Sachen, wie gesagt, ins Hauptprogramm und mi Hilfe der Flags ausführen lassen. So müssen in den INT-Routinen nur Flags gesetzt werden.
Ach ja, worüber Du Dir vielleicht zuerst Gedanken machen solltest, sind die Bearbeitungsprioritäten im Programm. Zeichne Dir am besten einen Ablaufplan. Denke daran, dass eine Frequenzmessung darauf angewiesen ist, dass kein Zählereignis verloren geht. Die Ausgabe und die Berechnung der auszugebenden Werte sind völlig unkritisch, was das Timing angeht. Die können auch mal warten, wenn grad was wichtiges ansteht. Merke: Sachen wie Fließkommaberechnungen, serielle Ausgaben, Warteschleifen usw. haben in einem Interrupt-Handler nichts zu suchen. Außerdem könntest Du überlegen, ob es wirklich unbedingt sprintf sein muss. Da gibt es wesentlich spezialisiertere Funktionen in der stdlib.h, die aufgrund ihrer Spezialisierung wesentlich weniger Overhead produzieren (was auch i.d.R. zu wesentlich kürzeren Bearbeitungszeiten führt).
@Rahul: Ich dachte immer, in der main darf man nur
1 | while(1); |
schreiben...;-)
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.