Sie sind vermutlich noch nicht im Forum angemeldet - Klicken Sie hier um sich kostenlos anzumelden Impressum 
Sie können sich hier anmelden
Dieses Thema hat 1 Antworten
und wurde 3.943 mal aufgerufen
 Bascom - Unser Einsteigerkurs
diezel Offline



Beiträge: 709

07.04.2013 00:50
[BEK08] Timer als Timer Zitat · Antworten

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
$regfile = "m8def.dat"                                      'Mikrocontroller ist Atmega 8
$crystal = 8000000 'Arbeitsfrequenz 8 MHz
$hwstack = 40 'Hardware-Stack
$swstack = 32 'Software-Stack
$framesize = 60 'Frame
$baud = 19200 'serielle Übertragungsgeschwindigkeit
 
'*** Ein/Ausgänge deklarieren **************************************************
Config Portb = Output 'PortB als Ausgang
Led1 Alias Portb.0 'Ausgang PortB.0 heitßt ab jetzt "Led1"
 
'*** Hauptschleife *************************************************************
 
Do 'Beginn Hauptschleife
Toggle Led1
Waitms 500
Loop 'Ende Hauptschleife
 
End
 



Hallo,

seht Euch mal das Beispiel oben an. Was macht es? Genau, eine LED blinkt mit 1Hz. Mehr nicht. Schade eigentlich, weil während dem "Waitms 500" verbringt der µC fast 4 Millionen Takte mit nix tun.

Ich will Euch nun zeigen, wie man das besser macht. Das Mittel der Wahl nennt sich "Timer".

Ein Timer ist ein Zähler, der die Systemtakte mitzählt. Und das macht er von ganz alleine, unser eigentliches Programm läuft gleichzeitig weiter, weil der Timer in einer eigenen "Baugruppe" des µC verbaut ist.
Die Atmels haben (fast) alle mehrere Timer. Wieviele sagt Euch das Datenblatt. Unser Atmega8 hat 3 Stück, die da heißen: Timer0, 1 und 2.
Es gibt noch Unterschiede, wie weit die Timer zählen können: Timer 0 und 2 sind 8-Bit-Timer, können also von 0 bis 255 zählen, der Timer 1 hat 16 Bit, kann also von 0 bis 65535 zählen.

Als weiteres Gimmick kann man "Prescaler" einschalten. Diese Vorteiler bewirken, das nur jeder x-te Systemtakt den Timer weiterzählen läßt. Mögliche Prescaler beim Atmega8 sind 8, 64, 256 und 1024. Z.B. wird Prescaler 8 konfiguriert, zählt der Timer nur bei jedem 8ten Systemtakt weiter.
Die neueren Atmels haben übrigends noch mehr Prescaler die feiner abgestuft und größer sein können -> Datenblett gucken!

Während dem Programmlauf kann jederzeit der aktuelle Zählerstand des Timers ausgelesen werden.
Ist ein Timer voll, bspw. der Timer0 hat bis 255 gezählt, kann er einen "Interrupt" auslösen. Dadurch wird der aktuelle Programmablauf unterbrochen, ein definierter Programmteil wird abgearbeitet und nach Erledigung geht´s an der vorherigen Stelle weiter.

Keine Angst, sooo schlimm ist´s gar nicht :-)

Jetzt mal zu unserem Beispiel: wir wollen ein Timer so konfigurieren, daß er uns alle 500ms einen Interrupt auslöst. Unser Atmega8 rennt mit 8MHz, er macht also je Sekunde 8 Millionen Takte. Wir müssen jetzt also 4 Millionen Takte mitzählen.
Ich nehm jetzt mal den Timer1, der bis 65535 zählen kann. Jetzt stellt sich die Frage, wie groß der Prescaler sein muß.
Ich rechne kurz:
4000000 / 65536 = 61,03
Der Prescaler muß größer sein, wir nehmen also Prescaler = 64.
Gegenrechnung: wir teilen die 4 Millionen Takte durch den Prescaler:
4000000 / 64 = 62500
Paßt. Die 62500 sind kleiner als die 65535, die unser Timer zählen kann.
Ganz zufällig ist mit 62500 ein genauer Wert rausgekommen. Meist kommt dort eine Kommazahl raus, man muß sich dann entweder mit der daraus entstehenden Ungenauigkeit zufrieden geben oder man versucht durch Auswahl eines anderen Timers oder Prescalers genau hinzukommen.

Eine kleine Hürde haben wir jetzt noch. Der Timer kann nur einen Interrupt auslösen, wenn er voll ist, also bis an seine Grenze gezählt hat. Dies umgeht man so, in dem man den Timer nicht bei 0 zu zählen beginnen läßt, sondern ihn vorlädt. Bei wieviel? Wir rechnen wieder:
65536 - 62500 = 3036
Wir sagen also dem Timer am Programmanfang und jedesmal, wenn er wieder bei 0 anfangen will, das ist gleich nachdem er den Interrupt ausgelöst hat, daß er bei 3036 anfängt.

Hier die Umsetzung des oben beschriebenen in Bascom:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
$regfile = "m8def.dat"                                      'Mikrocontroller ist Atmega 8
$crystal = 8000000 'Arbeitsfrequenz 8 MHz
$hwstack = 40 'Hardware-Stack
$swstack = 32 'Software-Stack
$framesize = 60 'Frame
$baud = 19200 'serielle Übertragungsgeschwindigkeit
 
'*** Ein/Ausgänge deklarieren **************************************************
Config Portb = Output 'PortB als Ausgang
Led1 Alias Portb.0 'Ausgang PortB.0 heitßt ab jetzt "Led1"
 
'*** Timer konfigurieren *******************************************************
Config Timer1 = Timer , Prescale = 64 'Timer konfigurieren
On Timer1 Timerroutine 'Timerinterrupt Subroutine zuweisen
Enable Timer1 'Timer aktivieren
Start Timer1 'Timer starten
Timer1 = 3036 'Timer auf neuen Startwert einstellen

Enable Interrupts 'Interrupt erlauben
 
'*** Hauptschleife *************************************************************
 

Do 'Beginn Hauptschleife
!nop 'Befehl "!nop" heißt: mach nix
Loop 'Ende Hauptschleife
 
End
 

'*** Subs **********************************************************************
Timerroutine: 'Beginn Subroutine
Timer1 = 3036 'Timer auf neuen Startwert einstellen
Toggle Led1
Return 'Ende Subroutine
 
 


Der Code sollte jetzt eigentlich für Euch nachvollziehbar sein. Achtet bitte im Bereich "Timer konfigurieren" auf die richtige Schreibweise. Das "Enable Interrupts" wird gerne vergessen, bewirkt dann, daß keine Interrupts ausgeführt werden.

Und schaut genau hin: unser Hauptprogramm ist leer! Dort könnte irgend etwas anderes passieren.

Ihr seid´s dran !!!


Gruß
Gerhard

-------------------------------------------------------------------------------------------
hier mein aktueller TinyKatalog

Dateianlage:
Aufgrund eingeschränkter Benutzerrechte werden nur die Namen der Dateianhänge angezeigt Jetzt anmelden!
bek08.bas.txt

diezel Offline



Beiträge: 709

07.04.2013 02:31
#2 RE: [BEK08] Timer als Timer Zitat · Antworten

Hallo,

einen hab ich noch für heute. Weil neulich erst dieses Beispiel von SvenG aufkam:
[BEK02] Installation und Inbetriebnahme (2)

Ich zeig Euch, wie ich meine Blinkmuster erzeuge. Ich erzeuge mir mit einem Timer eine Zeitbasis, die mir in einem festen Intervall eine Variable hochzählt. In der Main-Loop frag ich dann nur noch die Variable ab und reagiere entsprechend.
In dem Beispiel ist der Timer0 mit Prescaler 1024 und Vorladewert 100 konfiguriert. Das ergibt genau alle 20ms einen Interrupt. Dort wird dann die Variable hochgezählt und wenn diese den Wert 50 (entspricht 1 Sekunde) erreicht, wieder auf 0 gesetzt.
In der Main-Loop setz ich dann nur noch den Ausgang entsprechend. Fertig. In der Main-Loop ist auch noch genügend Zeit für etliche andere Dinge.

Kleiner Tip noch: Für´s berechnen der Timerwerte besuch ich meist diese Seite:
http://www.bunbury.de/Technik/avr/bascom.htm#Timer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 
$regfile = "m8def.dat"                                      'Mikrocontroller ist Atmega 8
$crystal = 8000000 'Arbeitsfrequenz 8 MHz
$hwstack = 40 'Hardware-Stack
$swstack = 32 'Software-Stack
$framesize = 60 'Frame
$baud = 19200 'serielle Übertragungsgeschwindigkeit
 
'*** Ein/Ausgänge deklarieren **************************************************
Config Portb = Output 'PortB als Ausgang
Led1 Alias Portb.0 'Ausgang PortB.0 heitßt ab jetzt "Led1"
 
'*** Variablen definieren ******************************************************
Dim Zaehler As Byte
 
'*** Timer konfigurieren *******************************************************
Config Timer0 = Timer , Prescale = 1024 'Timer konfigurieren
On Timer0 Timerroutine 'Timerinterrupt Subroutine zuweisen
Enable Timer0 'Timer aktivieren
Start Timer0 'Timer starten
Timer0 = 100 'Timer auf neuen Startwert einstellen
 
Enable Interrupts 'Interrupt erlauben
 
'*** Hauptschleife *************************************************************
 

Do 'Beginn Hauptschleife
If Zaehler < 6 Then
Led1 = 0
Elseif Zaehler < 15 Then
Led1 = 1
Elseif Zaehler < 21 Then
Led1 = 0
Else
Led1 = 1
End If
Loop 'Ende Hauptschleife
 
End
 

'*** Subs **********************************************************************
Timerroutine: 'Beginn Subroutine
Timer0 = 100 'Timer auf neuen Startwert einstellen
Incr Zaehler
If Zaehler = 50 Then Zaehler = 0
Return 'Ende Subroutine
 
 



Der Code sollte mit obigen Erklärungen selbststprechend sein :-))


Gute Nacht...

Gerhard

-------------------------------------------------------------------------------------------
hier mein aktueller TinyKatalog

Dateianlage:
Aufgrund eingeschränkter Benutzerrechte werden nur die Namen der Dateianhänge angezeigt Jetzt anmelden!
bek08-2.bas.txt

 Sprung  

disconnected Mikromodell-Chat Mitglieder Online 3
Xobor Xobor Community Software
Datenschutz