Hej Leute
nach einer langen Pause (wegen Abschlussprüfungen und Nachwuchs) möchte
ich mich wieder mit meinem Atmega8 beschäftigen. Ich habe schon mit
einfachen ein und ausschalten von Ausgängen (LED Blink Blink) im
Verbindung mit Taster und und gearbeitet. Nun möchte ich mich langsam an
Timer und später über eine externe PWM z.B. LED Blinkfrequenz Regelungen
machen.
Das größte Problem, was ich habe ist, ich lese und lese, Google und
google schon ewig doch blicke da einfach nicht durch. Es gab noch kein
AHAAA Effekt. Erst dann hat man so etwas verstanden und kann es
einsätzen. So geht es zu mindest mir so.
Bevor mich irgendjemand lyncht da das Thema schon 1000000 mal
angesprochen wurde, hab Verständnis bin Anfänger im Mµ Bereich.
Ich wäre wirklich wirklich sehr sehr dankbar wenn mir irgendwer an Hand
eines C Programms ein ganz einfaches Beispiel z.B. verschiedene LEDs mit
verschiedenen Frequenzen blinken lassen, schritt für Schritt erklären
würde. Nur das ist eine Vorstellung habe, worum es da genau geht.
Womit fange ich an? Was muss ich festlegen und / Oder Aktivieren?
Wonach muss ich im Datenblatt suchen...?
Meine Hardware:
Atmega8 mit externen Quarz 4MHz.
Alles aufm Steckbrett.
LEDs, Widerstände, Taster... alles vorhanden.
Oszi, Multimeter... auch alles da.
Ich bedanke mich schonmal im voraus.
LG
Shabi
Shabi N. schrieb:> Ich wäre wirklich wirklich sehr sehr dankbar wenn mir irgendwer an Hand> eines C Programms ein ganz einfaches Beispiel z.B. verschiedene LEDs mit> verschiedenen Frequenzen blinken lassen, schritt für Schritt erklären> würde. Nur das ist eine Vorstellung habe, worum es da genau geht.
Arbeite diese Seite durch.
https://sites.google.com/site/qeewiki/books/avr-guide
Fang bei den Timern an und arbeite dich zur PWM vor. Dann kannst du
deine LED blinken lassen in verschiedenen Frequenzen.
Cheers,
al3ko
Shabi N. schrieb:> wenn mir irgendwer an Hand> eines C Programms ein ganz einfaches Beispiel z.B. verschiedene LEDs mit> verschiedenen Frequenzen blinken lassen
Das wird Dir nichts nützen.
Der Trick beim Programmieren besteht nicht darin, ein paar Zeilen C
hinzuschreiben, sondern sich erstmal ein Konzept zu überlegen, d.h. in
Worten zu beschreiben, wie der Programmablauf erfolgen soll.
Wenn man das vollständig und eindeutig hinkriegt, ist der eigentliche
Code nur noch etwa 10..20% der Arbeit.
Auch muß man erstmal einige Grundkonzepte lernen, wie Mainloop,
Bitmanipulation, Entprellung, Zählvariablen, Timer, Statemaschine usw.
Das Falschestes ist, sofort drauflos zu programmieren, das muß unbedingt
schiefgehen.
Peter
Hej Leute
Danke für die Links die sind echt gut. So lngsam klappt es mit ´dem
Timer.
Hab es geschafft eine LED zum Blinken zu bringen...
Der folgende Code schaltet meine LED ein und aus und da hätte ich noch
ein paar generelle FRagen:
#define F_CPU 4000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <inttypes.h>
#include <avr/interrupt.h>
int main(void)
{
DDRB = 0xff;
PORTB =0xff;
TIMSK = (1 << TOIE0);
sei ();
TCCR0 = (1 << CS02) | (1 << CS00);
while(1)
{
}
}
ISR (TIMER0_OVF_vect)
{
PORTB |= 1<<PB5;
//_delay_ms(200);
PORTB &= ~(1<<PB5);
//_delay_ms(200);
}
Ich benutze den Atmega8 mit 4MHz und einen Prescale von 1024.
Das ergibt bei 4 MHz:
4000000/1024= 3906,25Hz
3906,25/256=15,25 mal/s
1/15,25=0,065s pro Durchlauf.
Meine LED Blinkt natürlich viel zu schnell. Hab noch nen kleinen Buzzer
angeschlossen so das ich das ticken hören kann.
Meine 1. Frage:
Geht denn nicht mehr als 1024 Vorteiler?
2. wie mache ich es denn wenn ich genau auf 1 ms pro Durchlauf haben
will??
Bei 4MHz passt keiner von den Prescales.
2.Wenn ich die delay_ms mit einbaue, blinkt die LED schön im Takt so das
man das auch sehen kann. Was passiert denn jetzt genau? Wenn mein Timer
einen Overflow erreicht wird mein Interrupt gestartet. Wartet jetzt mein
Timer bis 200ms bzw 400ms vorbei sind und zählt dann wieder weiter??
Danke schon mal im voraus.
LG
Shabi
Hi
>Geht denn nicht mehr als 1024 Vorteiler?
Nicht beim ATMega8.
>2. wie mache ich es denn wenn ich genau auf 1 ms pro Durchlauf haben>will??>Bei 4MHz passt keiner von den Prescales.
CTC-Mode des Timers.
>2.Wenn ich die delay_ms mit einbaue, blinkt die LED schön im Takt so das>man das auch sehen kann. Was passiert denn jetzt genau? Wenn mein Timer>einen Overflow erreicht wird mein Interrupt gestartet. Wartet jetzt mein>Timer bis 200ms bzw 400ms vorbei sind und zählt dann wieder weiter??
Er zählt weiter. Delays in Interrupt-Routinen sind Unsinn.
MfG Spess
Shabi N. schrieb:> Wartet jetzt mein> Timer bis 200ms bzw 400ms vorbei sind und zählt dann wieder weiter??
Dann könnte man die Timer in die Tonne treten, sie wären nutzlos.
Der Witz an den Timern ist ja gerade, daß sie unabhängig von der
Programmausführung laufen. Nur so kann man genaue Uhren bauen.
Wenn Dir der Zählbereich des Timers nicht reicht, dann zähl einfach noch
ne Variable im Interrupthandler.
hhhhmm Ok
ich hab jetzt mak etwas mit CTC rumgespielt doch es klappt noch nicht so
wie ich es gern hätte.
hier mal ein Beispiel:
#define F_CPU 4000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
int main()
{
DDRB = 0xff;
PORTB =0xff;
TIMSK = (1 << OCIE2);
OCR2 = 241 - 1;
TCCR2 = (1 << WGM21) | (1 << CS22) | (1 << CS21) | (1 << CS20);
sei ();
while(1)
{
}
}
ISR (TIMER2_COMP_vect)
{
PORTB |= 1<<PB5;
PORTB &= ~(1<<PB5);
}
Nehmen wir an ich will das meine LED 1 mal in einer Sekunde Blinkt.
Dann mache ich doch erstmal folgendes:
4000000/1024= 3906,25 Hz.mit dieser Frequenz zählt mein Timer.
Dann mach ich ja 3906,25/256= 15,25 So oft zäht der Timer von 0 - 255/s.
Wenn ich jetzt 1Hz haben möchte, wie muss ich denn jetzt weiter machen??
Ist es denn überhaubt möglich mit den reinen Timer Funktionen sowas zu
realisieren? Theoretisch müsste ich doch 3906,25/3906,25 ´machen damit 1
HZ raus kommt.
Bin etwas verwirrt. Die Zahl bei (OCR2 = 241 - 1) ist nur ein Beispiel
und funktioniert auch. Wenn ich z.B. 21 - 1 eingebe, geht die Frequenz
wieder hoch.
HHHmm Grübel grübel.
LG
Shabi
Shabi N. schrieb:> Wenn ich jetzt 1Hz haben möchte
Dann erinnere Dich an die Grundschule, Faktorenzerlegung:
4000000
= 2^8 * 5^6
= 256 * 125 * 125
Prescaler, Timer, Variable
Peter
Shabi N. schrieb:> Wenn ich jetzt 1Hz haben möchte, wie muss ich denn jetzt weiter machen??> Ist es denn überhaubt möglich mit den reinen Timer Funktionen sowas zu> realisieren? Theoretisch müsste ich doch 3906,25/3906,25 ´machen damit 1> HZ raus kommt.
Du darfst den Timer halt nicht stur von 0 bis 255 zählen lassen, sondern
bis zu einem anderen Maximalwert. Wenn er beispielsweise von 0 bis 194
zählst, dann macht er er das 3906,25 / 195 = 20 Mal pro Sekunde. Die ISR
wird also alle 50 ms aufgerufen. Darin erhöhst (oder verringerst) Du
jedes Mal eine Variable. Wenn die ISR 20 Mal aufgerufen wurde, ist eine
Sekunde vergangen und Du schaltest die LED um.
hhhm das hört sich gut an. Ich müsste dann eine Variable bei jeden
durchlauf um einen Wert hochzählen lassen z.B. i++. Und wenn i==20 dann
Led an und aus und i wieder auf 0.
Nur stell ich mir die Frage, i muss ja vorher einen wert haben wie z.B.
0.
Dann würde ja aber bei jedem durchgang i erst 0 und dann wieder 1 sein.
Ich muss doch irgendwie einmalig i den wert 0 zuweisen so das i nur beim
Programm start 0 ist und ab dann immer hochgezählt wird.
HHHm wie könnte man das lösen?
shabi
Der Unterschied ist, dass man im ersten Fall auch von anderen Funktionen
(innerhalb der gleichen C-Datei) auf counter zugreifen kann, im zweiten
Fall counter dagegen nur in der ISR sichtbar ist.
Ich hab es mal ausprobiert aber irgendwas stimmt da noch nicht.
sobal ich spannung am µC anlege dauert es 1 Sek und die LED geht an und
das wars. es passiert nichts mehr. Als ob mein Timer nur einen Overflow
macht. Die Zeit scheint zu stimmen.
#define F_CPU 4000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
int main()
{
DDRB = 0xff;
PORTB =0xff;
TIMSK = (1 << OCIE2);
OCR2 = 195 - 1;
TCCR2 = (1 << WGM21) | (1 << CS22) | (1 << CS21) | (1 << CS20);
sei ();
while(1)
{
}
}
ISR (TIMER2_COMP_vect)
{
static uint8_t counter = 0;
counter++;
if (counter == 20)
{
counter = 0;
PORTB |= 1<<PB5;
PORTB &= ~(1<<PB5);
}
}
Wo könnte denn der Fehler sein? Vom Compiler bekomme ich keine
Fehlermeldung oder so.
LG Shabi
Shabi N. schrieb:> So hat geklapt hier meine Lösung.>
Wenn man es ganz genau nimmt, dann ist deine Led-Auszeit, wegen der
zusätzlichen Counter Erhöhung hier
> if (counter == 20)> {> PORTB |= 1<<PB5;> counter++;> }
um eine Winzigkeit kürzer als die An-zeit
(Annahme led leuchtet bei einer 0 am Port)
Wenn du auf explizites ein-/ausschalten verzichtest und statt dessen den
Pin toggelst
1
ISR(TIMER2_COMP_vect)
2
{
3
staticuint8_tcounter=0;
4
counter++;
5
6
if(counter==20)
7
{
8
PORTB^=1<<PB5;
9
counter=0;
10
}
11
12
}
dann erledigt sich dieses "Problem" ganz von alleine. Die An-Auszeiten
sind dann trivialerweise EXAKT gleich lang. (Im Rahmen der Interrupt
Latenz)
Karl Heinz Buchegger schrieb:> Wenn du auf explizites ein-/ausschalten verzichtest und statt dessen den> Pin toggelst> ISR (TIMER2_COMP_vect)> {> static uint8_t counter = 0;> counter++;>> if (counter == 20)> {> PORTB ^= 1<<PB5;> counter = 0;> }>> }
Hallo Karl Heinz
Das funktioniert. Aber was passiert da genau? Und was ist Toggeln??
1. Counter ist 0
2. Counter wird um 1 erhöht
3. Wenn Counter == 20
4. Dann diese Zeile PORTB ^= 1<<PB5; (Was passiert hier genau?
Diese Schreibweise kenne ich noch nicht)
5. Counter wieder 0
Danke im voraus
LG
Shabi
Shabi N. schrieb:> Karl Heinz Buchegger schrieb:>> Wenn du auf explizites ein-/ausschalten verzichtest und statt dessen den>> Pin toggelst>> ISR (TIMER2_COMP_vect)>> {>> static uint8_t counter = 0;>> counter++;>>>> if (counter == 20)>> {>> PORTB ^= 1<<PB5;>> counter = 0;>> }>>>> }>> Hallo Karl Heinz>> Das funktioniert. Aber was passiert da genau? Und was ist Toggeln??
Toggeln ist einfach nur der technische Ausdruck für 'Umschalten'.
> 1. Counter ist 0> 2. Counter wird um 1 erhöht> 3. Wenn Counter == 20> 4. Dann diese Zeile PORTB ^= 1<<PB5; (Was passiert hier genau?> Diese Schreibweise kenne ich noch nicht)
^ ist xor.
a xor b das ergebnis ist 1, wenn entweder a oder b, aber nicht
beide 1 sind
a b ergebnis
---------------------
0 0 0
1 0 1
0 1 1
1 1 0
a sei bei dir der Portpin, b ist das eine Bit in der Maske, welches
logischerweise 1 ist.
D.h. aus der Tabelle sind nur die beiden Zeilen interessant, in denen b
auf 1 ist. Und man erkennt:
wenn a gleich 0 ist, dann ist das Ergebnis 1
wenn a gleich 1 ist, dann ist das Ergebnis 0
D.h. das ganze läuft darauf hinaus, dass der Portpin bei jedem Ausführen
von
PORTB ^= (1<<PB5);
seinen Zustand wechselt. Ist der Pin vorher auf 0, dann ist er danach
auf 1. Ist er vor der Operation auf 1, dann ist er danach auf 0.
Eben: er wird ge-toggelt.
Das ist eine Bitweise XOR-Verknüpfung:
Die Logiktabelle von XOR sieht so aus
0 0 = 0
0 1 = 1
1 0 = 1
1 1 = 0
Fall LED ist an:
PORTB sieht so aus:
0bxx1xxxxx
XOR-Verknüpft mit
0bxx1xxxxx
________
0bxx0xxxxx
Ergebnis: LED ist aus
Fall LED ist aus:
PORTB sieht so aus:
0bxx0xxxxx
XOR-Verknüpft mit
0bxx1xxxxx
________
0bxx1xxxxx
Ergebnis: LED ist an
Schönen Abend noch
edit: och da war jemand schneller ;-)
AAAAhhh
Das ist ja genial (^ Xor)
Jetzt verstehe ich es.
Mir ging es zwar hauptsächlich dadrum den Timer kennen zu lernen, aber
es ist immer wieder schön mehr als nur einen AHA Effekt zu haben.
Feine Sache...
Danke Jungs. Ich werde jetzt erstmal noch ein paar Übungen mit Timer
machen und wenn alles gut geht, geht es mit PWM los.
Mein Ziel ist ja in endeffekt mit einem externen 50 Hz PWM (RC Bereich)
z.B. LED ein und aus zu schalten. Oder über die eine Fernsteuerung die
Bilkfreuqenzen zu regeln....
Naja denke da werden noch einige Fragen von mir kommen.
LG
Shabi
Karl Heinz Buchegger schrieb:> Für eine kleine Einführung in Timer, die die wichtigsten Dinge aus der> praktischen Sicht heraus beleuchtet:> FAQ: Timer
Auschnitt aus der FAQ Timer:
"... so dass zb bei einer Taktfrequnz von 1Mhz der Timer auch genau so
schnell zählt. In 1 Sekunde zählt ein Timer also von 0 bis 1000000, also
1 Mio Zählschritte."
... hmm, wenn ich mich nicht irre ist das ein Tick zu viel. Vom 0 bis
1000000 sind es 1000001 Zählschritte.
Tickzähler schrieb:> Karl Heinz Buchegger schrieb:>> Für eine kleine Einführung in Timer, die die wichtigsten Dinge aus der>> praktischen Sicht heraus beleuchtet:>> FAQ: Timer>> Auschnitt aus der FAQ Timer:> "... so dass zb bei einer Taktfrequnz von 1Mhz der Timer auch genau so> schnell zählt. In 1 Sekunde zählt ein Timer also von 0 bis 1000000, also> 1 Mio Zählschritte.">> ... hmm, wenn ich mich nicht irre ist das ein Tick zu viel. Vom 0 bis> 1000000 sind es 1000001 Zählschritte.
Tja ja das stimmt. Das alte Problem mit den null basierten Werten.
Man soll ja auch schon Programmierer gesehen haben, die drücken im
Aufzug die 3 wenn sie in den 4. Stock wollen.
gruß cyblord
Tickzähler schrieb:> Auschnitt aus der FAQ Timer:> "... so dass zb bei einer Taktfrequnz von 1Mhz der Timer auch genau so> schnell zählt. In 1 Sekunde zählt ein Timer also von 0 bis 1000000, also> 1 Mio Zählschritte.">> ... hmm, wenn ich mich nicht irre ist das ein Tick zu viel. Vom 0 bis> 1000000 sind es 1000001 Zählschritte.
Ja, aber.
Angenommen der Zähler steht auf 0.
Jetzt macht er 1 Zählschritt. Auf welcher Zahl steht er dann. Auf 1.
Nach 2 Zählschritten steht er auf ... 2
Nach 3, auf 3 ....
Er durchläuft 1000001 verschiedene Zahlen, aber er macht dazu 1000000
Zählvorgänge. Denn die 0 hat er ja quasi umsonst, ohne Zählschritt
erhalten (und erst dann, wenn er von 1000000 wieder auf 0 zurückfällt,
macht er dann den 1Mio+1-ten Zählschritt, der ihn wieder auf 0
zurückbringt.