Forum: Mikrocontroller und Digitale Elektronik Hilfe! Schleife x Sekunden lang ausführen


von Diemo G. (diega)


Lesenswert?

Hallo, ich arbeite zum ersten Mal mit einem Mikrocontroller und zum 
ersten Mal mit AVR. Mein Controller ist ein attiny2313 und ich will eine 
Binäruhr bauen. Ich habe mir alles so zusammengebaut, dass ich die LEDs 
(jeweils 6 für Stunde, Minute und Sekunde) einzeln ansteuern kann. Die 
Idee hinter meinem Programm ist auch soweit fertig, ich weiß nur nicht, 
wie ich eine Schleife so programmiere, dass sie eine Sekunde lang 
ausgeführt wird. Ich habe mir schon viel Kram durchgelesen über Timer0 
und Timer1 und auch das AVR-Tutorial über Uhren, aber ich werde nicht 
schlau daraus... Ich muss also möglichst konkret wissen, wie ich eine 
Schleife so programmiere, dass der Controller sie eine Sekunde lang 
immer wieder im Loop ausführt und danach mit dem restlichen Code 
fortfährt.
Danke schon mal im Vorraus!

von Grrrr (Gast)


Lesenswert?

Das hört sich nach einem Designfehler an. An sich ist eine Schleife, die 
eine Sekunde lang ausgeführt wird in einer solchen Uhr garnicht 
notwendig.
Vielleicht beschreibst Du mal im grösseren Zusammenhang wozu solch eine 
zeitbegrenzte Schleife Deiner Ansicht nach notwendig ist.

Lies mal http://www.mikrocontroller.net/articles/AVR-Tutorial:_Uhr
Um Dir weiter zu helfen, müsstest Du schon genau schreiben was Du nicht 
verstehst, denn eine globale Erklärung, die potentiell alle Deine 
Verständnismängel, die wir dazu garnicht kennen, behebt, ist garnicht 
möglich.

von Diemo G. (diega)


Lesenswert?

Danke für die schnelle Antwort!
Das Problem ist, dass ich mit meinem Aufbau nicht ohne Weiteres mehrere 
LEDs gleichzeitig einschalten kann. Ich brauche die Schleife, damit eine 
Sekunde lang alle zu dem Zeitpunkt gewollten Lampen abwechselnd an- und 
aus geschaltet werden.

von Grrrr (Gast)


Lesenswert?

Diemo G. schrieb:
> Das Problem ist, dass ich mit meinem Aufbau nicht ohne Weiteres mehrere
> LEDs gleichzeitig einschalten kann.

Aha. Wie ist denn Dein Aufbau? Poste mal den Schaltplan. Hört sich nach 
Multiplexing oder Schieberegister an.

> Ich brauche die Schleife, damit eine
> Sekunde lang alle zu dem Zeitpunkt gewollten Lampen abwechselnd an- und
> aus geschaltet werden.

An sich ergibt sich der Zeittakt für eine Änderung des LED-Zustandes 
(Lampe oder LED?) aus dem der Uhr selbst. Eine besondere Vorkehrung für 
einen Sekundentakt ist also garnicht notwendig. Also, immer wenn sich 
die Sekunde ändert, dann muss der LED-Zustand geändert werden.
Da Du aber oben schreibst, das Du nicht mehrere LEDs gleichzeitig 
schalten kannst und damit Multiplexing (oder ein Schieberegister) 
suggerierst, wird überlicherweise ein noch schnellerer Takt benutzt um 
innerhalb der Sekunde die LEDs kurz anzuschalten bzw. den aktuellen 
Zustand in Schieberegister zu schieben.

Aber wiegesagt. Dazu sind nähere Erklärungen und ein Schaltplan 
notwendig.

von Karl H. (kbuchegg)


Lesenswert?

Dein Ansatz mit der Schleife ist schlecht.

Timer ist schon ein gutes Stichwort.
Was macht ein Timer?
Er zählt.

Hört sich jetzt banal an.
Aber so ein Timer zählt einfach nur vor sich hin und zwar, und das ist 
das entscheidende, völlig regelmässig.

An deinem µC hast du einen Quarz, der schwingt. Und zwar auch 
regelmässig. Zb. mit 4Mhz.
Wenn du nun den Quarz mit dem Timer koppelst, dann wird dein Timer 
ebenfalls regelmässig zählen. Und zwar auch mit 4Mhz. Oder in anderen 
Worten: Wenn man den Timer einfach vor sich hinzählen lassen würde, dann 
würde er in 1 Sekunde genau bis 4 Millionen kommen.

Nun gehts das aber nicht.
Der Timer kann nicht bis 4 Millionen zählen. Nehmen wir den Timer 1. Das 
ist ein 16 Bit Timer. Der kann daher nur bis 65535 zählen. Hat er 65536 
erreicht, dann beginnt er wieder bei 0. Das ist technologisch bedingt, 
weil der Timer nun mal nicht mehr als 16 Bit hat.

Stört uns aber nicht weiter. Rechnen wir doch mal in die andere 
Richtung.
Wenn der Timer in 1 Sekunde bis 4 Millionen zählen würde, es aber nicht 
kann, weil er bei 65535 (also nach jeweils 65536 Zählvorgängen) wieder 
bei 0 anfangen muss, wie lange dauert es dann, bis er einmal bis 65535 
kommt.

    1 Sekunde ............... 4000000
    x         ...............   65536
  --------------------------------------
          1 * 65536
    x = ------------- = 0.016384 Sekunden
         4000000

Wenn du deine Uhr daher nicht auf Sekunden als Basiseinheit, sondern auf 
diesen 0.016384 Sekunden aufbaust, dann gibt dir der Timer einen schön 
regelmässigen Takt vor. Du musst dann nur noch mitzählen, wie oft dieses 
Ereignis (Zähler ist übergelaufen) auftritt.

Wie kann man so etwas machen?

Nun. Ein Timer der nur vor sich hinzählt ist eher nutzlos. Interessant 
wird die Geschichte nur dadurch, dass du den Timer dazu bringen kannst, 
bei bestimmten Zählerständen irgendwelche Dinge auszulösen.

Ein solcher Zählerstand, ein Ereignis, ist zb genau dieser Overflow, 
wenn der Timer von 65535 zurück auf 0 springt. Man kann sich dann die 
Dinge so einrichten, dass bei diesem Ereignis eine ganz bestimmte 
Funktion automatisch aufgerufen wird, eine sogenannte ISR (Interrupt 
Service Routine). In diesem Fall ist es die ISR die für den Timer 
Overflow zuständig ist.

Jetzt können wir uns fragen: Na, wie oft wird denn die ISR in 1 Sekunde 
aufgerufen?
Und die Antwort ist einfach.
Wie wissen, dass der Overflow alle 0.016384 Sekunden kommt, die ISR wird 
daher in 1 Sekunde 61.035 mal aufgerufen. Leider ist das keine ganze 
Zahl (aber das sei jetzt erst einmal nebensächlich).
Wenn man also in der ISR eine globale Variable als Zähler hat, die bei 
jedem Aufruf ganz einfach um 1 hochgezählt wird und danach überprüft ob 
die Variable 61 geworden ist, dann weiss man, dass dieser Fall eintritt, 
wenn ~1 Sekunde vergangen ist. Hat man das festgestellt, dann erhöht man 
die Uhr um 1 Sekunde, setzt die Zählvariable wieder auf 0. Beim nächsten 
ISR Aufruf zählt die wieder um 1 hoch (1), beim nächsten wieder (2), 
usw. usw. bis nach 1 Sekunde wieder ein Stand von 61 erreicht ist und 
man darauf reagiert.

Und jetzt geb ich dich ab ans AVR-GCC-Tutorial bzw. das AVR-Tutorial. 
All das findest du nämlich dort auch wieder. Timer, Interrupts und was 
es rundherum noch so alles zu sagen und zu erzählen gibt.

von Karl H. (kbuchegg)


Lesenswert?

Diemo G. schrieb:
> Danke für die schnelle Antwort!
> Das Problem ist, dass ich mit meinem Aufbau nicht ohne Weiteres mehrere
> LEDs gleichzeitig einschalten kann. Ich brauche die Schleife, damit eine
> Sekunde lang alle zu dem Zeitpunkt gewollten Lampen abwechselnd an- und
> aus geschaltet werden.

Ui.
Du hast dir Multiplexing ausgesucht.
Dann hast du dir einen großen Brocken vorgenommen. Übelicherweise kommt 
man mit Multiplexing nicht vor 4 Wochen Erfahrung sammeln in der 
µC-Programmierung in Berührung. Und das ist auch gut so.

Lerne zuerst zu gehen, ehe du laufen willst.
Fang klein an, so wie alle anderen auch.

von Diemo G. (diega)


Lesenswert?

Ja, das ist Multiplexing und ich habe keinen Schaltplan, würde mich aber 
über ein geeignetes Programm freuen, um einen zu machen.
Der Timer, den ich möchte, soll den Sekundentakt überhaupt erst 
bestimmen. Ich habe bisher erst geschrieben, dass immer nach der 
Schleife, für die ich noch keine Abbruchbedingung habe, die eine Sekunde 
lang gehen soll, die Sekundenzahl um 1 erhöht wird und ggf. die Minuten 
usw. Dann wird noch übersetzt, welche LEDs beim nächsten Durchlauf 
leuchten müssen, damit  z.B. bei Sekunde 9 die LEDs 1 und 8 für Sekunden 
leuchten. Danach soll wieder die Schleife ausgeführt werden, die eine 
Sekunde lang die beiden LEDs an- und ausschaltet.

von Diemo G. (diega)


Lesenswert?

Karl heinz Buchegger schrieb:
> Diemo G. schrieb:
>> Danke für die schnelle Antwort!
>> Das Problem ist, dass ich mit meinem Aufbau nicht ohne Weiteres mehrere
>> LEDs gleichzeitig einschalten kann. Ich brauche die Schleife, damit eine
>> Sekunde lang alle zu dem Zeitpunkt gewollten Lampen abwechselnd an- und
>> aus geschaltet werden.
>
> Ui.
> Du hast dir Multiplexing ausgesucht.
> Dann hast du dir einen großen Brocken vorgenommen. Übelicherweise kommt
> man mit Multiplexing nicht vor 4 Wochen Erfahrung sammeln in der
> µC-Programmierung in Berührung. Und das ist auch gut so.
>
> Lerne zuerst zu gehen, ehe du laufen willst.
> Fang klein an, so wie alle anderen auch.

Das ist sehr traurig für mich, aber der Timer ist halt die letzte Hürde, 
vor der ich stehe. Kann der wirklich so viele Probleme machen?

von Karl H. (kbuchegg)


Lesenswert?

Diemo G. schrieb:
> Ja, das ist Multiplexing und ich habe keinen Schaltplan, würde mich aber
> über ein geeignetes Programm freuen, um einen zu machen.
> Der Timer, den ich möchte, soll den Sekundentakt überhaupt erst
> bestimmen. Ich habe bisher erst geschrieben, dass immer nach der
> Schleife, für die ich noch keine Abbruchbedingung habe, die eine Sekunde
> lang gehen soll

Nochmal
Das ist der falsche Ansatz.
So wird das nichts. Überhaupt dann nicht, wenn da aich noch Multiplexing 
mit im Spiel ist.

Du kannst es drehen und wenden wie du willst: Du wirst die Grundlagen 
lernen müssen!

Und eine der Grundlagen für Multiplexing und Uhr ist nun mal das man 
einen Timer einigermassen sicher benutzen kann.

von Floh (Gast)


Lesenswert?

Diemo G. schrieb:
> Ja, das ist Multiplexing und ich habe keinen Schaltplan, würde mich aber
> über ein geeignetes Programm freuen, um einen zu machen.

Eagle, Ascii-Circuit,
für die Leute mit künstlerischer Veranlagung auch Paint, Photoshop...

Oder ganz oldschool:
Ein Blatt Papier, dann einen Stift(Blei-),malen und 
einscannen/abfotografieren.
:-)
Und neben dem Schalplan zeigste uns dann auch mal dein Programm, dann 
kann man dir gezielt helfen.
:-)

von Grrrr (Gast)


Lesenswert?

Versuch hier mal in den Tutorien, die einfachen Timeraufgaben zu 
realisieren. Dann siehst Du schon wie es läuft.

Für Deine Uhr:
Du musst gedanklich immer von dem schnellsten Takt in Deiner Uhr 
ausgehen. In diesem Takt musst Du die am häufigsten auftretende Aktion 
ausführen. Das ist der Takt mit dem die LEDs gemultiplext werden.

Stell Dir vor, Du hättest Die Aufgabe eine Uhr von Hand zu bedienen, 
also den Sekundenzeiger, den Minutenzeiger selbst vorzurücken. Dazu hast 
Du ein Metronom, das alle Sekunde klackt.
Du würdest also bei jedem Klack, den Sekundenzeiger um einen Strich 
weiterrücken und wenn Du ihn auf Null vorgerückt hast, sofort den 
Minutenzeiger um eins vorrücken.

Genauso läuft es mit dem Multiplexing, nur ein wenig schneller.
Du musst z.B. alle 10ms jeweils die LEDs einschalten, die leuchten 
sollen, was gerade von der aktuellen Uhrzeit abhängt. Aber während Du 
das tust, ändert sich die Uhrzeit nicht. Wenn Du das 100 Mal getan hast, 
ist genau eine Sekunde vergangen.

von Diemo G. (diega)


Lesenswert?

Danke an alle, ich werde mich nun intensiver damit beschäftigen, aber 
eine Frage habe ich noch zu dem
>Zitat von Grrrr:
>Aber während Du das tust, ändert sich die Uhrzeit nicht."
Kann ich nicht herausfinden, wie lange er für die Berechnung der LEDs 
braucht und in Abhängigkeit davon einen Abbruchbedingung machen? Das 
wäre ja dann indirekt auch ein Timer.

von Stefan (Gast)


Lesenswert?

NEIN.

Nimm einfach 2 Timer

Den ersten stellst du auf 1sekunde, in dessen Interrupt Routine wird 
einfach die Sekunden nach den Regeln der Uhr erhöht.

Den zweiten stellst du z.b. auf 1kHz und mit dem machst du das 
Multiplexing.

Fertig.

von Karl H. (kbuchegg)


Lesenswert?

Diemo G. schrieb:

> Das ist sehr traurig für mich, aber der Timer ist halt die letzte Hürde,
> vor der ich stehe. Kann der wirklich so viele Probleme machen?

Der Timer nicht.

Aber du musst jetzt 2 Dinge gleichzeitig unter 1 Hut bringen. Wenns 
nicht funktioniert, woher weißt du welcher Teil nicht funktioniert?

von Grrrr (Gast)


Lesenswert?

Diemo G. schrieb:
> Kann ich nicht herausfinden, wie lange er für die Berechnung der LEDs
> braucht und in Abhängigkeit davon einen Abbruchbedingung machen? Das
> wäre ja dann indirekt auch ein Timer.

Theoretisch ja. Soweit ist Deine Überlegung folgerichtig und sie würde 
funktionieren.
Das würde man allenfalls in einem Multimilliarden-Dollar-Projekt machen, 
wenn alle Platinen soweit fertig sind und morgen der Abgabetermin ist 
und eben irgendwie verpennt wurde, das "richtig" zu machen und ein uC 
ohne Timer gewählt wurde.
In der "Praxis" würde man das nie so machen. Falls Du das erste und 
letzte Mal in Deinem Leben einen uC programmierst, dann mach es so, weil 
es dann keine Rolle spielt. Aber Du lernst eben nichts praktisch 
relevantes dabei.

Vergiss das mit der Schleife und der Abbruchbedingung. Du scheinst 
irgendwie darauf fixiert zu sein, die Sekunden mit einer Schleife 
abzumessen. Aber nimm einmal an, Du müsstest in einem späteren Projekt 
noch einen Alarm einbauen oder willst eine Maus auf dem Display tanzen 
lassen, ein MP3 abspielen etcpp. Jede Änderung an dem Zeitablauf würde 
ein neues bestimmen der Verzögerungszeit bedeuten. Und, noch viel 
schwerwiegender, falls Du Bedingungen in dem Code hast, wäre die 
Laufzeit evtl. nicht konstant, bzw. Du müsstest aufwendige Maßnahmen 
treffen um die Laufzeit konstant zu kriegen.

Deine Idee funktioniert ungefähr so gut, wie der Versuch ein Auto an 
einer Mauer anzuhalten. Es geht, aber es ist absolut nicht 
empfehlenswert. ;-)

von Karl H. (kbuchegg)


Lesenswert?

Diemo G. schrieb:

> Kann ich nicht herausfinden, wie lange er für die Berechnung der LEDs
> braucht und in Abhängigkeit davon einen Abbruchbedingung machen? Das
> wäre ja dann indirekt auch ein Timer.

Glaub es.
Deine Idee mit der Messung der Ausführungszeit ist zwar in der Theorie 
machbar, in der Paxis aber völlig untauglich.

Dazu musst du alle Pfade, die dein Programm nehmen kann berücksichtigen 
und von jeder Anweisung die Taktzyklen zählen und die aneinander 
angleichen. Und bei der geringsten Programmänderung geht alles wieder 
von vorne los. Ja schon die nächste Compilerversion kann dir alles 
durcheinanderwerfen.

Du brauchst einen Taktgeber, der unabhängig von deinem Programm einen 
reproduzierbar exakten Basistakt zur Verfügung stellt. Ein Timer ist so 
eine Komponente, sie wurde extra dafür gebaut. Eine Schleife ist das 
nicht.

Selbst dann, wenn du einen Timer benutzt, wird deine Uhr nicht auf 
Anhieb angemessen genau gehen, selbst wenn du dich mittels Timer an jede 
einzelne Quarzschwingung klemmst. Denn, Überraschung: Dein (Hausnummer) 
4Mhz Quarz macht keine 4000000 Schwingungen in der Sekunde. Der macht 
vielleicht ein paar 100 Hz mehr oder weniger. Zu allem Überdruss auch 
noch abhängig von der Temperatur.

Wir reden hier von einer Uhr! Selbst kleinste Abweichungen im µSekunden 
Bereich summieren sich bei Laufzeiten von Wochen und Monaten zu 
beträchtlichen Minuten und Stundenzahlen auf!

von Grrrr (Gast)


Lesenswert?

Siehst Du! Sogar Karl-Heinz sagt so. ;-)

von Karl H. (kbuchegg)


Lesenswert?

Stefan schrieb:
> NEIN.
>
> Nimm einfach 2 Timer
>
> Den ersten stellst du auf 1sekunde, in dessen Interrupt Routine wird
> einfach die Sekunden nach den Regeln der Uhr erhöht.
>
> Den zweiten stellst du z.b. auf 1kHz und mit dem machst du das
> Multiplexing.

Für ihn ist das eine gute Strategie, auch wenn sich mir die Haare ein 
wenig sträuben, 2 Timer zu benutzen, wo's 1 auch tut.

Aber, wie heißt es so schön: Für nicht benutzte Komponenten bekommt man 
von Atmel kein Geld zurück. Wenn der µC einen oder mehrere Timer hat, 
kann man die auch ruhig benutzen.

von Karl H. (kbuchegg)


Lesenswert?

Grrrr schrieb:
> Siehst Du! Sogar Karl-Heinz sagt so. ;-)

Kunststück :-)
Das ist so klar wie Klossbrühe, das das mit einer Schleife nichts werden 
kann.

Er sträubt sich doch nur gegen Timer, weil das schon wieder etwas Neues 
ist und er sich das Ganze eigentlich viel einfacher vorgestellt hat. Was 
er noch nicht weiß: Bei Timern geht es hauptsächlich um Konzepte und 
Verständnis. Hat man das erst einmal, ist die Implementierung ein 
Kinderspiel. Viel einfacher als Schleifen.

von R. F. (rfr)


Lesenswert?

Takte deinen Controller mit einem Uhrenquartz 32768 Hz.
Teile die 32768 durch 256, ergibt 128.

Also setze eine geschachtelte Schleife ein, die heruntrer zählt:

Start:
loop1:   ld r8,128
loop2:   dec r7
         jnz    loop2
         dec r8
         jnz loop1
;; wenn hier angekommen, mach das, was alle sec gemacht werden soll.




Das Beispiel geht davon aus, dass alle Befehle in einem Microzyklus 
ausgeführt werden. Mangels Datasheet kann es hier Abweichungen geben. 
Das muss dann in die Startwerte von r7 einfliessen.

Gruss

Robert

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
Noch kein Account? Hier anmelden.