Hallo zusammen,
wie im Betreff schon zugegeben: ich bin ein Newbie.
Und weil ich ein bisschen blöd und zu faul bin, mich mit dem
Fach-Chinesisch in der Programmiersprache auseinanderzusetzen, habe ich
mich (vorerst?) auf LunaAVR eingeschossen - da verstehe ich wenigstens
noch so ein bisschen was ich da scripte.
Nun experimentiere ich ein wenig mit dem Timer1 herum und clonte fix das
Script für eine Uhr.
1
const F_CPU = 4000000
2
const T1_PRESCALER = 64
3
const T1_10MS_TICKS = 625
4
avr.Device = atmega32
5
avr.clock = F_CPU
6
avr.stack = 128
7
8
'******** Ports definieren und mit Aliasen versehen ***********************
Funktioniert. Nach 2 Stunden habe ich keine auffälligen Abweichungen bei
der Uhrzeit.
Aber kaum ergänze ich die Hauptschleife noch um ein bisschen Code, macht
sich ein deutlicher Unterschied von -1sek/Minute bemerkbar.
1
const F_CPU = 4000000
2
const T1_PRESCALER = 64
3
const T1_10MS_TICKS = 625
4
avr.Device = atmega32
5
avr.clock = F_CPU
6
avr.stack = 128
7
8
'******** Ports definieren und mit Aliasen versehen ***********************
Wenn du jetzt noch verraten würdest, was nicht funktioniert, kann an
vielleicht auch versuchen zu helfen.
Du schreibst einen Quelltext hin und sagst: "Wo ist der Fehler?"
Das klingt mir ein wenig nach Bilderrätsel (nur eben mit Quelltext statt
Bild).
Fusel schrieb:> Kann mir bitte jemand in leicht verständlichen Worten erklären, worin> hier der Fehler liegt?
Sieh das Hochzählen der Uhr als eine unteilbare Einheit an.
Sprich: Das Hochzählen der Uhr muss ZUR GÄNZE innerhalb der ISR
durchgeführt werden.
So wie du das jetzt machst, bist du davon abhängig, dass ein Durchlauf
durch deine Hauptschleife im Hauptprogramm nicht länger als 1/10 Sekunde
dauert. Das kann bei Aufwändigeren OPerationen, wie zb dem Aufbereiten
für eine Anzeige schon mal der Fall sein, das das länger dauert. DEINE
Uhr funktioniert nur dann richtig, wenn das nicht der Fall ist.
So rum
1
isr taktung
2
3
Timer1.Value = 0
4
5
zehntels=zehntels+1
6
if zehntels > 99 then
7
zehntels = 0
8
sekunden = sekunden+1
9
if sekunden > 59 then
10
sekunden = 0
11
minuten = minuten+1
12
if minuten > 59 then
13
minuten = 0
14
stunden = stunden+1
15
if stunden > 23 then
16
stunden = 0
17
tag = tag+1
18
wtag = wtag+1
19
endif
20
endif
21
endif
22
endif
23
24
endisr
ist es egal, wie lange dein Hauptprogramm für einen Durchlauf benötigt.
Die Uhr zählt im Zehntelsekundentakt korrekt und ununterbrechbar hoch.
Solange die Interrupts aktiviert sind, verlierst du keine Zeit.
Du magst zwar an der Anzeige eventuell dann eine Zeiterhöhung nicht
sehen, intern wird sie aber registriert und korrekt bearbeitet.
Die Uhrzeit ist ein 'Objekt', welches in seiner Gesamtheit zu betrachten
ist. Sekunden, Minuten, Stunden, etc. gehören zusammen. Behandle sie
auch als solche und vor allen Dingen 'in einem Rutsch'.
PS:
Wenn du ein Datum mitführst, dann muss natürlich auch das innerhalb der
ISR behandelt werden und mit hochgezählt werden. Deinen schlimmsten ISR
Fall hast du daher am 31. Dezember xxxx um 23:59:59 und 9
Zehntelsekunden, wenn sich mit der nächsten Zehntelsekunde dann auch
tatsächlich alle Einzelvariablen ändern. Aber da dies alles in der ISR
geschieht, hast du die Gewissheit, dass da nichts verloren geht und die
interne Zeit auch korrekt weiter läuft. Denn immerhin hast du für die
komplette Operation 1/10 Sekunden Zeit. Mehr als genug Zeit um ein paar
Variablen um jeweils 1 weiter zu stellen.
heisst das eigentlich zehentels. Offenbar handelt es sich hier gar nicht
um Zehntel-Sekunden sondern um Hunderstel.
Mit irreführenden Variablennamen hat sich schon so mancher ins Knie
geschossen.
Ändert aber nichts am Prinzip. Auch 1 Hunderstel-Sekunde ist immer noch
mehr als genug Zeit um 7 Variablen gegebenenfalls um jeweils 1 weiter zu
zählen.
@ich:
ich schrieb:> Wenn du jetzt noch verraten würdest, was nicht funktioniert, kann an> vielleicht auch versuchen zu helfen.> Du schreibst einen Quelltext hin und sagst: "Wo ist der Fehler?"
Hatte ich. Ich muss aber zugeben das vor lauter Quelltext die Frage
schwer zu erkennen war.
@Karl Heinz:
Stimmt, Variablennamen sollten schon eindeutig sein ... ich kenne dies
aus PHP. Versuche ich mir auch hier mal anzugewöhnen.
Danke schon einmal für den ersten Denkansatz. :-)
Hm ... wenn ich Dich richtig verstanden habe, dann muss ich eigentlich
alles, was rechnerisch mit meiner "Uhrzeit" zu tun hat, in die ISR
packen, um keine Zeitsprünge zu erhalten. Aber Auswertungen wie z.B. den
Wochentagen einen Namen zu geben oder eventuell für eine Alarmfunktion
kommt dann in die Hauptschleife?
Wenn ja, dann habe ich die Infos im Netz, die ISR inhaltlich so kurz wie
möglich zu halten, wohl falsch verstanden.
Funktions-Aufrufe sollte ich lieber auch nicht in die ISR setzen, oder?
Gruß
Fusel
Fusel schrieb:> Wenn ja, dann habe ich die Infos im Netz, die ISR inhaltlich so kurz wie> möglich zu halten, wohl falsch verstanden.
so kurz wie möglich bedeutet nicht, dass man gar nichts machen darf.
In deinem Fall ist es vital, dass die Uhrzeit zur rechten Zeit und
vollständig weiter gezählt wird.
Moin,
nun, ich habe mal mehrere Szenarien durchprobiert und komme noch immer
auf keinen grünen Zweig.
1: Alles zeitrechnerisch relevante für die Uhr und das Datum 1:1 in die
ISR verschoben. Die Uhr geht nach wie vor nach bei
-0,010897sek/echtzeitsekunde.
2: Alles in der ISR, was mit dem Datum zu tun hat, auskommentiert.
Wieder geht die Uhr um -0,006111sek/echtzeitsekunde nach.
3: den ISR-Code mit dem Code ersetzt, der hier gestern um 17:55 gepostet
wurde. Meine Atmega-Uhr geht um -0,009333sek/echtzeitsekunde nach.
Natürlich habe ich die Variable "Zehntel" auch umbenannt in
"Hundertstel", da sich darin ja schliesslich die Hundertstel Sekunden
befinden.
Jetzt bin ich mit meinem Latein aber sowas vom am Ende.
Vielleicht die Fuses? Ich habe an dem Atmega32 einen 4Mhz-Quarz (mit
22pF Kondensatoren) entsprechend der Tuts angeschlossen. Beschrieben
wird der µC mit myAVR ProgTool, da sich alles andere nicht wirklich mit
meinem SelfMade-ISP-Adapter verträgt. Und da sind die
Einstellmöglichkeiten aufgrund der riesen Auswahl verwirrend.
Die Fuses sind wie folgt gesetzt:
LowFuse: 0x3F (00111111)
HighFuse: 0xD9 (11011001)
Lockbits: Lasse ich die Griffel von. :P
Gruß
Fusel
Das hier ist doch wohl falsch!
Do
if zehntels > 99 then
zehntels=0
sekunden=sekunden+1
tag=tag+1
wtag=wtag+1
endif
if sekunden > 59 then
sekunden=0
minuten=minuten+1
endif
if minuten > 59 then
minuten=0
stunden=stunden+1
endif
if stunden > 23 then
stunden=0
der Tag zählt jede sekunde hoch!
Fusel schrieb:> Jetzt bin ich mit meinem Latein aber sowas vom am Ende.
Kannst du dein Luna Basic dazu nötigen, den Assembler Code der erzeugten
ISR auszugeben?
Obwohl: so unperformant kann das gar nicht sein, dass ein Inkrementieren
von 7 Variablen derart lange daueren würde.
Fusel schrieb:> if zehntels > 99 then> zehntels=0> sekunden=sekunden+1> tag=tag+1> wtag=wtag+1> endif
Warum Du bei vollen Hundertsteln gleich noch Datum und Wochentag
hochzählst, musst Du mal ertklären.
Fusel schrieb:> isr taktung> zehntels=zehntels+1> Timer1.Value = 0> endisr
Wenn du in der ISR bei Timer.1Value= 0 setzt, hat der Timer eigentlich
schon einige Takte weiter gezählt und Du holst ihn wieder auf Null
zurück. Damit entsteht der Fehler, denn bis zum nächsten INT vergehen
dadurch mehr als 625 Timerticks.
Route 66 schrieb:> Warum Du bei vollen Hundertsteln gleich noch Datum und> Wochentag hochzählst, musst Du mal ertklären.
Ich denke mal, das war ein Test, damit er sieht ob seine Ausgabe
funktioniert, ohne dazu jedesmal einen ganzen Tag warten zu müssen :-)
> Wenn du in der ISR bei Timer.1Value= 0 setzt, hat der Timer eigentlich> schon einige Takte weiter gezählt und Du holst ihn wieder auf Null> zurück. Damit entsteht der Fehler, denn bis zum nächsten INT vergehen> dadurch mehr als 625 Timerticks.
Kommt drauf an, ob sein Luna Basic auch den Teiler des Prescalers zurück
setzt oder nicht.
Karl Heinz schrieb:> Kommt drauf an, ob sein Luna Basic auch den Teiler des Prescalers zurück> setzt oder nicht.
Kann er ja einfach ausprobieren, wenn er einen Autoreload programmiert,
und den Timer nuicht selbst setzt.
Route 66 schrieb:> Wenn du in der ISR bei Timer.1Value= 0 setzt, hat der Timer eigentlich> schon einige Takte weiter gezählt
Daher ist der Clear-On-Compare Modus das Mittel der Wahl.
Oder den Wert bis zum nächsten Compare-Interrupt auf das
Compare-Register addieren.
Also ... das die Wochentage und Tage jede Sekunde mitgezählt werden, war
aus Testzwecken. Habe ich natürlich noch gestern Abend rausgenommen den
Unfug. :-)
Karl Heinz schrieb:> Kannst du dein Luna Basic dazu nötigen, den Assembler Code der erzeugten> ISR auszugeben?
Ich habe mal eine Datei angehangen. Scheint so, als wäre es die
Assembler-Datei von Luna. Allerdings vom gesamten "Script".
Route 66 schrieb:> Wenn du in der ISR bei Timer.1Value= 0 setzt, hat der Timer eigentlich> schon einige Takte weiter gezählt und Du holst ihn wieder auf Null> zurück.
Und wie umgeht man das? Wie gesagt: Ich bin Newbie ... aber lerne gerne
hinzu.
Gruß
Fusel
Sorry für den Nachtrag. Aber ich bemühe mich ja auch und will mir nicht
nur alles vorkauen lassen.
Demnach könnte meine Lösung sein, in dem ich in der ISR
Timer1.Value = 0
rausnehme und stattdessen
Timer1.CmpA.Clear.Enable (Automatisches Nullsetzen des Zählers bei
Gleichheit)
nach der Timer-Inititialisierung notiere?
Fusel schrieb:> Sorry für den Nachtrag. Aber ich bemühe mich ja auch und will mir nicht> nur alles vorkauen lassen.>> Demnach könnte meine Lösung sein, in dem ich in der ISR> Timer1.Value = 0> rausnehme und stattdessen> Timer1.CmpA.Clear.Enable (Automatisches Nullsetzen des Zählers bei> Gleichheit)> nach der Timer-Inititialisierung notiere?
Ja, könntest du machen.
Wenn es da nicht ein Problem gäbe.
Auch das 0-Setzen des Timers ist eine Zählaktion.
Wenn du also einen Compare Match alle zb 180 Timer-Taktzyklen willst,
dann musst du 179 ins Compare Register laden, denn der Schritt von 179
auf 0 ist ja auch eine Zählaktion.
Das geht aber insofern nicht, weil du ja einen Vorteiler von 64 benutzt.
d.h. wenn du einen um 1 kleineren Wert ins Compare Register lädst, dann
verkürzt du den zeitlichen Abstand um 64 Quarz-Takte und nicht nur um
einen.
Gut, das ist jetzt insofern egal, weil dein Quarz ganz sicher nicht
exakt 4000000 Schwingungen pro Sekunde macht, sondern ein wenig mehr
oder weniger.
Allerdings ist eine Abweichung von 1 Hunderstel pro Sekunde viel zu viel
um damit erklärt zu werden. Da stimmt noch was anderes nicht. 0.0093
Sekunden ist um Größenordnungen daneben.
Gibt es im Luna Basic einen Optimizer, den man aktivieren kann?
So richtig berühmt ist das nicht gerade, was der Compiler da draus
macht. Da hat er viel ungenutzt liegen gelassen.
Ich schreibe jetzt erstmal den Compare-mach-null da rein und laß die uhr
auf ein neues laufen. ich müsste dann ja eine trotzdem sehr geringe
zeitabweichung haben.
Im vorliegendem Falle habe ich einen 4Mhz-Quarz. der mit einem Prescaler
von 64 betrieben. Also ergäbe das nach Adam-Riese 62500 Ticks/Sekunde.
Das ganze durch 100 um auf meine Hundertsel Sekunden zu kommen.
Damit würde ich regulär den Compare-Interrupt auf 625 setzen, wenn ich
den Fehler machen wollen würde, den ich jetzt ohnehin im Code habe. Also
setze ich ihn auf 624, damit clear-on-compare seinen einen Tick bekommt,
um das "selbstständige" Zurücksetzen zu ermöglichen ... soweit habe ich
es im theoretischem richtig verstanden?
Karl Heinz schrieb:> Gibt es im Luna Basic einen Optimizer, den man aktivieren kann?
Ich sehe zwar immer, das er etwas optimiert, aber heissen soll das ja
noch lange nix.^^