Forum: Mikrocontroller und Digitale Elektronik verzögerung mit CTC


von Stk 500 anfänger (Gast)


Lesenswert?

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_t intcounter;
10
11
12
ISR(TIMER0_COMP_vect)
13
{
14
15
intcounter++;
16
17
18
}
19
20
21
22
void verzoegerung(uint16_t ms)
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
int main(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
return 0;
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

von holger (Gast)


Lesenswert?

volatile uint16_t intcounter;

von Stk 500 anfänger (Gast)


Lesenswert?

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

von Stk 500 anfänger (Gast)


Lesenswert?

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
volatile uint16_t intcounter;
10
11
12
ISR(TIMER0_COMP_vect)
13
{
14
15
intcounter++;
16
17
18
}
19
20
21
22
void verzoegerung(uint16_t ms)
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
int main(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
return 0;
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

von Floh (Gast)


Lesenswert?

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. :-)

von Stk 500 anfänger (Gast)


Lesenswert?

jetzt hab ich es nochmal überarbeitet:
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
volatile uint16_t intcounter;
10
11
12
ISR(TIMER0_COMP_vect)
13
{
14
15
intcounter++;
16
17
18
}
19
20
21
22
void verzoegerung(uint16_t ms)
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
int main(void)
44
{
45
46
DDRB |= (1<<PB1);    // PB1 als Ausgang
47
48
49
TIMSK |= (1<< OCIE0);  //Interrupt bei Compare Match
50
51
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
return 0;
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

von Floh (Gast)


Lesenswert?

halbier mal deinen ocr0 wert :-)
-> try and error Prinzip zum Testen

von Floh (Gast)


Lesenswert?

ansosnten vielleicht mal das Nullsetzen von intcounter vor die 
while-Schleife? Erscheint für mich logischer, wobei es eigentlich egal 
sein sollte :-)

von Stk 500 anfänger (Gast)


Lesenswert?

jetzt hab ich mal OCR0 = 248 gesetzt. aber irgendwie ändert das an der 
blinkdauer gar nichts. versteh ich jetzt irgendwie auch nicht.

von Stk 500 anfänger (Gast)


Lesenswert?

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.

von Floh (Gast)


Lesenswert?

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?

von Stk 500 anfänger (Gast)


Lesenswert?

ja das habe ich schon gemacht. auch die richtige frequenz hab ich 
eingestellt.

von holger (Gast)


Lesenswert?

> 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.

von Stk 500 anfänger (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von AVR (Gast)


Lesenswert?

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

von Stk 500 anfänger (Gast)


Lesenswert?

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
volatile uint16_t intcounter;
10
11
12
ISR(TIMER1_COMPA_vect)
13
{
14
15
intcounter++;
16
17
18
}
19
20
21
22
void verzoegerung(uint16_t ms)
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
int main(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
return 0;
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

von Stk 500 anfänger (Gast)


Lesenswert?

...............................................

von Karl H. (kbuchegg)


Lesenswert?

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?

von STK500 anfänger (Gast)


Lesenswert?

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

von helper (Gast)


Lesenswert?

hast Du denn die Fuses auch auf intern 8MHZ gestellt? und auch 
programmiert?

helper

von Karl H. (kbuchegg)


Lesenswert?

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.

von Stk 500 anfänger (Gast)


Lesenswert?

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

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.