Hallo, ich würde gern ein Blinklicht programmieren, welches ich über ein gesendetes Zeichen per UART ein- und ausschalten kann. Das Blinklicht soll jedoch ohne Timer programmiert werden. Kann mir jemand einen Tip geben wie ich die Sache am besten angehe? Vielen Dank! Gruß
Indem du dir mal überlegst, wie du ein Blinklicht alleine hinkriegst. Vergiss erst mal das ein-/aus-schalten über den UART und kümmere dich nur darum eine LED an einem Port zum blinken zu kriegen. Wenns denn ohne Timer sein soll, dann musst du halt anderweitig dafür sorgen, dass zwischen ein und ausschalten der Led ( nichts anderes ist ja blinken) eine gewisse Zeit vergeht. Es gibt da mehrer Möglichkeiten: eine davon ist eine vorgefertigte delay - Funktion (kommt mit avr-gcc daher), eine andere ist es den µC ganz einfach in einer Schleife Zeit vertrödeln zu lassen (nichts anderes macht die delay Funktion). Wenn du das hast, dann liest du erst mal alles, was du über UART zum lesen auftreiben kannst und probierst mal ein paar einfache Beispiele durch. zb. Der µC sendet über die UART dasselbe Zeichen zurück, dass er empfängt. Klappt das, dann überlegst du dir, wie du den Blinkcode umbauen musst, damit du das Blinken selbst ein und aus- schalten kannst. Das testest du am besten mal indem du eine globale Variable benutzt, die das Blinken ein und ausschaltet. Funktioniert das, dann kommt der UART dazu, der je nach empfangegen Zeichen, die globale Variable auf den richtigen Wert setzt.
Empfiehlt sich denn eher die deelay Funktion oder eine Schleife?
Die delay-Funktion ist auch nur eine Schleife, die Zeit vertrödelt. Besser wäre allerdings ein Timer, aber den willst Du ja vermeiden. Falls Deine Timer anderweitig belegt sind, mach ne Schleife, wenn Du nur zu faul bist, dir die Timer-Funktion anzuschauen, solltest Du die Faulheit überwinden, der Timer is nämlich ne praktische Sache, die Du bestimmt noch öfter brauchen kannst.
Wieso willst du denn keinen Timer verwenden? Is doch ideal dafür !!
Ich denke, Frank ist drauf und drann sein erstes Programm zu schreiben. Dafür ist eine Zeitschleife, wie delay durchaus ok. Auch Rom wurde nicht an einem Tag erbaut. Irgendwo muss er mal anfangen. @Frank Mit avr-gcc kommt eine _delay_ms Funktion. Sie wartet die angegene Zeit in Millisekunden. Allerdings hat das Ding einen Haken: Du kannst nicht beliebige Millisekunden angeben. Die maximale Wartezeit hängt von der Taktfrequenz ab und berechnet sich zu: 262ms / Taktfrequenz in Megahertz. Ist aber kein Problem. Man kann ja delay_ms selbst wieder in einer Schleife immer wieder aufrufen. #define F_CPU 1000000 // hier musst du deine tatsächliche // Taktfrequenz eintragen. Die wird von // _delay_ms zur Berechnung der Schleifen- // dauer benoetigt. #include <avr/io.h> #include <util/delay.h> int main() { unsigned char i; DDRB = 0xFF; // angenommen an Port B haengt deine LED // dann muss Port B mal als Ausgang definiert // werden while( 1 ) { PORTB = 0xFF; // am PORT B mal alle Pins auf 1 // danach warten for( i = 0; i < 50; i++ ) _delay_ms( 10 ); // 50 mal 10 ms macht 0.5 Sekunden // am PORT B alle Pins wieder auf 0 PORTB = 0x00; // und wieder warten for( i = 0; i < 50; i++ ) _delay_ms( 10 ); // 50 mal 10 ms macht 0.5 Sekunden // durch die while Schleife geht jetzt alles // wieder von vorne los: Alle Pins auf 1, // warten, alle Pins auf 0, warten, etc. etc. } }
Die Timer will ich leider anderweitig verwenden. Mit nem Timer hab ich schon nen Blinklicht programmiert, das hat echt gut funktioniert. Wenn ich jetzt nen Blinker mit ner Schleife programmiere, z.B. ich zähle in der Schleife bis zu einem bestimmten Wert und schalte dann den Port um, dann kommt dieser Programmteil ja in die while(1) in der main(). Wenn ich nun noch nen AD-Wandler benutze, wird dieser ja auch in der while(1) in der main() initialisiert. Kommt es dabei dann vielleicht zu Problemen, weil er ja für eine bestimmte Zeit in der Schleife für den Blinker hängt?
> Die Timer will ich leider anderweitig verwenden. Das ist meist kein Hindernisgrund. Ein Timer kann ja durchaus mehrere Aufgaben auf einmal durchführen. Meist hat man in einem Programm sowieso einen Basistimer, der einfach nur vor sich hintickt und dem Programm einen Zeittakt vorgibt. Alle zeitabhängigen Dinge sind dann einfach nur ganzzahlige Vielfache dieses Basistaktes. > while(1) in der main() initialisiert ganz sicher nicht. Initialisiert wird alles nur einmal, nicht öfter! Was in der Schleife passiert ist, du gibst den ADC für eine Messung frei. Der ADC kann sich dann zb. mit einem Interrupt wieder melden, wenn er fertig ist.
Hi Karl Heinz, vielen Dank für den Beispielcode! Wäre es also möglich, den 8-Bit Timer mit dem ich ein PWM-Signal erzeuge auch noch für den Blinker zu verwenden? Aber dieser zählt doch nicht nur hoch und macht nen Overflow sondern zählt auch wieder runter. Oder macht er den Overflow trotzdem? Weil dann könnt ich ja den Overflow Interrupt nutzen.
Kommt drauf an: Welchen µC? welcher PWM Modus? Sollte aber eigentlich im Datenblatt stehen, welcher Interrupt ausgelöst werden kann. Beim Mega16 ist das zb. ein Output Compare Interrupt am Timer0.
Ein Atmega88 im Fast PWM Mode. Im Datenblatt steht, dass zwei Output Compare Interrupts zur Verfügung stehen und ein Overflow Interrupt. Nur ob diese auch im PWM Modus funktionieren, weiß ich nicht! Da steht irgendwas mit Force Output Compare auf Seite 104 im Datenblatt. Dieses Bit ist soweit ich das Verstanden habe im PWM Mode nicht gesetzt. Heißt das also dass auch der Interrupt nicht während des PWM Modus läuft? Eigentlich ist doch das Bit OCIE0B für den Compare Interrupt verantwortlich. Wie weit OCIE0A und FOC0A nun zusammenhängen kapier ich nicht ganz.
Bin mir jetzt nicht ganz sicher, aber auch beim Fast PWM-Mode müsste es noch das Überlauf Interrupt geben. Man könnte also in der Timer-Overflow-ISR einfach eine Variable in- oder dekrementieren, die dann für ein Software-Interrupt sorgt (die Variable von halt in der Main abgefragt...).
Im fast PWM mode wird nix runtergezählt. Das passiert ausschließlich bei phase correct PwM. Das force outupt compare ist nie gesetzt. Das mußt du setzen, wenn du ein compare-match-Ereignis manuell auslösen willst. Die Interrupts werden ausgelöst, wenn die entsprechende Bedingung gegeben ist. die Output-Compare-Interrupts werden immer beim entsprechenden Compare-Match ausgeführt. Für den Overflow steht es . in der Beschreibung der WGM-Bits (TOV flag set on... in der Tabelle). Wenn der Overflow-Interrupt an ist, wird er immer ausgelöst, wenn das TOV-Flag gesetzt wurde.
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.