Forum: Compiler & IDEs Frage zur "genauen Sekunde"


von baeri3 (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe leider ein "kleines" Problem mit der "genauen Sekunde".
Habe diese aus dem WIKI rauskopiert, bekomme es aber leider im
AVR-Simulator nicht gescheit zum laufen.
Der PORTB sollte eigentlich die Sekunde im Bin-Wert ausgeben,
aber wie es scheint, wird der Timer-IRQ nur einmal ausgeführt,
denn wenn ich dort den PORTB auf 0xFF setze, ist dieser auch HIGH.
Habe ich irgendwo einen Fatalen Fehler gemacht?

Danke für eure Hilfe!

von Timmo H. (masterfx)


Lesenswert?

Also ich habe es immer so gemacht:
1
#include <avr/io.h> 
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
#define TIMER_VALUE 34286 /* Bei 16MHz und prescaler von 256 => 500ms
6
Int. */
7
8
ISR(TIMER1_OVF_vect){
9
  timercount++;
10
  TCNT1 = TIMER_VALUE;
11
  /* Hier könntest du dann was ausgeben */
12
}
13
14
int main(void){
15
16
  TCCR1A = 0x00;        /* kein PWM usw. */
17
  TCCR1B |= (4<<CS10);  /* Prescaler = 256 */
18
  TCNT1 = TIMER_VALUE;  /* => erzeugt alle 500ms nen Int. */
19
  TIMSK |= (1 << TOIE1);
20
  sei();
21
  while(1);
22
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Die Overflow-Methode sollte man vermeiden, wenn immer möglich.
Sie ist prinzipbedingt mit Unsicherheiten und Jitter durch die
Interruptlatenz behaftet.  Bis auf ganz wenige Ausnahmen hat der
Timer 1 doch überall einen CTC-Modus, den man benutzen kann.
(Bei neueren AVRs hat Timer 0 diesen Modus auch.)

von Timmo H. (masterfx)


Lesenswert?

Mhh, wusste ich nicht. Aber was sollte der Comparemodus daran ändern?
Der Zähler ist der selbe, Takt ist auch gleich. Und wenn ich das mal so
über nen Tag messe, kann ich eigentlich keine Ungenauigkeit feststellen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Aber was sollte der Comparemodus daran ändern?

Dass das Rücksetzen des Zählers in der Hardware erledigt
wird und damit unabhängig von der Interruptlatenz erfolgt.
Einen Interrupt kannst du dir ja dennoch generieren lassen
(damit du auch erfährst, dass jetzt wieder Zeit vergangen
ist), aber die Latenz in der Interruptannahme spielt dann
keine Rolle mehr; dein Programm erfährt zwar u. U. erst etwas
später, dass es jetzt später geworden ist, der Zähler hat es
aber schon vorher erfahren und kann weiterzählen.

von Timmo H. (masterfx)


Lesenswert?

Stimmt leutet ein, danke für die Info.

von leo9 (Gast)


Lesenswert?

im Prinzip hat Jörg mit den Latenzzeiten schon recht, aber man sollte
auch die Auswirkungen auf die Applikation betrachten.

In diesem Beispiel würde der Fehler
365  24  60  60  62,5 ns = +1,97 Sek pro Jahr ausmachen (unter der
Annahme dass der int immer bei 2-zyklischen Befehlen zuschlägt,
statistisch wird er auch etliche 1-zyklische erwischen und der Fehler
wird kleiner).

Steht kein CTC Mode zur Verfügung und der Prescaler ist groß genug
könnte auch ein TCNT = TCNT + VALUE helfen, dann muß man nur aufpassen
dass man das "Prescaler-Fenster" erwischt, ab pres > 1:16 sollte das
aber kein Problem sein.

Wenn es auf absolute Genauigkeit ankommt könnte man auch einen
"Vorinterrupt" generieren der GIE per SW enabled und eine Folge von
nops startet, dann unterbricht der echte Interrupt jedenfalls einen
1-zyklischen Befehl und der Fehler der Latenzzeit reduziert sich auf -0
bis +1 Taktzyklus.

Eine weitere Möglichkeit wäre den up schlafen zu lassen, dann ist die
Latenzzeit ebenfalls konstant.

grüße leo9

von peter dannegger (Gast)


Lesenswert?

@leo9,

die Interruptlatenz ist vielleicht nicht so erheblich, aber man hat ja
noch andere Interuptquellen oder Programmabschnitte unter
Interruptsperre und dann gibt es schon erhebliche Verzögerungen.

Der AVR hat ja keine Prioritäten, wenn also ein anderer Interrupt z.B.
1ms dauert, wird Deine RTC-Routine so lange verzögert.


Peter

von Wolfram (Gast)


Lesenswert?

Nicht nur im Prinzip hat Jörg recht

gewöhnlich sieht die ISR Routine so aus

(volatile unsigned char timercount;)
ISR(TIMER1_OVF_vect){
timercount++;
//tue evt. noch was
TCNT1 = TIMER_VALUE;
}

da kommen noch 4 Takte eintritt in den Interrupt hinzu
+ push der benötigten Register ca. x*3 Takte
+ code bis TCNTx = Timervalue =x Takte

wenn man die Suchfunktion dieses Forums benutzt kann man die
Auswirkungen hervoragend nachvollziehen. Dabei steht schon im
Datenblatt der Hinweis.

von Manuel B. (baeri3)


Lesenswert?

Danke für die Zahlreichen Hinweise...
Ich dachte eiegntlich dass die Lösung die ich verwendet habe
In Ordnung sei, da diese aus einem Articel von hier stammt:

http://www.mikrocontroller.net/articles/AVR_-_Die_genaue_Sekunde_/_RTC

Evt. sollte diesen jemand überarbeiten, und die hier Diskutieren
Anhaltspunkte miteinbeziehen.

von peter dannegger (Gast)


Lesenswert?

@Manuel,

die Kommentare beziehen sich nur auf den Code von Timmo.

Dein Code benutzt ja das Compareregister.

Warum er bei Dir nicht funktioniert, könnte daran liegen, daß Du den
falschen AVR-Typ angegeben hast, dann zeigen die Interrupts in den
Wald.


Peter

von Manuel B. (baeri3)


Lesenswert?

Hi Peter,

danke für die Info.

Also ich verwende einen Mega8 und habe diesen auch im Simulator
ausgewählt. Der Code sollte wie er ist ja auf einem Mega8 laufen,
oder liege ich da falsch?

von Manuel B. (baeri3)


Lesenswert?

Hallo nochmals,

also die Interrupt Vektoren für den Mega8 stimmen mit denen in dem
Code Sample überein.
Die initialisierung der Register und Compare-Werte stammen ja aus dem
Artikel (s.O.), sollten somit auch stimmen.
Ist dies evt. ein Problem mit dem Simulator aus dem AVR-Studio?

von peter dannegger (Gast)


Lesenswert?

Zum Simulator kann ich nichts sagen, ich teste immer im real-life, z.B.
aufm STK500.


Peter

von Karl H. (kbuchegg)


Lesenswert?

Also in meinem AVR-Studio Simulator funzt das Ganze
einwandfrei.

von Manuel B. (baeri3)


Lesenswert?

Eigenartig... Evt. mach ich da ja irgendwo einen fatalen Fehler!?
Ich bin bisher einfach ins AVR-Studio und dann habe ich direkt über
File -> Open File das Hex-File geladen. Danach kann man Ihm ja dann
noch
den AVR Typ angeben, da habe ich natürlich den Mega8 ausgewählt.
Und dann gehts ja schon los.
Im I/O View Window sehe ich auch, dass der DDRB usw. richtig gesetzt
wird und auch der Timer schön hoch zählt.

Ich habe gerade noch auf die Version 4.12 mit SP2 geupdatet.

von Manuel B. (baeri3)


Lesenswert?

Hey, es scheint nun doch zu funktioneren.
Sorry für die Umstände! Werde es demnächst noch in Real-Life testen..

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.