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.
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!!
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.
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...!
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 :(
- 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...