Hallo,
ich erzeuge über den Timer0 eine FastPWM. Nun möchte ich während des
High-Pegels ein anderes Signal mit dem ADC messen.
Wie bekomme ich nun den steigende Flanke des PWM-Ausgangs erkannt? Gibt
es da ein Flag welches der Timer setzen kann?
Es ist bestimmt ganz einfach, aber irgendwie...
Danke schonmal.
Hallo,
erstmal danke für die Antworten und entschuldige, dass ich so lang für
eine Antwort gebraucht habe.
So ganz durchsteige ich die Funktion nur nicht.
ICR1 muss ich doch noch einen Wert zuweisen, oder? (Nur welchen)
Genauso verhält es sich für OCR1A/OCR1B?
Mir fehlt die Verbindung zu meiner eigentlichen PWM des Timers0.
Die Verbindung besteht darin, dass du ja WEISST wann die steigende
Flanke im PWM Signal kommt!
Nämlich dann, wenn der Timer im FastPWM Modus (und entsprechender Pin
Einstellung) bei 0 zu zählen anfängt. Und das geschieht dadurch, dass
der Timer einen Overflow macht.
TCCR1B=((1<<WGM13)|(1<<WGM12)|(1<<CS10));// Mode 14 + No prescaling
3
TIMSK1=(1<<TOIE1);// Die ISR (TIMER1_OVF_vect) beim Erreichen von ICR1 aufrufen
4
TCNT1=0;// reset timer / counterregister
Damit habe ich also den Timer1 eingestellt
In der Interruptroutine führe ich nun eine Funktion aus. Zur Kontrolle
lasse ich mir die ermittelten Werte auf den Terminal schicken.
So nun kommt allerdings nichts. Ich schließe daraus, dass die
Interruptroutine nicht angesprungen wird.
(Funktion und Senden per UART funktioniert, ist getestet).
alguesto schrieb:> So nun kommt allerdings nichts. Ich schließe daraus, dass die> Interruptroutine nicht angesprungen wird.> (Funktion und Senden per UART funktioniert, ist getestet).
Daraus schliesse ich wiederrum, dass du keinen sei() im Programm hast.
Zeig vollständigen Code. Schön langsam sind es die meisten Regulars hier
im Forum leid, sich immer wieder aus Codeausschnitten (in denen der
Fehler nicht steckt), den Rest zusammenzureimen und zu Raten, welche
Fehler du noch hättest machen können.
> ISR (TIMER1_OVF_vect)> {> cli();
braucht keiner
> char buffer[20];> itoa(getAD(2,3), buffer, 10);> uart_puts(buffer);> sei();
den willst du hier ganz sicher nicht haben!
Karl Heinz Buchegger schrieb:> Daraus schliesse ich wiederrum, dass du keinen sei() im Programm hast.
Doch den habe ich in der main().
Hier nochmal alles. Habe die sei() und cli() in der ISR rausgenommen.
Bei einer PWM-Freuquenz von f=8MHz/(8*256)=3,9kHz ist das eine sehr
beträchtliche Anzahl.
Deine Vermutung ist also, dass die Abarbeitung gar nicht so schnell
erfolgen kann und während der Abarbeitung schon wieder ein neuer
Interrupt aufgetreten ist.
Deshalb hatte ich die Interrupts innerhalb der Routine abgeschaltet, was
mir ja wieder um die Ohren geworfen wurde ;)
Oder ich sollte die uart_puts nicht in der ISR abhandeln sondern
ausserhalb?(Müßte ich dafür dann die Funktion als volatile deklarieren?)
alguesto schrieb:> Deine Vermutung ist also, dass die Abarbeitung gar nicht so schnell> erfolgen kann und während der Abarbeitung schon wieder ein neuer> Interrupt aufgetreten ist.> Deshalb hatte ich die Interrupts innerhalb der Routine abgeschaltet, was> mir ja wieder um die Ohren geworfen wurde ;)> Oder ich sollte die uart_puts nicht in der ISR abhandeln sondern> ausserhalb?(Müßte ich dafür dann die Funktion als volatile deklarieren?)
Machs halt erst mal einfach:
Keine ADC, keine UART.
Wenn die ISR aufgerufen wird, wird eine LED eingeschaltet.
Das erzählt dir erst mal alles, was du wissen willst. Je mehr du machst
und je komplexer dein Testprogramm ist, desto mehr Fehlermöglichkeiten
gibt es auch.
(Und ich bin ehrlich gesagt auch nicht sicher, ob im Modus 14 vom Timer
1 überhaupt ein Overflow ausgelöst wird. Lässt sich aber schnell mit
einer LED abklären)
alguesto schrieb:> Bei einer PWM-Freuquenz von f=8MHz/(8*256)=3,9kHz ist das eine sehr> beträchtliche Anzahl.
Jedes Zeichen dauert bei 9600Bd knapp 1 Millisekunde. Du kannst also gar
nicht bei jedem Overflow die ADC-Werte über UART senden, sondern
vielleicht bei jedem zehnten - wenns hochkommt. Solche zeitintensiven
Sachen gehören einfach nicht in die ISR. Dort kannst Du höchstens ein
Flag setzen, dass mittlerweile ein ADC-Wert ermittelt wurde. Das
eigentliche Senden über UART erfolgt dann in der main-funktion - oder
auch Interrupt-gesteuert, indem man ein FIFO füllt.
Abgesehen davon habe ich dieselben Zweifel wie Karl Heinz, dass hier
überhaupt ein OVF-Interrupt ausgelöst wird. Daher ist ein Test mit einer
LED sehr sinnvoll.
> Deshalb hatte ich die Interrupts innerhalb der Routine abgeschaltet, was> mir ja wieder um die Ohren geworfen wurde ;)
Beim Betreten einer ISR werden die Interrupts sowieso global
abgeschaltet, beim Beenden der ISR werden sie wieder eingeschaltet.
Deine cli-/sei-Kombination in der ISR war daher hyperfluid.
Aber was passiert: Kommt während des Abarbeitens einer ISR ein neuer
Interrupt, merkt sich der µC das in einem Flag und führt die
entsprechende ISR direkt nach Abarbeiten der vorhergehenden ISR aus!
Im schlechtesten Falle macht der µC also nichts mehr anderes als ISRs
auszuführen - in Deinem Fall immer dieselbe.
Das wird aber alles hier im AVR-Tutorial beschrieben. Du solltest Dir
solche Grundlagen erst einmal aneignen, bevor Du komplizierte Sachen
anpackst.
> Oder ich sollte die uart_puts nicht in der ISR abhandeln sondern> ausserhalb?(Müßte ich dafür dann die Funktion als volatile deklarieren?)
Ja. Nein.
Der uart_puts war ja eigentlich auch nur zum schauen ob es funktioniert,
werd den dann mal in die main schreiben.
Das mit der "LED-Methode" werde ich mal austesten, werd mir einen
Ausgang am Oszi anschauen.
Bin aber heute nicht mehr am Objekt,kann es also erst später einmal
testen.
Eure Befürchtungen beunruhigen mich allerdings etwas, dass es so
prinzipiell nicht funktionieren kann. Gibt es denn noch Alternativen?
So war heute mal am Objekt.
Also die ISR wird tatsächlich angesprungen. Ich habe einen Pin in der
ISR gesetzt und ausserhalb wieder zurückgestzt.
Problem ist jetzt noch, dass es frequenzmässig noch nicht zusammen
passt, was ich allerdings auf den (nicht eingestellten) Prescaler des
Timers1 zurückführe.
Des weiteren ist das Duty-cycle zum Timer0 invertiert, ist ja auch so
eingestellt, aber wird dadurch die ISR nicht gerade zum ungewollten
Zeitpunkt angesprungen?