Forum: Mikrocontroller und Digitale Elektronik Timer0 Atmega644


von Anfänger (Gast)


Lesenswert?

Hallo,

ich möchte eine Stoppuhr mit Timer0 programmieren.
Könnte mir jemand sagen, wie oft die Methode "Stoppuhr" angesprungen 
wird bzw wie ich das berechnen kann?

Danke!

1
$regfile = "m644pdef.dat"
2
$crystal = 16000000
3
$hwstack = 128
4
$swstack = 512
5
$framesize = 128
6
$baud = 38400
7
$baud1 = 38400
8
9
Open "COM2:" For Binary As #2
10
11
12
13
Enable Interrupts
14
15
Config Timer0 = Timer , Prescale = 1
16
On Timer0 Stoppuhr
17
Enable Timer0
18
Start Timer0
19
20
Dim Mycnt As Integer
21
22
Do
23
24
   Do
25
   Waitms 20
26
   Print #2 , Mycnt
27
   Loop
28
29
Loop
30
31
End
32
33
34
Stoppuhr:
35
   Incr Mycnt
36
Return

von Karl H. (kbuchegg)


Lesenswert?

Anfänger schrieb:
> Hallo,
>
> ich möchte eine Stoppuhr mit Timer0 programmieren.
> Könnte mir jemand sagen, wie oft die Methode "Stoppuhr" angesprungen
> wird bzw wie ich das berechnen kann?

Das ist eigentlich sehr einfach, wenn man verstanden hat, was ein Timer 
macht und wie er arbeitet.

Der grundsätzliche Aufbau ist so:



   CPU-Haupttakt   -> Vorteiler  ->  Timer

Der Haupttakt des Systems (bei dir offenbar 16Mhz) wird durch den 
Vorteiler gejagt. Ist der zb auf 16 eingestellt, dann kommt aus dem 
Vorteiler ein Takt von 1Mhz raus. Steht der Vorteiler auf 8, dann eben 
2Mhz. Bei 256 sind es 16/256 Mhz etc. etc.

Mit diesem Takt wird der Timer gespeist und der zählt mit jedem 
Taktschlag vor sich hin

   0, 1, 2, 3, 4, 5 ....

Ohne irgendwelche sonstige Beschränkungen würde ein Timer mit einem 
Vorteiler von 8 bei 16Mhz Haupttakt also in 1 Sekunde bis 2Millionen 
zählen. Ist ja auch logisch: Herz ist ja 1 Schwingung in 1 Sekunde. Hast 
du 2 Millionen Schingungen in der Sekunde, dann wird eben bis 2 
Millionen gezählt.

Jetzt kann aber ein Timer nicht so hoch zählen.
Timer0 ist ein 8 Bit Timer. Der kann nur bis 255 zählen. Danach geht es 
bei 0 weiter. Es ist ein sog. Überlauf (Overflow) entstanden.

Jetzt kann man sich natürlich fragen: Wenn der Timer in 1 Sekunde bis 2 
Millionen zählen würde, das aber nicht kann, weil bei 255 (also nach 256 
Takten) ein Überlauf entstand; wieviele Überläufe gibt es dann 
eigentlich in 1 Sekunde?

Einfach: 2000000 / 256 = 7812.5  Überläufe pro Sekunde.

Du hast dich mit

> On Timer0 Stoppuhr


an diese Überläufe gekoppelt. Bei jedem Überlauf wird die Funktion 
Stoppuhr aufgerufen. Daher wird diese Funktion (bei den von mir 
gewählten Zahlen) in 1 Sekunde 7812.5 mal aufgerufen.

Jetzt bist du drann: Wie oft wird die Funktion bei DIR aufgerufen?

von Paul Baumann (Gast)


Lesenswert?

Timer 0 ist 8 Bit breit. Prescale steht auf 1.
Das heißt: Du mußt die 16Mhz durch 256 teilen. Dann hast Du die 
Frequenz,
mit der der Interrupt auftritt. Die Zeit ist dann: T=1/F

Zum Rechnen bin ich jetzt zu faul.
;-)
MfG Paul

von Falk B. (falk)


Lesenswert?

@  Anfänger (Gast)

>Könnte mir jemand sagen, wie oft die Methode "Stoppuhr" angesprungen
>wird bzw wie ich das berechnen kann?

Mit Hilfe des Datenblatts und der Kenntniss deines CPU-Taktes.

In deinem Fall 16 MHz, Timer 0 hat 8 Bit und läuft damit nach 256 Takten 
über und löst den Interrupt aus. Macht 16MHz/256 = 62,5kHz bzw. 
16us. Ziemlich schnell, zu schnell. Du musst den Prescaler höher setzen, 
damit du auf ca. 1..10ms kommst.

MFG
Falk

von Anfänger (Gast)


Lesenswert?

Hallo,

vielen Dank, jetzt wird es klarer.
Karl Heinz: bei mir wird also die Methode 16.000.000 mal pro Sekunde 
aufgerufen. Ich müsste also, wenn die Stoppuhr zb Millisekunden zählen 
soll, den Takt mit dem Prescaler so anpassen, dass der Interrupt 1x pro 
ms aufgerufen wird.

Allerdings klappt das nicht so recht. Wenn ich zb den Vorteiler auf 256 
stelle, dann würde der Interrupt 62.500 mal pro Sekunde aufgerufen 
werden, das entspricht 0,016 ms. Bekommt man da irgendwie einen geraden 
Wert hin? Der Prescaler kann ja max auf 1024 eingestellt werden, oder?

von Karl H. (kbuchegg)


Lesenswert?

Anfänger schrieb:
> Hallo,
>
> vielen Dank, jetzt wird es klarer.
> Karl Heinz: bei mir wird also die Methode 16.000.000 mal pro Sekunde
> aufgerufen.

Nein.
Denk nach einmal darüber nach.
Die Methode wird aufgerufen, wenn ein ÜBERLAUF entsteht. Der ensteht 
aber nicht bei jedem Timer-Takt sondern genau dann, wenn ....

von Karl H. (kbuchegg)


Lesenswert?

Anfänger schrieb:

> werden, das entspricht 0,016 ms. Bekommt man da irgendwie einen geraden
> Wert hin?

Du kannst ja einfach mal alle vorhandenen Vorteiler durchrechnen :-)

-> Es geht sich mit keinem richtig aus.

Aber du musst ja auch nicht auf Millisekunden.
Wenn du weisst, dass die Funktion 354 mal in der Sekunde aufgerufen 
wird, dann brauchst du doch nur in der Funktion eine Variable um 1 
hochzählen und wenn diese 354 erreicht hat, dann ist 1 Sekunde vorbei 
:-)

von Anfänger (Gast)


Lesenswert?

Ah ok, es sind 16.000.000 / 256 = 62.500 Aufrufe / Sek.

Wenn ich also den Prescaler auf 256 einstelle, sind es 16.000.000 / 256 
/ 256 = 244.14 Aufrufe pro Sekunde. Das entspricht etwa einem Aufruf 
jede 4.1ms

Aber wie kommt man nun auf einen geraden Wert? Zb alle 1ms oder 10ms?

von Anfänger (Gast)


Lesenswert?

Du warst schneller. Stimmt, ich lasse eine Variable mitzählen :)

von Karl H. (kbuchegg)


Lesenswert?

Anfänger schrieb:
> Ah ok, es sind 16.000.000 / 256 = 62.500 Aufrufe / Sek.
>
> Wenn ich also den Prescaler auf 256 einstelle, sind es 16.000.000 / 256
> / 256 = 244.14 Aufrufe pro Sekunde. Das entspricht etwa einem Aufruf
> jede 4.1ms
>
> Aber wie kommt man nun auf einen geraden Wert? Zb alle 1ms oder 10ms?

Gar nicht!
Zumindest nicht mit dem einfachen Schema, sich an die Überläufe zu 
hängen. (Jetzt weißt du auch, warum der Systemtakt bei reinen 
Uhrenanwendungen gerne als eine Potenz von 2 gewählt wird. Dann geht es 
sich nämlich aus)

Du brauchst einen Timer der den CTC Mode kann. Dort kannst DU dann 
vorgeben, wann ein 'Überlauf' entstehen soll.

Aber eins nach dem anderen. Man kann auch mit geringen Fehlern leben, 
solange die Uhr nicht zulange läuft :-)
Und eine gute Übung ist es allemal.

von Anfänger (Gast)


Lesenswert?

Ist es so korrekt?
1
$regfile = "m644pdef.dat"
2
$crystal = 16000000
3
$hwstack = 128
4
$swstack = 512
5
$framesize = 128
6
$baud = 38400
7
8
9
10
Enable Interrupts
11
12
Config Timer0 = Timer , Prescale = 8
13
On Timer0 Stoppuhr
14
Enable Timer0
15
Start Timer0
16
17
Dim Mycnt As Integer
18
Dim Millisekunden As Integer
19
Dim Sekunden As Integer
20
Dim Minuten As Integer
21
22
Do
23
24
   Do
25
   Waitms 20
26
   Print Minuten ; ":" ; Sekunden ; ":" ; Millisekunden
27
28
   Loop
29
30
Loop
31
32
End
33
34
35
Stoppuhr:
36
   Incr Mycnt
37
38
   If Mycnt = 8 Then
39
      Incr Millisekunden
40
      If Millisekunden = 1000 Then
41
         Incr Sekunden
42
         Millisekunden = 0
43
      End If
44
      Mycnt = 0
45
   End If
46
47
   If Sekunden = 60 Then
48
      Incr Minuten
49
      Sekunden = 0
50
   End If
51
Return

Ich habe gelesen, dass man so wenige Berechnungen in die 
Interrupt-Routinen packen soll. Ist bei in dem oberen Beispiel schon zu 
viel?

von L. K. (ladde)


Lesenswert?

Guck dir das mal an:

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

Der Code ist zwar in C, aber das Prinzip ist meiner Meinung nach so gut 
erklärt, dass es kein Problem sein sollte, das ganze in Bascom (oder 
Assembler oder ...) umzusetzen.

von Falk B. (falk)


Lesenswert?

@Anfänger (Gast)

>Ist es so korrekt?

Sieht gut aus.

>Ich habe gelesen, dass man so wenige Berechnungen in die
>Interrupt-Routinen packen soll. Ist bei in dem oberen Beispiel schon zu
>viel?

Nein, das ist voll OK. Nur ist deine Millisekunde um 24us zu lang, sind 
immerhin 2,4% Fehler. Anderen Quarz nutzen oder den CTC-Modus.

MfG
Falk

von Paul Baumann (Gast)


Lesenswert?

Hier ist ein Beispiel, wie man einen Sekundentakt erzeugen kann:

'Sekundenimpuls mit Timer 0 erzeugen (Paul Baumann)
$regfile = "m8def.dat"                         'ATmega8-Deklarationen
$crystal = 16000000                            'Quarz: 16 MHz



Dim Umlauf As Byte
Dim X As Bit




On Timer0 Ontimer0

Config Timer0 = Timer , Prescale = 256      '16Mhz/256 = 62500 Hz
                                           'Timer auf 6 heißt 250 
Schritte
                                           'bis Überlauf
Enable Timer0                              'Timer erzeugt 250 Hz

Enable Interrupts                           'Interrupts global zulassen
Timer0 = 6
Umlauf = 250                                 'Umlauf zählt die 
Interrupts
Config Portd.6 = Output                      'LED an Port D6
Portd.6 = 0
X = 0


Do
 If Umlauf = 0 Then
    Umlauf = 250
    If X = 0 Then
      Portd.6 = 0
      X = 1
    Else
      Portd.6 = 1
      X = 0
    End If
 End If
Loop

'Interrupt-Routine

Ontimer0:

Timer0 = 6                'Timer sofort neu laden
 Decr Umlauf
Return


MfG Paul

von Anfänger (Gast)


Lesenswert?

Danke Paul.

In dem Zusammenhang fällt mir noch was ein:
Es gibt ja in Bascom den waitms - Befehl.
Wie berechnet der die Dauer? Wird da auch ein Timer genutzt?

von Purzel H. (hacky)


Lesenswert?

Nein. Das geht anders. Man nimmt zwar den Uebrlauf, zaehlt aber nicht 
von Null weg. Dh, im Intterrupt setzt man den Wert des Zaehlers :

Interrupt Timer0Overflow;
{
 Timer0Count:=155;
}

von Anfänger (Gast)


Lesenswert?

Hi Falk,

ich denke ich kann mit diesem Fehler leben. Die Uhr läuft in der Regel 
max 20 Minuten, da kommt ein Fehler von etwa 250 ms zusammen :)

von Anfänger (Gast)


Lesenswert?

Hallo,

ich habe es nochmal angepasst. Jetzt dürfte es keinen Fehler mehr geben, 
richtig?
1
$regfile = "m644pdef.dat"
2
$crystal = 16000000
3
$hwstack = 128
4
$swstack = 512
5
$framesize = 128
6
$baud = 38400
7
8
9
10
Enable Interrupts
11
12
Config Timer0 = Timer , Prescale = 256
13
Timer0 = 6
14
15
On Timer0 Stoppuhr
16
Enable Timer0
17
Start Timer0
18
19
Dim Millisekunden As Integer
20
Dim Sekunden As Integer
21
Dim Minuten As Integer
22
23
Do
24
25
   Do
26
      Waitms 10
27
      Print Minuten ; ":" ; Sekunden ; ":" ; Millisekunden
28
   Loop
29
30
Loop
31
32
End
33
34
35
Stoppuhr:
36
   Timer0 = 6
37
38
   Millisekunden = Millisekunden + 4
39
   If Millisekunden = 1000 Then
40
         Incr Sekunden
41
         Millisekunden = 0
42
   End If
43
44
   If Sekunden = 60 Then
45
      Incr Minuten
46
      Sekunden = 0
47
   End If
48
Return

von Paul Baumann (Gast)


Lesenswert?

Ja, das müßte so hinhauen. Aber: Denk dran, -wir haben es mit Elektronik
zu tun. Da treten Effekte auf, die allen physikalischen Gesetzen 
widersprechen...

Grins
Paul

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.