www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timer0 Atmega644


Autor: Anfänger (Gast)
Datum:

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

$regfile = "m644pdef.dat"
$crystal = 16000000
$hwstack = 128
$swstack = 512
$framesize = 128
$baud = 38400
$baud1 = 38400

Open "COM2:" For Binary As #2



Enable Interrupts

Config Timer0 = Timer , Prescale = 1
On Timer0 Stoppuhr
Enable Timer0
Start Timer0

Dim Mycnt As Integer

Do

   Do
   Waitms 20
   Print #2 , Mycnt
   Loop

Loop

End


Stoppuhr:
   Incr Mycnt
Return


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

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

Autor: Paul Baumann (Gast)
Datum:

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

Autor: Falk Brunner (falk)
Datum:

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

Autor: Anfänger (Gast)
Datum:

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

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

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

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

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

Autor: Anfänger (Gast)
Datum:

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

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du warst schneller. Stimmt, ich lasse eine Variable mitzählen :)

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

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

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist es so korrekt?
$regfile = "m644pdef.dat"
$crystal = 16000000
$hwstack = 128
$swstack = 512
$framesize = 128
$baud = 38400



Enable Interrupts

Config Timer0 = Timer , Prescale = 8
On Timer0 Stoppuhr
Enable Timer0
Start Timer0

Dim Mycnt As Integer
Dim Millisekunden As Integer
Dim Sekunden As Integer
Dim Minuten As Integer

Do

   Do
   Waitms 20
   Print Minuten ; ":" ; Sekunden ; ":" ; Millisekunden

   Loop

Loop

End


Stoppuhr:
   Incr Mycnt

   If Mycnt = 8 Then
      Incr Millisekunden
      If Millisekunden = 1000 Then
         Incr Sekunden
         Millisekunden = 0
      End If
      Mycnt = 0
   End If

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


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

Autor: L. K. (ladde)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guck dir das mal an:

http://www.mikrocontroller.net/articles/AVR_-_Die_...

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.

Autor: Falk Brunner (falk)
Datum:

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

Autor: Paul Baumann (Gast)
Datum:

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

Autor: Anfänger (Gast)
Datum:

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

Autor: Zwölf Mal Acht (hacky)
Datum:

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

Autor: Anfänger (Gast)
Datum:

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

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe es nochmal angepasst. Jetzt dürfte es keinen Fehler mehr geben, 
richtig?
$regfile = "m644pdef.dat"
$crystal = 16000000
$hwstack = 128
$swstack = 512
$framesize = 128
$baud = 38400



Enable Interrupts

Config Timer0 = Timer , Prescale = 256
Timer0 = 6

On Timer0 Stoppuhr
Enable Timer0
Start Timer0

Dim Millisekunden As Integer
Dim Sekunden As Integer
Dim Minuten As Integer

Do

   Do
      Waitms 10
      Print Minuten ; ":" ; Sekunden ; ":" ; Millisekunden
   Loop

Loop

End


Stoppuhr:
   Timer0 = 6

   Millisekunden = Millisekunden + 4
   If Millisekunden = 1000 Then
         Incr Sekunden
         Millisekunden = 0
   End If

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


Autor: Paul Baumann (Gast)
Datum:

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

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.