hallo leute, ich brauch mal wieder eure hilfe. und zwar bin ich gerade
damit beschäftigt für mich zur übung und zum besseren verständnis der
verschiedenen Timermodi eine genaue gewünschte Verzögerung zu erzeugen.
die funktion ist ja außerdem auch noch ganz nützlich, da das mit dem
_ms_delay() ja für zeitkritische dinge zu ungenau ist.
hier mein programm:
1
/* Demonstriert den 8-Bit Timer 0
2
*
3
* Laesst LED an PB0 blinken
4
*/
5
6
#include<avr/io.h>
7
#include<avr/interrupt.h>
8
9
uint16_tintcounter;
10
11
12
ISR(TIMER0_COMP_vect)
13
{
14
15
intcounter++;
16
17
18
}
19
20
21
22
voidverzoegerung(uint16_tms)
23
{
24
25
sei();// globale Interrupts ein
26
27
28
while(ms>=intcounter)
29
{
30
// tue nichts außer warten
31
}
32
33
intcounter=0;
34
35
cli();//globale Interrupts aus
36
37
}
38
39
40
41
42
43
intmain(void)
44
{
45
46
DDRB|=(1<<PB1);// PB1 als Ausgang
47
48
49
TIMSK|=(1<<OCIE0);//Interrupt bei Compare Match
50
51
OCR0=(8000000/256)/1000-1;//OCR0 auf 30,25 => Interrupt wird mit frequenz von 1khz ausgelöst
52
53
54
TCCR0=(1<<WGM01);// CTC- Modus
55
TCCR0|=(1<<CS02);//Prescaler auf 256
56
57
58
while(1)
59
{
60
61
verzoegerung(1000);
62
PORTB^=(1<<PB1);// Toggle LED1, hier mit jede Sekunde 1 mal
63
64
}
65
66
return0;
67
}
meinen atmega16 betreibe ich 8 MHZ taktfrequenz und programmieren tue
ich auf einem STK500. eigentlich möchte ich vorerst einmal lediglich
eine LED (hier LED1) blinken lassen. aber aus irgendeinem grund leuchtet
meine LED andauernd.
kann mir irgendjemand sagen ob ich den Timer richtig eingestellt habe
bzw. was an meinem programm sonst verbesserungswürdig ist?
mfg
danke holger, das hab ich wohl vergessen. aber bei der einstellung der
frequenz hab ich auf jeden fall auch noch etwas falsch gemacht. bisher
ändert die LED nämlich nur so ca. alle 10 sekunden ihren schaltzustand.
wo liegt da mein denkfehler?
mfg
jetzt hab ich mein programm mal nochmal verändert. hauptsächlich mal die
frequenzeinstellung mit der formel aus dem datenblatt:
1
/* Demonstriert den 8-Bit Timer 0
2
*
3
* Laesst LED an PB0 blinken
4
*/
5
6
#include<avr/io.h>
7
#include<avr/interrupt.h>
8
9
volatileuint16_tintcounter;
10
11
12
ISR(TIMER0_COMP_vect)
13
{
14
15
intcounter++;
16
17
18
}
19
20
21
22
voidverzoegerung(uint16_tms)
23
{
24
25
sei();// globale Interrupts ein
26
27
28
while(ms>=intcounter)
29
{
30
// tue nichts außer warten
31
}
32
33
intcounter=0;
34
35
cli();//globale Interrupts aus
36
37
}
38
39
40
41
42
43
intmain(void)
44
{
45
46
DDRB|=(1<<PB1);// PB1 als Ausgang
47
48
49
TIMSK|=(1<<OCIE0);//Interrupt bei Compare Match
50
51
OCR0=14.625;//OCR0 auf 14,625= 8000000/(2* 256* 1000) => Interrupt wird mit frequenz von 1khz ausgelöst
52
53
54
TCCR0|=(1<<WGM01);// CTC- Modus
55
TCCR0|=(1<<CS02);//Prescaler auf 256
56
57
58
while(1)
59
{
60
61
verzoegerung(1000);
62
PORTB^=(1<<PB1);// Toggle LED1, hier mit jede Sekunde 1 mal
63
64
}
65
66
return0;
67
}
aber die blinkdauer stimmt immer noch nicht. jetzt ändert die led so
alle 2-3 sekunden den schaltzustand.
diese ungenauigkeit wird ja wohl nicht davon kommen, dass ich den µc mit
dem internen oszillator betreibe.
welche timereinstellung rechnet ihr aus?
wer
Stk 500 anfänger schrieb:> OCR0 = 14.625; //OCR0 auf 14,625= 8000000/(2* 256* 1000) => Interrupt wird mit
frequenz von 1khz ausgelöst
das funktioniert halt suboptimal, das OCR0 nur ganzzahlig ist. Folglich
wird dein Zeitfehler mit steigendem Verzögerungswert größer.
Such dir nen Teiler/OCR-Wert, der möglichst ganzzahlig aufgeht. :-)
OCR0=8000000/(2*8*1000)-1;//OCR0 auf 499= 8000000/(2* 8* 1000) => Interrupt wird mit frequenz von 1khz ausgelöst
52
53
54
TCCR0|=(1<<CS01);//Prescaler 8
55
TCCR0|=(1<<WGM01);// CTC- Modus
56
57
58
59
while(1)
60
{
61
62
verzoegerung(1000);
63
PORTB^=(1<<PB1);// Toggle LED1, hier mit jede Sekunde 1 mal
64
65
}
66
67
return0;
68
}
jetzt komme ich auf einen ganzzahligen OCR0 wert. aber ich werd das
gefühl nicht los, dass die Blinkdauer falsch eingestellt ist. hab es
gerade mit der Sekunde einer uhr verglichen und ich muss sagen, dass
meine LED ziemlich genau alle 2sekunden ihren Schaltzustand ändert,
obwohl ich es ja so programmiert habe, dass sie ihn jede sekunde ändern
soll.
ist meine timereinstellung wirklich richtig?
mfg
update: das umsetzten von intcounter = 0; bringt auch nichts. jetzt hab
ich es mal handgestoppt.
egal ob mit OCR0= 499 oder OCR0 = 249: die LED ändert immer erst nach
ca. 1,6 sekunden seinen blinkzustand.
kann das an der ungenauigkeit des internen quarzoszillators liegen?
vielleicht summiert sich die taktungenauigkeit über eine Sekunde ja auf.
Stk 500 anfänger schrieb:> egal ob mit OCR0= 499 oder OCR0 = 249: die LED ändert immer erst nach> ca. 1,6 sekunden seinen blinkzustand.> kann das an der ungenauigkeit des internen quarzoszillators liegen?> vielleicht summiert sich die taktungenauigkeit über eine Sekunde ja auf.
Das liegt mit Sicherheit nicht an der ungenauigkeit des Oszillators
(intern ists übrigends RC nicht Quarz).
Mir kommt da grad so ein Verdacht: Den richtigen Prozessor in den
Compileroptionen hast du eingestellt?
> egal ob mit OCR0= 499 oder OCR0 = 249: die LED ändert immer erst nach> ca. 1,6 sekunden seinen blinkzustand.
Programm speichern, compilieren und erst dann brennen könnte helfen.
holger schrieb:> Programm speichern, compilieren und erst dann brennen könnte helfen.>>>>>> Beitrag melden | Bearbeiten | Löschen |
hab ich gerade probiert. ändert aber auch nichts an der funktion
Stk 500 anfänger schrieb:> meine LED ziemlich genau alle 2sekunden ihren Schaltzustand ändert,> obwohl ich es ja so programmiert habe, dass sie ihn jede sekunde ändern> soll.
Nein. Das hast du nicht.
Wenn du den Schaltzustand jede Sekunde ändern willst, dann brauchst ist
dein Faktor 2, den du da immer drinnen hast, nicht. Dieser Faktor 2
kommt ja nur daher, dass du 2 ISR Aufrufe brauchst um eine komplette
"Welle" (also steigende Flanke - fallende Flanke; mit der nächsten
steigenden Flanke beginnt die nächste Welle) zu erzeugen und die ist
wiederrum wichtig, wenn du eine Frequenz einstellen willst.
Wenn deine LED mit 1Hz blinken soll, dann muss sie alle 0.5 Sekunden
ihren Zustand wechseln. Da kommt der Faktor 2 her
Aber:
Erklär mir mal bitte, wie du ein Rechenergebnis von 499 in einem 8-Bit
Register unterbringen willst?
Du arbeitest mit dem Timer 0. Der ist 8 Bit breit. Bei allem!
Tu dir selbst einen Gefallen und mach deine ersten Gehversuche immer mit
dem Timer 1. Als 16 Bit Timer sind alle Register 16 Bit und du läufst
nicht so leicht Gefahr, ständig ungewollt in arithmetische
Überläufsituationen reinzulaufen.
Stk 500 anfänger schrieb:> egal ob mit OCR0= 499 oder OCR0 = 249: die LED ändert immer erst nach> ca. 1,6 sekunden seinen blinkzustand.
Ähm, bei einem 8 Bit Timer ist maximal nur 255 mgl. Das heisst, aus
deinen 499 werden mal schnell 243. Den Unterschied zu 249 merkst du
natürlich kaum
499d=1 1111 0011b --> nur letzten 8bit --1111 0011b=243d
jetzt hab ich mal eure ratschläge zu herzen genommen und das ganze mit
dem Timer1 programmiert:
1
/* Demonstriert den 8-Bit Timer 0
2
*
3
* Laesst LED an PB0 blinken
4
*/
5
6
#include<avr/io.h>
7
#include<avr/interrupt.h>
8
9
volatileuint16_tintcounter;
10
11
12
ISR(TIMER1_COMPA_vect)
13
{
14
15
intcounter++;
16
17
18
}
19
20
21
22
voidverzoegerung(uint16_tms)
23
{
24
intcounter=0;
25
sei();// globale Interrupts ein
26
27
28
while(ms>=intcounter)
29
{
30
// tue nichts außer warten
31
}
32
33
34
35
cli();//globale Interrupts aus
36
37
}
38
39
40
41
42
43
intmain(void)
44
{
45
46
DDRB|=(1<<PB1);// PB1 als Ausgang
47
48
49
TIMSK|=(1<<OCIE1A);//Interrupt bei Compare Match
50
51
OCR1A=1000;//OCR1A auf 249= 8000000/(2* 8* 2000) => Interrupt wird mit frequenz von 1khz ausgelöst
52
53
54
TCCR0|=(1<<CS01);//Prescaler 8
55
TCCR1B|=(1<<WGM12)|(1<<CS11);// CTC- Modus mit Prescaler= 8
56
57
58
59
while(1)
60
{
61
62
verzoegerung(1000);
63
PORTB^=(1<<PB1);// Toggle LED1, hier jede Sekunde 1 mal
64
65
}
66
67
return0;
68
}
auch den wert von OCR1A hab ich neu berechnet. bin nun auf 499 gekommen.
aber das kann nicht stimmen, da die led jetzt nur alle 3-4 sekunden
ihren blinkzustand ändert.
jetzt hab ich mal ausprobiert für welchen vergleichswert meine LED mit
den gewünschten 0,5Hz blinkt. da komm ich auf so ca. einen wert von 200.
da aber da ich es verstehen möchte, wüsste ich jetzt gerne was ich in
die formel einsetzen muss, um den korrekten wert für OCR1A zu erhalten.
irgendwie kapier ich das mit der frequenzeinstellung trotz eurer
zahlreichen erklärungen noch überhaupt nicht. kann mir mal bitte jemand
sagen, was mit dem Focna in der formel aus dem datenblatt für eine
frequenz gemeint ist? meint man damit die frequenz mit der die ISR
aufgerufen wird oder meint man damit die frequenz mit der ein Ausgang
toggeln würde in der ISR?
ich in meinem fall brauche ja meiner meinung nach eine ISR- frequenz von
1/1ms= 1khz.
bin irgendwie momentan recht verwirrt wie ich nun machen soll.
mfg
Stk 500 anfänger schrieb:> auch den wert von OCR1A hab ich neu berechnet. bin nun auf 499 gekommen.
Und warum steht dann da ...
1
OCR1A=1000;//OCR1A auf 249= 8000000/(2* 8* 2000) => Interrupt
.... ?
> aber das kann nicht stimmen, da die led jetzt nur alle 3-4 sekunden> ihren blinkzustand ändert.
logisch.
Wenn du einen Wert ausrechnest, dann musst du den schon auch benutzen.
> jetzt hab ich mal ausprobiert für welchen vergleichswert meine LED mit> den gewünschten 0,5Hz blinkt. da komm ich auf so ca. einen wert von 200.
Das könnte hinkommen wenn dein µC tatsächlich mit ~1Mhz und nicht mit
8MHz läuft.
> da aber da ich es verstehen möchte, wüsste ich jetzt gerne was ich in> die formel einsetzen muss, um den korrekten wert für OCR1A zu erhalten.
Vergiss fürs erste die Formel.
Dein µC läuft (laut deiner Aussage) mit 8Mhz.
D.h. der Timer würde das auch. Tut er aber nicht, weil du einen
Vorteiler von 8 gesetzt hast.
Das heißt: Dein Timer macht in 1 Sekunde 8Mio / 8 -> 1 Mio Zählvorgänge.
Du willst 1/1000 Sekunde abmessen. D.h. du darfst den Zähler nur bis
1000000 / 1000 = 1000 zählen lassen.
Mit der Teiler-Taktrate von 1Mhz schafft es der Timer in 1/1000 Sekunde
gerade bis 1000 zu zählen.
Wenn du daher dem Timer klarmachst, mittels OCR Register, dass er nach
1000 Zählvorgängen (daher muss ins Register auch 999 rein und nicht
1000, denn auch die 0 ist ja ein Zählvorgang) sich auf 0 zurücksetzen
soll und einen Interrupt auslösen soll, dann kommt der Interrupt
regelmässig alle 1/1000 Sekunden.
Da dies alles von dir nicht beeinflussbar ist und du bei ~999 keine
1/1000 Sekunde zwischen den Interrupts hast, ist der einzig logische
Schluss: Dein µC läuft nicht mit 8 Mhz.
Ein frischer Mega16 läuft mit 1Mhz. Rechnen wir mal damit:
In 1 Sekunde würde der Timer bei einem Vorteiler von 8 daher
1000000 / 8 = 125000 Zählvorgänge machen.
In 1/1000 Sekunde kommt er daher nur bis 125. D.h. Eine 124 im OCR
Register sorgt für (mehr oder weniger, denn ob die 1Mhz genau 1Mhz sind,
steht in den Sternen) einen Interrupt Aufruf alle 1/1000 Sekunde.
125 ist für mich nahe genug an den von dir empirisch festgestellten ~200
als Vergleichswert, dass ich die Behauptung wage: Dein µC läuft mit 1
Mhz.
2 Mhz wären auch noch möglich, dann müsste ein Wert von 250 ins OCR
register.
> irgendwie kapier ich das mit der frequenzeinstellung trotz eurer> zahlreichen erklärungen noch überhaupt nicht.
Weil du an den Formeln klebst und dir nicht klar machst, was da
eigentlich passiert und wie man dann auf die Formeln kommt. Wenn du mit
den Formeln nicht klar kommst, dann lass sie beiseite und überleg was da
eigentlich passiert und was das für die Zahlen bedeutet.
Du musst dir nur klar machen:
Ein Hammer schlägt in einer Stunde 1000 mal auf einen Amboss. Wieviele
Hammerschlägr musst du abzählen, wenn du 6 Minuten warten willst?
Karl heinz Buchegger schrieb:> Ein frischer Mega16 läuft mit 1Mhz.
also ich habe halt makefile (welches ja das avr studio bei mir selber
macht) 8000000 für die frequenz eingetragen. und in dem dialogfenster im
avr studio, von welchem aus man den atmega programmiert hab ich bei der
frequenz auch 8MHZ eingestellt. ich betreibe den atmega ohne externen
quarz.
hätte ich noch irgendwo anders 8MHZ einstellen müssen?
denn ich denke deine einschätzung mit den 125 macht in meinem fall
wirklich sinn. also schaut es wohl so aus als ob mein atmega mit 1MHZ
läuft.
mfg
STK500 anfänger schrieb:> hätte ich noch irgendwo anders 8MHZ einstellen müssen?
Vor allen Dingen musst du deinen Mega16 auf 8 Mhz einstellen.
Eintragen kannst du an diversen Stellen viel. Das beeindruckt den Chip
nicht wirklich.
danke jungs für eure hilfe. hab natürlich in den fusebits noch den
default wert von 1MHZ eingestellt gehabt. jetzt hab ich ihn auf 8MHZ
geändert und jetzt erreiche ich mit einem OCR1A = 999 auch eine
Blinkfrequenz von 0,5 Hz.
ich dachte bisher immer, dass die taktfrequenz nur im makefile
eingestellt werden muss.
mfg