Hallo zusammen,
vor kurzem habe ich begonnen mich mit Mikrocontrollern zu beschäftigen.
Im Moment bin ich noch gaaanz am Anfang der Lernphase und würde mich
freuen, wenn wir jemand bei folgendem Problem helfen könnte.
Zuerst ein paar Randbedingungen:
- ATmega8A
- AtmelStudio 7
- STK500
Ich möchte ein Programm ertellen, dass eine LED mit der doppelten
Frequenz eines externen Rechtecksignals (etwa 1-5 Hz, Tastgrad variabel
zwischen 10-90%) blinken lässt.
Einen tieferen Sinn hat das Ganze zunächst nicht, es ist mehr eine
Verständnisaufgabe für mich.
So weit bin ich bisher gekommen:
Man kann die input capture Funktion des 16bit-Timers nutzen um die
positiven Flanken zu erkennen. Damit kann man die Periode des
Eingangssignals bestimmen.
Aufgrund der niedrigen Frequenz benutze ich einen Teiler von 256.
Nachdem die Periode bestimmt ist soll Timer0 starten. Sobald dieser den
halben Periodenwert erreicht, soll an Port D2 eine LED für 20ms
angeschaltet werden und der Timer0 zurückgesetzt werden.
Dann sollte der Timer wieder neu starten usw.
Leider klappt es irgendwie noch nicht, es scheint der Fall nicht
einzutreten, dass der Wert von Timer0 dem Periodenwert entspricht.
Es würde mich sehr freuen, wenn mir jemand einen Tip geben könnte was
ich falsch gemacht habe. Falls es einen einfacheren Weg gibt bin ich
ebenfalls für Hinweise dankbar. Danke im voraus!
Basis des Programms ist übrigens der Code hier, danke dafür an den
Autor:
https://www.mikrocontroller.net/attachment/highlight/77856
Hier ist der Code:
Bitte beschreibe die Fehlersymptome. Woran erkennst Du, daß:
> Leider klappt es irgendwie noch nicht, es scheint der Fall nicht ...
Auffallig ist bei oberflächlicher Betrachtung der Code und der
Kommentar:
1
Messungfertig=TRUE;// Dieser Zweig wird nicht mehr durchlaufen
in Verbindung damit, dass er von der folgenden Bedingung abhängig ist:
1
if(Messungfertig==FALSE)
Das heisst, "Messungfertig = TRUE;" verhindert nicht nur, dass der
fragliche Zweig durchlaufen wird, sondern, dass überhaupt in der ISR
noch irgend etwas geschieht.
Ich empfehle Dir, für eine Analyse, eine Zeitlinie hinzumalen und
einzutragen, in welcher Reihenfolge, welche Aktion ausgeführt wird,
resp. welche Entscheidung wie ausfällt.
Hier noch ein ganz anderer Lösungsweg:
External Interrupt auf jede Flanke des Eingangssignals konfigurieren und
damit die 20ms Blinke der LED starten. 100ms sieht man aber besser.
Hallo Theor,
danke für die schnelle Antwort.
Theor schrieb:> Das heisst, "Messungfertig = TRUE;" verhindert nicht nur, dass der> fragliche Zweig durchlaufen wird, sondern, dass überhaupt in der ISR> noch irgend etwas geschieht.
Ja, das stimmt. Die Periode des Eingangssignals ist dann ja schon
bekannt, deshalb dachte ich mir ich könnte diesen Zweig komplett
überspringen, damit der Wert nicht wieder überschrieben wird. Natürlich
gibt es dann ein Problem wenn sich die Frequenz des Signals ändert.
Was mir gerade auffällt: Ich könnte später auch wieder Timer1 statt
Timer0 nutzen, den brauche ich dann ja nicht mehr..
Theor schrieb:> Bitte beschreibe die Fehlersymptome.
Wenn ich das Programm lade passiert nichts an Port D2.
Wenn ich die Bedingung in if (counter2 < periode)ändere landet er in dem
Zweig und die LED geht wie geplant an. Also zählt Timer0 nicht hoch bzw.
erreicht periode nicht.
Die Flankenerkennung habe ich auch getestet, indem ich die zwei
LED-Zeilen (PORTD |= _BV(PD2);_delay_ms(20);) in die entsprechenden
Zweige kopiert habe. Läuft.
Starte ich den Timer0 vielleicht falsch?
Danke und Grüße
Nicola
Hallo Matthias,
danke für die Antwort.
Wenn ich zwei verschiedene Ausgänge in den beiden Zweigen des Interrupts
aktiv schalte bekomme ich dies:
Sind jetzt keine LEDs mehr, aber so sieht man es besser..
Die Flankenerkennung sollte also funktionieren.
Meintest Du das?
Grüße
Nicola
Ach jetzt habe ich es verstanden.. Ja, wenn ich immer 50% Tastgrad hätte
könnte ich auf steigende und fallende Flanke triggern, dann wäre ich bei
der doppelten Frequenz.
So auf ganz lange Sicht möchte ich die Mikrocontroller gerne dazu nutzen
Steuersignale von modularen Synthesizern zu verändern.
Da können dann auch Eingangssignale mit unterschiedlichem Tastgrad dabei
sein.
Im Moment möchte ich erst einnmal lernen, wie ich mit dem Controller und
den Timern überhaupt umgehe, damit ich später mit verschiedenen
Eingangssignalen arbeiten kann. Deshalb diese Übungsaufgabe.
So, ich habe das Problem etwas eingegrenzt:
Offenbar wird der Durchlauf von timer0 nicht registriert, d.h.
NrOverflows2 bleibt 0 und der Wert counter2 = (NrOverflows2 * 256) +
TCNT0 bleibt damit bei maximal 255 stehen. Damit bleibt er immer
unterhalb des Periodenwertes.
Mir ist schon aufgefallen, dass die bits für die Interrupts zum Zählen
des Timerüberlaufes bei beiden Timern gleich sind:
TIMSK = (1<<TICIE1) | (1<<TOIE1); // Interrupts akivieren, Capture +
Overflow
Hier
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR
steht ganz unten etwas von einer Global Enable Interrupt Flag. hat es
etwas damit zu tun?
Ich würde Dir folgende Tipps geben:
1)
Nutze Digitale Ausgänge als Diagnose. Das main toggelt einen Ausgang.
Damit siehst Du (am Oszi) das das Prg läuft.
1
intmain()
2
{
3
..initalisation
4
while(1)
5
{
6
PORTA^=_BV(PD1);
7
..cyclicwork
8
}
9
}
Die ISR zeigt Dir so an, das sie regelmässig aufgerufen wird:
1
ISR(TIMER0_OVF_vect)
2
{
3
PORTA|=_BV(PD2);
4
..do_something
5
PORTA&=~_BV(PD2);
6
}
2)
>etwa 1-5 Hz, Tastgrad variabel zwischen 10-90%) blinken lässt.
[10..90]% bei 5Hz sind [20..180]ms. Das sind also die kurzesten Zeiten,
die Du detektieren möchtest. Das ist für einen µC langsam.
Lasse einen Timer laufen. Evtl. den TIM0_OVR_vect. Diesen stellst Du so
ein, das er alle 1ms anspricht, also überläuft. In diesem prüfst DU
jetzt einfach, wie es um das abzutastende Signal gerade und letztens
aussah. Dann kannst Du die Messungen durchführen. Also etwa so:
Hallo S. Landolt,
ja, das war es tatsächlich! Danke für den Hinweis! Jetzt läuft es alles.
Ich werde aber trotzdem mal versuchen den Vorschlag von Matthias
umzusetzen, das sieht irgendwie sinnvoller aus als mein Ansatz. Für die
Weiterverarbeitung ist ein tick von 1 ms sicher handlicher.
Ich mache hier noch nicht zu, sicher habe ich später noch Fragen zu dem
Vorschlag.
Nicola R. schrieb:> Hallo Theor,>> danke für die schnelle Antwort.>> Theor schrieb:>> Das heisst, "Messungfertig = TRUE;" verhindert nicht nur, dass der>> fragliche Zweig durchlaufen wird, sondern, dass überhaupt in der ISR>> noch irgend etwas geschieht.>> Ja, das stimmt. Die Periode des Eingangssignals ist dann ja schon> bekannt, deshalb dachte ich mir ich könnte diesen Zweig komplett> überspringen, damit der Wert nicht wieder überschrieben wird. Natürlich> gibt es dann ein Problem wenn sich die Frequenz des Signals ändert.
Richtig. Ich bin auch davon ausgegangen, dass sich die Periode ändert.
Dumm von mir. Aber ich gehe schon immer allen auf die Nerven wenn ich
sowas nachfrage. :-)
> Was mir gerade auffällt: Ich könnte später auch wieder Timer1 statt> Timer0 nutzen, den brauche ich dann ja nicht mehr..
Richtig. Falls sich die Periode nicht ändert. Aber ich würde das erstmal
weiter so verfolgen, weil ich den Lerneffekt so für größer halte.
> Theor schrieb:>> Bitte beschreibe die Fehlersymptome.>> Wenn ich das Programm lade passiert nichts an Port D2.> Wenn ich die Bedingung in if (counter2 < periode)ändere landet er in dem> Zweig und die LED geht wie geplant an. Also zählt Timer0 nicht hoch bzw.> erreicht periode nicht.
Der Schluss ist voreilig. Du kannst eigentlich nur sagen, dass. falls
die LED nie ein Signal bekommte, immer zu den Zeitpunkten zu denen der
Vergleich erfolgt, counter2 != periode gilt.
Das sollte Dir zu denken geben. Wann genau erfolgt dieser Vergleich?
Steht dieser Zeitpunkt in einem passenden Verhältnis zu der Zykluszeit
des Timers? Gibt es nicht einem Möglichkeit, den Vergleich unabhängig
von der Befehlsauführung zu machen.
Auch solltest Du nochmal überdenken, warum Du NrOverflows2 mit 256
multiplizierst und welche Folgen das für die Bitbreite des Ergebnisses
hat.
> [...]
Ich rate Dir, wie oben schon einmal, Dir zunächst mal im Überblick zu
überlegen, was wann und aufgrund welcher Bedingungen geschehen soll und
erst dann eine Implementierung zu versuchen.
Zusätzlich rate ich Dir, die Kapitel über die Timer und Interrupts
nochmal gründlichst zu studieren.
Und modifiziere am besten erstmal nicht vorhandenen Code sondern
schreibe eigenen. Falls Du aber darauf bestehst, dann mache diese
Überlegungen zunächst mal in Bezug auf den unmodifizierten Code.
Nicola R. schrieb:> Hallo S. Landolt,>> ja, das war es tatsächlich! Danke für den Hinweis! Jetzt läuft es alles.
Tatsächlich? Meine Güte. Na gut.
> [...]
> Tatsächlich?
Ja, ich hatte auch zuerst gestutzt und dann gestaunt, besonders wegen
dieser '=='-Abfrage; aber da beide Timer mit Vorteiler 256 laufen und
sonst nichts passiert in der Hauptschleife, klappt das tatsächlich.
Hallo,
das wäre der Versuch mit dem ms-Tick.
Leider klappt es noch nicht so richtig, das neue Signal entspricht dem
alten Signal, siehe Bild 1.
Wenn ich die alte Periode durch vier teile stimmt die neue Periode, aber
es wird nur jedes zweite Rechteck ausgegeben (Bild 2).
Das Eingangssignal ist rot, das Ausgangssignal braun.
Ich vermute mal das Problem liegt vielleicht im Bereich if (Signal ==
0).
Jetzt essen wir erst mal, vielleicht komme ich ja noch dahinter.
Aber im Prinzip finde ich den Weg über den ms-Ticker gut.
>Ich vermute mal das Problem liegt vielleicht im Bereich
Nein.
>aber es wird nur jedes zweite Rechteck ausgegeben
Nein. Es wird mit jeder positiven Flanke ein eigener Impuls mit
definierter Länge kreiert. Das ist, wie ich später erkannt habe, nicht
ganz das was Du möchtest. Aber mein Beispiel zsollte nur aufzeigen, wie
ich daran gehen würde.
Das was Du ändern musst, ist das if-else if-else Konstrukt. Dort wird
das Signal generiert. Direkt darüber wird ja nur die Periodendauer
gemessen. Das wird ja benötigt.
EDIT:
>//Ausgabe neues Signal (braun): aus wenn mstick = flanke? Das passiert doch >nie?
Dies dient dazu zu verhindern, das bei Signal=0 weiter decrementiert
wird.
>Flanke wurde im vorherigen Durchgang erkannt
Nein. In allen solange noch nicht auf Null runtergezählt wurde
Hallo Matthias,
vielen Dank für die Antwort und für die Erklärungen. Ich werde mir die
Sache morgen noch einmal anschauen.
Hallo Theor,
Dir auch vielen Dank für Deine Anmerkungen.
Du hast recht, die Herangehensweise mit den beiden Timern ist
wahrscheinlich nicht optimal und durch die Brust ins Auge. Für mich ist
das eine gute Übung, ich lerne so etwas am besten, indem ich mich
einfach dransetze und loslege.
Natürlich lese ich auch viel in den Datenblättern, Artikeln und
Tutorials in diesem Forum. Ziemlich oft weiß ich aber noch nicht mal
welche Information ich gerade brauche, da hilft mir vorhandener Code
schon weiter.
Wenn ich dann ein größeres Projekt angehe werde ich tatsächlich einen
Ablaufplan skizzieren, im Moment hilft mir trial, error, gezielt
Nachlesen und Nachfragen gut weiter.
Und es ist ja auch nicht verkehrt, wenn dann Code dabei herauskommt, der
die CPU zum Kaffeeholen veranlasst. Das muss man ja auch erst einmal
hinbekommen!
Grüße und bis demnächst mal
Nicola
Nicola R. schrieb:> Hallo Matthias,>> vielen Dank für die Antwort und für die Erklärungen. Ich werde mir die> Sache morgen noch einmal anschauen.>>> Hallo Theor,>> Dir auch vielen Dank für Deine Anmerkungen.> Du hast recht, die Herangehensweise mit den beiden Timern ist> wahrscheinlich nicht optimal und durch die Brust ins Auge.
Das habe ich garnicht gesagt.
Beitrag "Re: Bitte um Hilfe bei Timerprogrammierung"
Ich habe nur zugestimmt, dass Du den selben Timer für die Messung und
anschliessend für die LED-Ausgabe verwenden kannst, falls sich die
Periodendauer nicht ändert. Das ist etwas ganz Anderes. Im Gegenteil
habe ich Dir geraten bei der 2-Timer-Lösung wegen des Lerneffekts zu
bleiben.
Es gibt dabei nämlich sehr viel Potential zur Vereinfachung, wenn man
die Möglichkeiten der Timer kennt.
(Ich habe da eine Lösung im Kopf, bei der ich keine einzige if-Anweisung
benötigen würde und lediglich eine statische und zwei Stack-Variablen im
Interrupt. Stichwort wäre PWM.).
> Für mich ist> das eine gute Übung, ich lerne so etwas am besten, indem ich mich> einfach dransetze und loslege.
Meiner Erfahrung nach, kommt dabei im allgemeinen nicht viel rum. Aber
vielleicht bist Du ja die Ausnahme, schreibst Dir das auf, machst Dir
Gedanken, vergleichst mit dem Datenblatt und baust so ein gedankliches
Modell der jeweiligen Algorithmus, des Prozessors auf. Erlebt habe ich
das noch nie hier, bei Leuten, die meinen sie lernen von
Trial-And-Error.
> Natürlich lese ich auch viel in den Datenblättern, Artikeln und> Tutorials in diesem Forum.
Es geht mir nicht darum, dass Du viel liest, wo auch immer. Es geht
nicht um die Menge. Sondern darum, dass Du die genannten Abschnitte über
Timer und Interrupts liest.
> Ziemlich oft weiß ich aber noch nicht mal> welche Information ich gerade brauche,
Das ist ein Kreislauf. Durch lesen lernst Du die Struktur und das
Verhalten kennen. Danach ergibt sich aus der Aufgabenstellung eine
bestimmte nötige Struktur und Verhalten. Danach, falls Du das nicht aus
dem Gedächtnis in Übereinstimmung bringen kannst, suchst Du dann gezielt
und lernst Neues. Bei der nächsten Aufgabenstellung musst Du wieder
weniger lesen.
> da hilft mir vorhandener Code> schon weiter.
Das halte ich für zweifelhaft, auch wenn ich annehme, dass das Deine
aufrichtig Ansicht ist. Um den Code zu verstehen, musst Du nämlich
gerade das im Datenblatt beschrieben Verhalten und die ebenso dort
beschriebene Struktur kennen. Ein anderer Fall ist rein Daten
manipulierender Code(, der keine Peripherie benötigt).
> Wenn ich dann ein größeres Projekt angehe werde ich tatsächlich einen> Ablaufplan skizzieren, im Moment hilft mir trial, error, gezielt> Nachlesen und Nachfragen gut weiter.
Hm. Ich meinte keinen Ablaufplan, sonst hätte ich "Ablaufplan"
geschrieben, sondern, wie ich auch schrieb ein Gegenüberstellung der
äusseren Ereignisse und des inneren Verhaltens, - also durchaus auch des
Codes - aber nicht ausschliesslich.
Zitat: "... eine Analyse, eine Zeitlinie hinzumalen und
einzutragen, in welcher Reihenfolge, welche Aktion ausgeführt wird,
resp. welche Entscheidung wie ausfällt."
Zitat: "... was wann und aufgrund welcher Bedingungen geschehen soll
..."
Ich will zugegeben, dass ich das Verhalten der Peripherie dabei nicht
erwähnt habe, und die Annahme, ich rede von einem Programmablaufplan,
nicht völlig unplausibel ist. Aber das ist ein Mißverständnis.
> Und es ist ja auch nicht verkehrt, wenn dann Code dabei herauskommt, der> die CPU zum Kaffeeholen veranlasst. Das muss man ja auch erst einmal> hinbekommen!
Nicht zu vergessen, der Plausch mit der Sekretärin. :-)
> [...]
Nicola R. schrieb:> Ich möchte ein Programm ertellen, dass eine LED mit der doppelten> Frequenz eines externen Rechtecksignals (etwa 1-5 Hz, Tastgrad variabel> zwischen 10-90%) blinken lässt.
Welchen Tastgrad soll dabei die LED haben?
Guten Morgen zusammen,
jetzt habe ich es hinbekommen und auch etwas besser verstanden. Ich
hatte das -- falsch interpretiert, da hat meine c-Schwäche
zugeschlagen..
Danke für die Hilfe und ein schönes Wochenende
Nicola