Forum: Mikrocontroller und Digitale Elektronik Warteschleifen in C für Atmega 8


von noop (Gast)


Lesenswert?

Hallo,

ich suche für einen Atmega8 mit 16Mhz eine Wartschleife weil ich mit 
delay_ms() nicht mehr auskomme leider kriege ich das irgenwie nicht 
gebacken ich will Zeiten zwischen 3s und 300s überbrücken mir ist es 
gegal wenn der AVR in der Zeit nix macht sollte halt relativ genau sein 
( im µs Bereich). Kann mir da jemand helfen?

Schon mal vielen dank!!

Gruß
noop

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?


von Stefan E. (sternst)


Lesenswert?

noop schrieb:

> ich suche für einen Atmega8 mit 16Mhz eine Wartschleife weil ich mit
> delay_ms() nicht mehr auskomme leider kriege ich das irgenwie nicht
> gebacken ich will Zeiten zwischen 3s und 300s überbrücken mir ist es
> gegal wenn der AVR in der Zeit nix macht sollte halt relativ genau sein
> ( im µs Bereich). Kann mir da jemand helfen?

_delay_ms geht bis 65535 Sekunden, allerdings dann nur mit einer 
Genauigkeit von max 100µs. Wozu braucht man bei einem 300s Delay eine 
Genauigkeit im µs-Bereich? Wenn es wirklich so genau sein muss, solltest 
du am besten einen Timer benutzen.

von noop (Gast)


Lesenswert?

100µs wäre noch okay aber _delay_ms geht nur bi 6,5535 Sekunden


Gruß

noop

von Stefan E. (sternst)


Lesenswert?

noop schrieb:
> 100µs wäre noch okay aber _delay_ms geht nur bi 6,5535 Sekunden

Ach ja verdammt, der Punkt ist ja ein Komma.

von noop (Gast)


Lesenswert?

Und wenn ich _delay_ms() in ner for schleife ablaufen lasse hab ich ja 
wieder die Schleifenzeit drin.

von STK500-Besitzer (Gast)


Lesenswert?

Für sowas gibt es Timer.

von noop (Gast)


Lesenswert?

Hallo,


ich blick da noch net so ganz durch also ich hab einen Timer z.b. 8 Bit 
und lass denn mit 16MHz/ 1024 laufen der kann maximal einen Wert von 256 
dann kann der doch bis 0,16384s zählen oder ? und wie komm ich dann auf 
z.b. 300s ?


Gruß noop

von Falk B. (falk)


Lesenswert?

Mit einer Zählvariable in Software.

von noop (Gast)


Lesenswert?

Hallo,

dann hab ich aber doch wieder die Zeit von der Zählerschleife mit 
Variablen drin dann kann ich doch auch _delay_ms en paar tausend mal 
laufen lassen oder ?

von Gast (Gast)


Lesenswert?

Du zählst die Überläufe mit bis du die fragliche Zeit erreicht hast.
Wenn ich nicht ganz daneben liege sind es 16,384ms die du mit dem 8bit 
timer schaffst. Mit einem 16bit Timer wären es schon 4,194s. Bei jedem 
Timeroverflow n+1 while n<x mit x=Wunschzeit/Zähldauer

von Falk B. (falk)


Lesenswert?

@  noop (Gast)

Das macht man so. Stell deinen timer so ein, dass er z.B. mit 100Hz 
einen Interrupt erzeugt, kann man mit dem CTC-Modus spielend 
erreichen. In dem Interrupt wird dann eine Variable hochgezählt. 
Erreicht die dann den gewünschten Wert, wird eine Aktion ausgeführt.

Aber an deiner Frage erkennt man, dass du noch VIIIIIELLE Grundlagen 
durcharbeiten musst, ehe du dort was Gescheites machen kannst.

MFG
Falk

von noop (Gast)


Lesenswert?

mh das merke ich so langsam auch -.-

von Stefan E. (sternst)


Lesenswert?

Zuerst überlegst du dir mal, in welcher Auflösung du deine Delays 
brauchst (nicht zu fein, das ist problematisch, die 100 µs von oben sind 
doch z.B. ein schöner Wert). Dann nimmst du einen Timer, der den 
CTC-Modus beherrscht, und stellst ihn so ein, dass er Interrupts in 
dieser Auflösung produziert. Im Interrupt zählst du einen Wert runter. 
Das Warten ist dann nur ein Warten darauf, dass der Wert Null wird.

Bisschen Pseudocode:
1
volatile Typ_passender_Groesse delay_count;
2
3
ISR () {
4
5
  if (delay_count)
6
    delay_count--;
7
}
8
9
wait (Typ_passender_Groesse delay) {
10
11
  counter auf Null setzen;
12
  delay_count = delay;
13
  while (delay_count)
14
    ;
15
}
16
17
18
wait(3000); // warte 300s

von noop (Gast)


Lesenswert?

Hallo,

wie bekomme ich denn den Timer dazu das der bei 100µs ein Interrupt 
produziert weil ich kann ja z.b. den Timer 16Mhz/8 nehmen also 2 Mhz das 
ergibt dann bei 256 Takten 128µs?


Gruß
noop

von Stefan E. (sternst)


Lesenswert?

Du kannst z.B. den Teiler 64 nehmen, und dann bis 24 zählen lassen. Der 
Timer0 des Mega8 kann aber keinen CTC Modus. Musst dann also Timer2 
nehmen (wenn es ein 8-Bit Zähler sein soll).
Versuche jetzt aber nicht, das bis ins letzte Detail aus mir 
rauszuleiern. Das Stichwort "CTC" ist völlig ausreichend, dass du dir 
das selber zusammensuchen kannst. Im Datenblatt und dem Tutorial gibt es 
haufenweise Infos darüber.

von Sebba (Gast)


Lesenswert?

mal abgesehen davon das das durchaus möglich ist
(und wer weiß wie bekommt das auch im 5 min programmiert)
vermute ich einen Denkfehler bei 300Sek Wait und 100µS Genauigkeit

Erzähl uns doch mal was du vor hast...

Gruß Sven

von noop (Gast)


Lesenswert?

Hallo,

es geht halt darum das eine LED leuchten zu lassen und das halt relativ 
genau und das unterschiedliche Zeiten.

von STK500-Besitzer (Gast)


Lesenswert?

Welches ist denn die kürzeste Zeit?
In welchen Zeitraster soll eingeschaltet werden? Also in welchen 
Intervallen kann man zwischen der oberen und unteren Grenze die Zeit 
einstellen?

von noop (Gast)


Lesenswert?

also ich brauch von 0,4s - 300s in 0,1s Schritten

von STK500-Besitzer (Gast)


Lesenswert?

>also ich brauch von 0,4s - 300s in 0,1s Schritten

Dann kann man den Timer so einstellen, dass er alle 100ms einen 
Interrupt erzeugt, und in der ISR dazu einfach Variablen hoch- oder 
runterzählen.
In der Hauptschleife guckt man dann einfach nach, ob die "Weckzeit" 
erreicht wurde.
Das sollte man sogar mit dem Wissen aus dem Tutorium als "blutiger" 
Anfänger an einem Tag hinbekommen.

von Andreas W. (Gast)


Lesenswert?

Hi

zu deiner Sorge das die Schleifenaufrufe mitzählen.
Das machen sie bei Timer-Interrupts nicht. Der Timer läuft unabhängig 
von der CPU (bis auf die Taktfrequenz). Wenn also die CPU gerade die 
Schleife abarbeitet, läuft der Timer weiter. Kritisch wird es nur wenn 
du zulange im Interrupt bist und der Timer noch einen Interrupt auslöst, 
dieser wird dann übersehen.
In 100µs sollte das aber locker drin sein, baue aber kein Delay ein :-)

von noop (Gast)


Lesenswert?

Hallo,

hab mal was rumgebastelt nur warum kann ich das im AVR Studio nicht 
vernünftig Simulieren wenn ich über den Teil springen will und dahinter 
einen Breakpoint setze dann zeigt der als Stop Watch nur ca 470µs an 
woran liegt das er müsste doch 1s anzeigen

1
OCR2 = 6250;                    // Wenn Timer bis 62500 gezählt hat dann Ereigniss auslösen und clearen
2
   
3
    TCNT2 = 0;                      // Setze Counter auf 0
4
5
    TCCR2 |=(1<<CS22)|(1<<WGM21);            // 16MHz/256 - CTC-Mode
6
7
    loop_until_bit_is_set(TIFR, OCF2);          // warte, bis der Timer angekommen ist
8
9
  TIFR |= (1 << OCF2);                // lösche Output Compate Flag

von Karl H. (kbuchegg)


Lesenswert?

16000000 / 256   ergibt 62500 und nicht 6250

von noop (Gast)


Lesenswert?

oh sry hab mich vertippt müsste OCR2 = 62500; heißen

von Karl H. (kbuchegg)


Lesenswert?

Du hast da anscheinend überhaupt ein Durcheinander.
Timer 2 ist ein 8 Bit Timer!

von Karl H. (kbuchegg)


Lesenswert?

noop schrieb:
> oh sry hab mich vertippt müsste OCR2 = 62500; heißen

Wieso tippst du Programmcode ab?
Copy&Paste und schon hast du diese blöden Tippfehler nicht mehr und wir 
suchen nicht Probleme die du in deinem realen Code gar nichts hast.

von noop (Gast)


Lesenswert?

okay hab jetzt den 1024 teiler genommen kann dass es daran liegt das der 
Compiler mir ne Fehlermeldung rausgibt: warning: large integer 
implicitly truncated to unsigned type

1
OCR2 = 15625;                    // Wenn Timer bis 15625 gezählt hat dann Ereigniss auslösen und clearen
2
   
3
    TCNT2 = 0;                      // Setze Counter auf 0
4
5
    TCCR2 |= (1<<CS20)|(1<<CS22)|(1<<WGM21);      // 16MHz/15625 - CTC-Mode
6
7
    loop_until_bit_is_set(TIFR, OCF2);          // warte, bis der Timer angekommen ist
8
9
  TIFR |= (1<<OCF2);                  // lösche Output Compate Flag

von Karl H. (kbuchegg)


Lesenswert?

noop schrieb:
> okay hab jetzt den 1024 teiler genommen kann dass es daran liegt das der
> Compiler mir ne Fehlermeldung rausgibt: warning: large integer
> implicitly truncated to unsigned type


Der Hinweis des Compilers ist schon nicht schlecht.

Timer 2 ist ein 8 Bit Timer. In 8 Bit passt nichts größeres rein als 
255. Wie willst du daher 15625 in 8 Bit unterbringen? Dazu musstest du 
mindestens über 14 Bits verfügen, die du aber nicht hast

von noop (Gast)


Lesenswert?

ich dachte der timer 2 ist ein 16 bit Timer?

von Karl H. (kbuchegg)


Lesenswert?

noop schrieb:
> ich dachte der timer 2 ist ein 16 bit Timer?

Im Zweifelsfall hilft immer: Datenblatt lesen
Und auch im Nichtzweifelfall ist Datenblatt lesen immer eine gute Idee.

von noop (Gast)


Lesenswert?

okay :-) also nehm ich dann mal Timer 1 :-) pack ich den timer jetzt in 
eine For-Schleife und lass die dann entsprechend ausführen oder wie 
mache ich das am besten um auf die gewünschte Zeit zu kommen ?

von Karl H. (kbuchegg)


Lesenswert?

noop schrieb:
> okay :-) also nehm ich dann mal Timer 1 :-) pack ich den timer jetzt in
> eine For-Schleife und lass die dann entsprechend ausführen

Das Prinzip, das du benutzt hast, kannst du ja weiterbenutzen (Das Flag 
aber auch löschen ehe du den Timer startest. Kein Mensch garantiert dir, 
dass das zurückgesetzt ist). Du bist nur darüber gestolpert, dass Timer 
2 nicht so weit zählen kann, wie du es brauchen würdest.

> oder wie
> mache ich das am besten um auf die gewünschte Zeit zu kommen ?

Das kommt immer darauf an, wie genau die die Zeit brauchst.
Im einfachsten Fall lässt man sich von einem Timer einen periodischen 
Interrupt auslösen und zählt in der ISR eine Uhr hoch. Frei nach dem 
Motto: Wenn ich 10 mal 1 Sekunde gewartet habe, hab ich in Summe auch 10 
Sekunden gewartet.

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.