Hallo, mein Code soll mit 2Mhz Quarz und ATmega8 eine Frequenz von 1-100 Hz Messen. Dabei wird bei ankommen einer positiven Flanke an INT0 ein timer mit 1024erPS gestartet. Bei der nächsten Flanke wird dann der Timer gestoppt. Das ergebnis wird jeweils bei aufruf der ISR auf Port B gegeben und ich schaus mir mit LEDs an. Leider funktioniert das ganze nicht. Hier mal der Code: .include "m8def.inc" .def temp = r16 .def temp1=r17 .def temp3=r18 .org 0x0000 rjmp main .org INT0addr rjmp int0_handler .org OVF0addr reti main: ldi temp, LOW(RAMEND) ; Stackpointer initialisieren out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ldi temp, 0b00000011 ; INT0, rising edge out MCUCR, temp ldi temp, 0 << TOIE0 out TIMSK, temp ldi temp, 0b00000000 out TCCR0, temp ldi temp, 0x00 out TCNT0, temp ldi temp,0xFF ;Ausgang konfigurieren out DDRB, temp ldi temp,0x00 ; Eingang konfigurieren out DDRD, temp ldi temp, 0b01000000 ; INT0 aktivieren! out GICR, temp ldi temp, 0b00000000 ;Hier Temp mit 1024erPS laden ldi temp3,0b00000101 ;Hier einmal festgelegt! sei ;Generelle Interruptfreigabe! loop: rjmp loop int0_handler: ldi temp1, TCNT0 out PORTB, temp1 eor temp, temp3 out TCCR0, temp reti Eigentlich ein einfaches Programm. Danke!
Doch, sicherlich. Nur wie Du es machen willst, wird es keinem hier gefallenen. Einfach und elegant ist es, T1 mit hoher Taktfrequenz laufen zu lassen und die Periodendauer des Eingangssignals mit dem InputCaptureRegister ICR1 zu messen. Dazu muß Dein Signal an ICP1 anliegen, und Überläufe von T1 müssen mit ausgewertet werden. Das Thema ist hier schon öfter ausführlich besprochen worden: suchen und finden.
Gerade weil Du nur 100Hz messen willst, ist ICP1 ideal. Dein Programm ist sicherlich sehr kurz, aber es funktioniert ja auch nicht ;-)
Ja das stimmt ;) Aber ich dachte mir, mit 2Mhz Quarz währe es dann ideal mit 1024er PS sowas zu machen.... Es ist ja nichts großartiges. Positive Flanke, Zählstart, positive Flanke, Zählstopp. Das wars ja schon ;)
>ldi temp, 0b00000000 ;Hier Temp mit 1024erPS laden >ldi temp3,0b00000101 ;Hier einmal festgelegt! Was soll das? Du musst es schon noch in ein Register schreiben, damit es eine Auswirkung hat
? Ja habe ich doch auch gemacht! In der ISR des INT0 wird jeweils 0x00 oder ebenhalt 0x05 gesschrieben. Damit wird dann der timer jeweils gestartet und gestoppt!!
Starten und stoppen allein bringt afaik nichts, du musst ihn auch mal auf null setzten oder die Differenz zwischen neuem und altem Timerwert ausgeben,
Also meinst du: Timer Starten, Stoppen. Timer Wert auslesen. Timer Wert ausgeben. Timer auf 0 Setzen. Von Vorn. ?
Nein, ich wuerde den Timer nie stoppen sondern so (wenn du es ohne ICP machen willst): Hauptprogramm: Timer mit prescaler 1024 starten sei() Endlosschleife() ******* Interrupt: temp = Timer Timer = 0 PortB = temp reti
Hmm jo... Also meine Lösung kann ja nur "datenmüll" ausgeben... Denn wenn immer in Endlosschleife der Timer Wert ausgegeben wert, welcher sich ständig und schnell ändert, kanns nicht funktionieren ;) Also erst Zeit messen und ENDWERT, nach Stoppen des Timers, ausgeben.
Wie gesagt, den Timer musst du nicht stoppen, sondern nur auf 0 setzen, dann sollte es klappen. Ist mein "Programm" oben nicht verstaendlich?
Ja doch schon. Bis auf die Tatsache, dass der Timer Wert nur jedes zweite mal reinkopiert werden soll. Denn sonst hat man einmal 0 und einmal den Wert.
Nein, du kannst bei jeder steigenden Flanke den Timerwert auslesen, nach dem auslesen wieder auf 0 setzten. Es gibt so genau einen falschen Wert, und der entsteht dann, wenn der Interrupt zum ersten Mal ausgefuehrt wird nach einem Reset. Danach stimmt es mit dieser Methode immer. Nix mit Timer anhalten...!
Oki, bin gerade nicht daheim und kanns nich probieren. Nachher schau ich mal ob es funzt..
Hmm Funktioniert leider nicht :( Ich starte den Timer. Der uC Bleibt dann in einer endlosschleife und mach nichts. Bei Positiver Flanke wird in der ISR der Timer Wert gesichert, der Timer auf null gesetzt und der timer wert aufs port geschrieben. Lustigerweise kommt bei mir dann immer raus: 0bxxx10011 (Also das, was aufs port c geschrieben wird). Das verändert sich auch nicht :(
So jetzt läufts, erst nicht aber nun doch ;) Merke: TCNT0 wir nicht mit ldi in ein arbeitsregister kopiert sondern mit in! hinterdieohrenschreib
So funktioniert es glaube ich ;) .include "m8def.inc" .def temp = r16 .def temp1=r17 .def temp3=r18 .org 0x0000 rjmp main .org INT0addr rjmp int0_handler .org OVF0addr reti main: ldi temp, LOW(RAMEND) ; Stackpointer initialisieren out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;****************************** ; INTERRUPTs konfigurieren ldi temp, 0b00000011 ; INT0, rising edge generates interrupt request out MCUCR, temp ldi temp, 0 << TOIE0 ; Bei überlauf von Timer0 KEIN Interrupt out TIMSK, temp ;****************************** ; T I M E R 0 konfigurieren ldi temp, 0b00000000 ; Timer für den Anfang ausschalten! out TCCR0, temp ldi temp, 0x00 out TCNT0, temp ;***************************** ;Ports ldi temp,0xFF ;Ausgang konfigurieren out DDRC, temp ldi temp,0x00 ; Eingang konfigurieren out DDRD, temp ldi temp, 0xFF out PORTD, temp ldi temp, 0b01000000 ; INT0 aktivieren! out GICR, temp ldi temp, 0b00000000 ldi temp3,0b00000101 ;Hier einmal festgelegt! sei ;Generelle Interruptfreigabe! out TCCR0, temp3 ;Timer Starten! loop: rjmp loop int0_handler: in temp1, TCNT0 out PORTC, temp1 ldi temp, 0x00 out TCNT0, temp reti
- Im ext. Interrupt eine Zählvariable hochzählen. - Mit Timer einen Sekundentakt erzeugen. Darin die Zählvariable zur Ausgabe kopieren und danach löschen. Oder - Einen Timer/Counter als asynchronen Zähler über den externen Zähleingang (T0 oder T1) benutzen und damit die Impulse zählen. - Mit anderem Timer einen Sekundentakt erzeugen, in dem den ersten Timer/counter auslesen und löschen. Oder (wenn nicht die Frequenz, sondern die Periodendauer gewünscht wird) - Timer1 frei laufen lassen. - Signal an ICP1-Eingang legen. - Bei ICP-Interrupt ICR1H:ICR1L auslesen und Differenz zum Wert der letzten Messung bilden, dann den neuen Wert für die nächste Messung merken. Timer dabei nicht löschen. Vorteil: Man kann nebenher noch die beiden Compare-Interrupts des Timer1 benutzen, um z.B. eine 7-Segment-Anzeige zu multiplexen. - Messwert (Differenz neu minus alt) entspricht der Periodendauer. Soll die Frequenz gemessen werden, dann ist er umzurechnen (f=1/t). Da der AVR aber kein Hardware-Div hat, wird das eine kleine Fleißarbeit. KH
So um verwirrungen zu vermeiden habe ich jetzt mal nen mega32... Denn beim mega8 ist das port c ja "abgehackt". Klappt sehr gut und ich habe eine frequenzabweichung von "nur" einem Herz. Wohlgemerkt mit selbstgebautem Funktionsgenerator, der noch ein etwas zu schnelles quarz drinne hat... Danke nochmal für alle tipps. Ich werde mich, zwecks genauigkeit, noch mit der ICP Methode und 16bit arithmetik befassen...
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.