mikrocontroller.net

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


Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Tim T. (tim_taylor)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: noop (Gast)
Datum:

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


Gruß

noop

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: noop (Gast)
Datum:

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

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für sowas gibt es Timer.

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit einer Zählvariable in Software.

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mh das merke ich so langsam auch -.-

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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:

volatile Typ_passender_Groesse delay_count;

ISR () {

  if (delay_count)
    delay_count--;
}

wait (Typ_passender_Groesse delay) {

  counter auf Null setzen;
  delay_count = delay;
  while (delay_count)
    ;
}


wait(3000); // warte 300s

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sebba (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

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

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: noop (Gast)
Datum:

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

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

OCR2 = 6250;                    // Wenn Timer bis 62500 gezählt hat dann Ereigniss auslösen und clearen
   
    TCNT2 = 0;                      // Setze Counter auf 0

    TCCR2 |=(1<<CS22)|(1<<WGM21);            // 16MHz/256 - CTC-Mode

    loop_until_bit_is_set(TIFR, OCF2);          // warte, bis der Timer angekommen ist

  TIFR |= (1 << OCF2);                // lösche Output Compate Flag


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
16000000 / 256   ergibt 62500 und nicht 6250

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oh sry hab mich vertippt müsste OCR2 = 62500; heißen

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast da anscheinend überhaupt ein Durcheinander.
Timer 2 ist ein 8 Bit Timer!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

OCR2 = 15625;                    // Wenn Timer bis 15625 gezählt hat dann Ereigniss auslösen und clearen
   
    TCNT2 = 0;                      // Setze Counter auf 0

    TCCR2 |= (1<<CS20)|(1<<CS22)|(1<<WGM21);      // 16MHz/15625 - CTC-Mode

    loop_until_bit_is_set(TIFR, OCF2);          // warte, bis der Timer angekommen ist

  TIFR |= (1<<OCF2);                  // lösche Output Compate Flag


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich dachte der timer 2 ist ein 16 bit Timer?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: noop (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.