PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Uhr an Timer2 vom Atmgea32 bei 16.000.000Hz



Dominik009
19.12.2013, 19:38
Hallo Zusammen,
ich brauche für ein neues Projekt eine Uhr auf meinem Mega32.
Timer 1 ist leider schon belegt, bzw. wird später für ne andere Funktion gebraucht, wozu ich einen 16 Bit Timer brauche.

Daher kommt eigentlich nur Timer 2 in Frage. Der Mega32 ist auf der RN-Control und hat nen 16000000Hz Quarz.

Nun habe ich mir überlegt, ich teile 16000000 erstmal durch 256 (Prescale). Dann komme ich auf 62500.
Ich lasse meinen 8 Bit Timer von 5 an zählen, so komme ich auf 250 Schritte, also 62500/250= 250.

Jetzt erstelle ich eine Variable die ich in der ISR von Timer 2 um 1 erhöhe.
Zusätzlich wird hier der Timer wieder auf 5 gestellt.

In meiner normalen Do Loop schleife lasse ich jetzt sobald die Variable auf 250 ist sie zurück auf 0 setzen und erhöhe meine Sekunden um 1.

Dann noch über ein paar If Than befehle bei 60s zurück auf 0 und die Minuten +1.

Das läuft alles soweit gut, nur bekomme ich extreme Abweichungen. Der Mega32 hängt pro Minute mehrere Sekunden hinter der Zeit. Woran kann das liegen?

Ich programmiere auf nem alten 95 Rechner ohne Internet, daher ist es schwer den Code hier rein zubekommen, werde ihn aber versuchen morgen auf cd zu brennen und dann hier reinzustellen :)


Ich hoffe ihr versteht mein Probelem und könnt mir helfen :D

Viele Grüße
Dominik

PICture
19.12.2013, 20:13
Hallo!


Der Mega32 hängt pro Minute mehrere Sekunden hinter der Zeit. Woran kann das liegen?

Es liegt sicher an zu langer und variabler Ausführungszeit der ISR.

Hardware-Entwickler
19.12.2013, 20:15
Mein Vorschlag:
- Prescaler von 1024 verwenden, daraus ergibt sich eine Frequenz von f_Timer = 15625 Hz
- CTC Mode benutzen, Timer Compare Match bei OCR2 = 125-1
- TIMER2_COMP Interrupt aktivieren, die ISR wird nun 125mal die Sekunde aufgerufen
- in der ISR eine Variable inkrementieren, und bei 125 zurücksetzen und eine Minute ist um

Dominik009
20.12.2013, 01:25
Hallo,
An der ISR kann es natürlich liegen, das wird es auch wahrscheinlich sein.
leider verstehe ich die Idee vom Hardware-Entwickler nicht so ganz.prescaler auf 1024 ok, aber weiter???

Was bedeutet ctc bei orc2 = 125-1?
Und was genau meinst du mit timer2_comp interrupt?

Hättest du oder vielleicht wer anders ein paar Zeilen Code die das zeigen?


Im ctc Modus errechne ich ja den Vergleichswert wie folgt:
Quarz-Frequenz/prescaler/2/gewünschte-frequenz

Bei mir also 16000000/1024/2/1 = 7812,5 also zu groß für nen 8 Bit timer
was meinst du mit 125-1?


Viele grüße
Dominik

oberallgeier
20.12.2013, 08:57
...
- TIMER2_COMP Interrupt aktivieren, die ISR wird nun 125mal die Sekunde aufgerufen
- in der ISR eine Variable inkrementieren, und bei 125 zurücksetzen und eine Minute ist umDie Minute hat bei mir 60 Sekunden. Ist ja egal, da zählt man eben weiter wenns bis zur Minute reichen soll; nur das ist dann der Unterschied zwischen unit8_t und uint16_t.

for_ro
20.12.2013, 09:33
Hallo Dominik,
deine Lösung und die von Hardware-Entwickler liegen von der Berechnung her nicht weit auseinander.
Bei dir: Prescale 256, Timer läuft nach 250 Ticks über, Zähler läuft bis 250 == 256 * 250 * 250 = 16M
Bei ihm: Prescale 1024, Timer matched nach 125 Ticks, Zähler läuft bis 125 == 1024 * 125 * 125 =16M
Seine ISR wird nur halb so oft pro Sekunde aufgerufen, verbraucht also weniger Prozessorzeit.

Wichtiger ist der Unterschied mit CTC Mode und Timer vorladen. Bei deiner Art bist du in Teilen von der Ausführungszeit der ISR abhängig. Speziell bei kleinen Prescale Werten ergeben sich dadurch signifikante Abweichungen.
Anders der CTC Mode. Der Timer läuft praktisch komplett in HW, inklusive Zurücksetzen. In der ISR änderst du nichts am Timer.
Leider wird deine Art in allen Tutorials, Foren und auch in der Bascomhilfe immer als erstes gezeigt und scheint auch besser verständlich zu sein. Aber ich würde dir raten, grundsätzlich darauf zu verzichten.

Der CTC Modus funktioniert in Bascom so:
Config Timer2 = Timer, Prescale = 1024, Clear_Timer=1, Compare = Toggle
Compare2 = 124 '125 Ticks, weil der Timer bei 0 anfängt (deshalb 125 - 1), du kannst auch OCR2 = 124 schreiben
On Compare2 Timer_Isr
Enable Compare2

Allerdings glaube ich nicht, dass dadurch mehrere Sekunden pro Minute zu erklären sind.
Zeig doch mal dein ganzes Programm.

wkrug
20.12.2013, 11:56
Was bedeutet ctc bei orc2 = 125-1?
Und was genau meinst du mit timer2_comp interrupt?
Ich denke das Problem sind hier die Begrifflichkeiten.
CTC bedeutet Clear Timer at Comparematch und heisst, wenn das entsprechende TCNT Register den Wert des Comparematchregisters erreicht wird es in der Hardware sofort wieder auf 0 gesetzt. Beispiel Comp 2 Register hat den Wert 127, TCNT2 erreicht 127 und wird sofort auf 0 gesetzt.

zu 2. So ein Timer kann nicht nur bei einem Überlauf einen Interrupt produzieren, sondern auch wenn das TCNT Register den Wert eines Comparematchregisters erreicht. Dadurch hat man bei der Wahl der Prescaler mehr Möglichkeiten den gewünschten Teilerfaktor zu erreichen.

Grundsätzlich bevorzuge ich große Prescaler, weil sich damit normalerweise eher seltener Interruptaufrufe ergeben.

Wenn dein 16 Bit Timer frei läuft kannst Du sogar dort noch deine Uhr mit einbauen.

Du gibst dort den Comparematch Interrupt frei und zählst zum Comparematchregister innerhalb dieses Interrupts den Wert für den nächsten Zeitabschnitt dazu.
Dadurch kommt es immer wieder zu festen Zyklen zu einem Comparematch Interrupt.

Zusätzlich würde ich Dir empfehlen eine zusätzliche Vergleichs- " Uhr " wie eine Real Time Clock ( RTC ) oder DCF 77 als Vergleich zu benutzen, weil sonst Deine Uhr nach längerer Zeit falsch gehen wird. Die Zeitbasis ist ja vom Controllerquarz abhängig, der auch nich zu 100% genau ist.

Dominik009
20.12.2013, 13:30
Hallo,
erstml danke für die zahlreichen Antworten.
bessere Grade den Code aus, doch leider nimmt er die Zeile:
On Compare2 ISR_von_timer2 nicht an (error 117)

Kann ich anstelle von compare2 auch timer2 schreiben?

Gruß
Dominik

for_ro
20.12.2013, 13:45
Hallo,
erstml danke für die zahlreichen Antworten.
bessere Grade den Code aus, doch leider nimmt er die Zeile:
On Compare2 ISR_von_timer2 nicht an (error 117)

Kann ich anstelle von compare2 auch timer2 schreiben?

Gruß
Dominik
Nein, der Timer2 Interrupt ist bei Bascom der OVF2, also der Überlauf. Du brauchst den Compare.
Du verwendest einen Mega32, richtig? Welche Bascom Version hast du?

Dominik009
20.12.2013, 13:47
Jo, ich hab nen mega32 und bascom 1.11.9.0

for_ro
20.12.2013, 13:49
Du weißt schon, dass aktuell die Version 2.0.7.6 raus ist, also 3 Generationen weiter.

Dominik009
20.12.2013, 13:50
Ich habe den Code jetzt trotz des angeblichen Fehlers geflasht. Nun macht mein Controller (oder ein anderes Bauteil) extrem merkwürdige Geräusche (so eine Art brummen).

Werde gleich den stark vereinfachten Code mal versuchen hier ins Board zu bekommen.

Viele grüße
Dominik

Edit: Oh, das wusste ich nicht. Sollte ich die. Erosion updaten?
Bisher hatte i h nämlich nie Probleme mit der Version

for_ro
20.12.2013, 13:54
Nimm mal anstelle von Compare2 OC2, das geht.

- - - Aktualisiert - - -



Edit: Oh, das wusste ich nicht. Sollte ich die. Erosion updaten?
Bisher hatte i h nämlich nie Probleme mit der Version
Würde ich definitiv machen, sonst läufst du immer wieder in solche Situationen, wo dir alle sagen, dass es bei ihnen läuft.

Dominik009
20.12.2013, 14:16
Ok, bascom meldet keinen Fehler mehr. Irrlicht sollte ich trozdem bald mal updaten.

Sobald das Programm auf dem mega32 ist fängt der laut an zu Brummen (zumindest glaube ich, dass du Brummen. Im Mega kommt). Irgendwas ist da falsch.

- - - Aktualisiert - - -

So, hier ist mal der Code. Hab ihn auf ne CD gebrannt und jetzt von nem anderen Rechner hochgeladen:




$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 16000000
$baud = 9600


' Variablen für die Uhrzeit
Dim Hilfswert_sekunden As Byte
Dim Sekunden As Byte
Dim Minuten As Byte
Dim Stunden As Byte
Dim Wochentag As Byte
Wochentag = 1



Led Alias Portc.0
Config Led = Output

Dim Z As Single
Dim I As Long
Dim N As Integer
Dim Ton As Integer



' Timer 2 für die Uhrzeit einstellen und starten
Config Timer2 = Timer , Prescale = 1024 , Clear_timer = 1 , Compare = Toggle
Compare2 = 124
On Oc2 Isr_von_timer2:

Enable Compare2


'Enable Timer2
'On Timer2 Isr_von_timer1
'Enable Interrupts
'Load Timer2 , 250
'Start Timer2





I = 0
Sound Portd.7 , 400 , 450 'BEEP
Sound Portd.7 , 400 , 250 'BEEP
Sound Portd.7 , 400 , 450 'BEEP
Print
Print "**** RN-CONTROL 1.4 *****"
Print "Das neue Experimentier- und Roboterboard"
Print "Weitere passende Zusatzboards bei www.robotikhardware.de"
Print



Do



If Hilfswert_sekunden = 125 Then
Print ; Wochentag ; " - " ; Stunden ; ":" ; Minuten ; ":" ; Sekunden ; ""
Incr Sekunden
Hilfswert_sekunden = 0
Toggle Led
End If

If Sekunden = 60 Then
Sekunden = 0
Incr Minuten
End If

If Minuten = 60 Then
Minuten = 0
Incr Stunden
End If

If Stunden = 24 Then
Stunden = 0
Incr Wochentag
End If

If Wochentag = 8 Then
Wochentag = 1
End If



Loop




' Funktion die mit Timer 2 verbunden ist
' Ist nötieg um aktuelle Uhrzeit auszugeben
Isr_von_timer2:
Incr Hilfswert_sekunden




Return

End

for_ro
20.12.2013, 14:40
Hallo Dominik,
der Lautsprecher brummt, weil du den an PortD.7 dran hast, wo auch das Signal OC2 raus kommt. Und das hat 62Hz.
Da du den Ausgang aber gar nicht benötigst, konfiguriere den Timer so:
Config Timer2 = Timer , Prescale = 1024 , Clear_timer = 1
Außerdem fehlt bei dir das globale Freigeben der Interrupts
Enable Interrupts

Dominik009
20.12.2013, 14:44
Ok, werde ich gleich machen. Mit dem Lautsprecher hast dur recht, da hab ich jetzt gar nicht dran gedacht-
Und nochmal vielen Dank für die Hilfe.

Das Compare = Toggle kann ich dann bei der Timerkonfiguration weglassen, oder?

Es sollte dan so aussehen:

' Timer 2 für die Uhrzeit einstellen und starten Config Timer2 = Timer , Prescale = 1024 , Clear_timer = 1 Compare2 = 124 On Oc2 Isr_von_timer2
Enable Interrupts


Ich werde das ganze gleich mal testen gehen

Viele Grüße
Dominik

for_ro
20.12.2013, 15:05
Ich habe dir hier mal eine leicht modifizierte Version angehangen. Die läuft sicherer, besonders wenn dein Programm mal größer wird. Schau dir die Unterschiede mal an und überlege, was sie bewirken.

$regfile = "m32def.dat"
$framesize = 40
$swstack = 32
$hwstack = 32
$crystal = 16000000
$baud = 9600


' Variablen für die Uhrzeit
Dim Hilfswert_sekunden As Byte
Dim Sekunden As Byte
Dim Minuten As Byte
Dim Stunden As Byte
Dim Wochentag As Byte
Wochentag = 1

Led Alias Portc.0
Config Led = Output

Dim Z As Single
Dim I As Long
Dim N As Integer
Dim Ton As Integer
Dim Sekunden_flag As Bit


' Timer 2 für die Uhrzeit einstellen und starten
Config Timer2 = Timer , Prescale = 1024 , Clear_timer = 1 ', Compare = Toggle
Compare2 = 124
On Compare2 Isr_von_timer2
Enable Compare2

I = 0
Sound Portd.7 , 400 , 450 'BEEP
Sound Portd.7 , 400 , 250 'BEEP
Sound Portd.7 , 400 , 450 'BEEP
Print
Print "**** RN-CONTROL 1.4 *****"
Print "Das neue Experimentier- und Roboterboard"
Print "Weitere passende Zusatzboards bei www.robotikhardware.de"
Print

Enable Interrupts 'normalerweise erst kurz vor der Hauptschleife
Do
If Sekunden_flag = 1 Then 'jetzt hast du eine Sekunde Zeit für alles zu verarbeiten
Reset Sekunden_flag
Print ; Wochentag ; " - " ; Stunden ; ":" ; Minuten ; ":" ; Sekunden ; "" 'sonst könnte es hier schon knapp werden
Incr Sekunden
Toggle Led
If Sekunden = 60 Then
Sekunden = 0
Incr Minuten
If Minuten = 60 Then
Minuten = 0
Incr Stunden
If Stunden = 24 Then
Stunden = 0
Incr Wochentag
If Wochentag = 8 Then
Wochentag = 1
End If
End If
End If
End If
End If
Loop

End

' Funktion die mit Timer 2 verbunden ist
' Ist nötieg um aktuelle Uhrzeit auszugeben
Isr_von_timer2:
Incr Hilfswert_sekunden
If Hilfswert_sekunden = 125 Then
Hilfswert_sekunden = 0
Set Sekunden_flag
End If
Return

ihle
20.12.2013, 18:48
Hallo Dominik009,

Timer2 ist optimal für einen Uhrenquarz an TOSC1 und TOSC2,
du teilst den Takt durch 128 gibt den OVL Interrupt frei und lässt den Timer einfach loslaufen
und bei jedem Überlauf wird ein Interrupt ausgelöst und 1 Sekunde ist abgelaufen du musst nur eine Variable incrementieren.
Ich muss dazu sagen ich mache sowas immer im Assembler, ich weis nicht wie sich die Laufzeiten in Bascom verlängern.
Mehr info findest du im Datenblatt unter Timer2.

nfg ihle

Dominik009
20.12.2013, 19:07
Vielen Dank für den Code!
Auch vielen Dank für den Tipp mit dem Quarz. Kann ich den weiterhin den normslen 16000000hz Quarz nehmen und den Uhrenabsatz zusätzlich? Werde ich bei meinem nächsten Projekt mal testen, habe jetzt leider keinen passenden Quarz und extra einen einzeln bestellen ist auch blöd ;)


@for_ro,
Das Programm läuft dank deinem code, jedoch zu langsam.
Ich würde sagen, gefühlt läuft sie etwa halb so langsam wie ne richtige Uhr, also +eine Sekunde auf dem Mega sind +2 Sekunden in echt :(
woran kann das liegen?

Wenn ich richtig rechne stimmt im Code evtl. Was nicht.
16000000/1024/2/125 = 62,5
also muss ich entweder in die ISR 62,5 packen, was logischerweise nicht geht.

Also muss 62,5-1=61,5
und das ändert an der Geschwindigkeit der Uhr leider nichts :(

Gruß
Dominik

for_ro
20.12.2013, 19:24
Hallo Dominik,
bist du sicher, dass dein Controller von einem 16MHz Quarz angetrieben wird und nicht vom internen 8MHz Oscillator?

Dominik009
20.12.2013, 19:42
Abend for_ro,
jo Fusebit KLA987 steht auf 011110 ext. Crystal/resonator High Frequenz ; Start-up Time 258 CK + 64 ms ; (CKSEL=1110 SUT=01)

Sollte ja so stimmen, oder?

Viele Grüße
Dominik

ihle
20.12.2013, 20:28
Hallo Dominik,


Kann ich den weiterhin den normslen 16000000hz Quarz nehmen und den Uhrenabsatz zusätzlich?

Ja, du musst sogar den normalen 16 MHz Quarz nehmen, denn der ist für deinen Systemtakt zuständig der Uhrenquarz hängt nur
an Timer2 und taktet deine Uhr.

mfg ihle

Dominik009
20.12.2013, 20:34
Das klingt ja nichtmal schlecht. Ich möchte jedoch erstmal die Uhr ohne Uhrenquarz zum laufen bringen. Der Code von for_ro läuft ansich gut, ist halt nur zu langsam. Der externe Quarz sollte wie ich oben geschrieben habe ja aktiviert sein, oder? Es gibt da so viele Varianten zum auswählen, ich hoffe die oben ist richtig.

Bei meinem nächsten Projekt werde ich dann auch nen Uhrenquarz an den Mega anschließen. Werde dann mal testen welche Uhr genauer läuft, aber dazu müsste meine Aktuelle erstmal laufen :(

Ich finde einfach den Fehler nicht, aber nach meiner berechnung müsste beim Timer anstelle von 125, 61.5 hin, das bringt aber auch keine verbesserung :(

Viele Grüße
Dominik

for_ro
20.12.2013, 22:31
Hallo Dominik,
ich habe das Programm mal auf einen Mega32 gebrannt. Bei mir kommt die Printausgabe exakt jede Sekunde.
Evtl liegt es an deiner alten Bascom Version. Ich habe zwar noch die 1.11.9.0, aber mein USB Brenner funktioniert damit nicht.
Wenn du eine aktuelle Version installieren kannst, dann würde ich mal auf die neueste gehen. Aber lass deine alte zur Sicherheit liegen.
Du wirst bemerken, dass einige deiner Programme nicht mehr mit der neuen Version kompilieren.

Hauptvorteil von dem zusätzlichen Uhrenquarz ist deren höhere Genauigkeit. Normale Quarze haben eine Abweichung von bis zu 100ppm, während die 32KHz Quarze in der Gegend von 30ppm liegen.
Du findest sie übrigens in jeder Quarzuhr. Also wenn du eine kaputte rumliegen hast, kannst du ihn dort auslöten.
Dir gehen dann zwei IOs verloren, aber das lässt sich bei einem M32 häufig auch verkraften.
Wieso müsste nach deiner Berechnung dort 61,5 hin? Nach deiner Beobachtung der tatsächlichen Ausführungszeiten?

- - - Aktualisiert - - -

So, jetzt habe ich den Chip mit der Version 1.11.9.4 brennen können. Und es ist wie bei dir, halb so schnell.
Da ich keine Ahnung mehr habe, warum das damals so war, würde ich an deiner Stelle auf die neueste Version gehen.

- - - Aktualisiert - - -

Hallo Dominik,
ich weiss jetzt, warum das nicht funktioniert.
In deiner Version wird die Option Cear_Timer noch als Clear Timer geschrieben. Der Compiler beschwert sich nicht, aber macht es auch nicht. Daher springt der Timer nicht von 124 auf 0, sondern erst von 255, also etwa halb so schnell. Schreibe die Konfig mal so:
Config Timer2 = Timer , Prescale = 1024 , Clear timer = 1

Dominik009
21.12.2013, 17:37
Vielen, vielen Dank an alle und ganz besonders an for_ro! Es läuft. Es lag wirklich an der Schreibweise und meiner alten Bascom version.
Vielen Dank für die Unterstüzung und dafür das du extra die Version bei dir getestet hast und mir beim Code weitergeholfen hast.
Die Uhr läuft jetzt seit mehreren Stunden ohne Merkliche/Sichtbare abweichung :D

Viele grüße und nochmals vielen Dank
Dominik