Forum: Compiler & IDEs mega8515 Timer-> Anfänger


von JannikS (Gast)


Lesenswert?

Hallo,

Ich habe jetzt mehrere Themen gelesen, jedoch ist keines auf meinem 
"Niveau" :/
Habe hier einen mega8515. Ich kann bislang lediglich mit dem Controler 
Ein- und Ausgänge und einfach Schleifen realisieren.

Ich würde gernen eine LED einfach nur blinken lassen im Takt von vll. 
einer Sek.
Kann mir wer detailliert erklären wie ich welches Timer register zu 
setzten habe? Darüber würde ich mich wirklich sehr freuen.

Gruß
Jannik

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Schreib doch schon mal die Source soweit hin, wie du kommst.

Und vergiss nicht anzugeben, mit welchem Takt dein Atmega8515 in deiner 
Schaltung betrieben wird.

von JannikS (Gast)


Lesenswert?

Hallo Stefan,

Leider bin ich noch garnicht weit, da ich hier im gcc Tut einfach nicht 
durchblicke welche Register ich jetzt wirklich brauche. Quasi als 
Minimalkonfiguration!

Das einzige was ich jetzt einigermaßen verstehe, ist das ich nach jedem 
überlaufen von meinem 16Bit Register einen Interrupt hervorrufe, mit dem 
ich dann z.B. auch einen Ausgang setzten kann?!
Damit dies nicht zu schnell geschieht setzte ich z.B. TCCR1B = 
0b00000101 womit ich dann die F_CPU / 1024 teilen würde?! und mit sei() 
aktiviere ich meine Interrupts.

Das sind wie du merkst alles nur Bruchteile. Ich finde auch kein 
vernünftiges Beispiel wo es wirklich für Anfänger kommentiert ist.

Meine F_CPU ist bei 8 Mhz.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Schreib ein Gerüst ohne das ganze Timer-Gedöns. Also ein einfaches 
Beispiel wie du es zum LED-Blinken brauchst. Du kannst auch schon deine 
Überlegungen zum Timer einfügen und mit Kommentar // Unfertig markieren.

von Michael U. (amiga)


Lesenswert?

Hallo,

was Du außer dem Tutorial immer zur Hand haben mußt, ist das komplette 
Datenblatt des jeweiligen AVR.

Dort dann eben nach 16 Bit Timer schauen, interessiere Dich für Dein 
Vorhaben vorrangig für die Betriebsart CTC (Clear Timer on Compare 
Match). Such die nötigen Register und Werte zusammen und versuch Dein 
Glück.

Das Programm kannst Du dann ja gern hier zur Diskussion und 
Fehlersuchhilfe hier reinstellen.

Gruß aus Berlin
Michael

von JannikS (Gast)


Lesenswert?

1
#include <avr/io.h>
2
 
3
int main(void)
4
{
5
    DDRA = 0xff; //Ausgang LCD
6
  DDRB = 0xff; //Ausgang LED
7
  DDRC = 0x00; //Eingang DIP
8
  DDRD = 0x00; //Eingang DIP
9
  
10
    //Vermutlich hier die ungewisse Konfiguration der Timer-Register
11
  
12
  if (bit_is_set(PINC, 2)) {
13
    PORTB = 0xff; //PortB soll im Takt von etwa 1ner Sek blinken
14
  }
15
/*
16
Das wars zunächst. Das dient für mich erstmal nur zum reinen Verständnis
17
18
*/
19
    
20
}

von Karl H. (kbuchegg)


Lesenswert?

JannikS wrote:
>
> Das einzige was ich jetzt einigermaßen verstehe, ist das ich nach jedem
> überlaufen von meinem 16Bit Register einen Interrupt hervorrufe, mit dem
> ich dann z.B. auch einen Ausgang setzten kann?!
> Damit dies nicht zu schnell geschieht setzte ich z.B. TCCR1B =
> 0b00000101 womit ich dann die F_CPU / 1024 teilen würde?! und mit sei()
> aktiviere ich meine Interrupts.
>
> Das sind wie du merkst alles nur Bruchteile.

Nö, das ist eigentlich schon fast alles, was es über Timer
in dieser Betriebsart zu sagen gibt.

Also: schnapp dir das Datenblatt. Such dir die Register
raus. Such dir die Bits in den Registern raus, die du setzen
musst und das wars dann auch schon fast.

> Meine F_CPU ist bei 8 Mhz.

OK. Ist schon mal was.
Zur Rumrechnerei mit dem Vorteiler kannst du dir ja mal das
hier reinziehen:

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer

Tja. Und dann heist es: Einfach mal ein Programm schreiben.
Im Simulator durchprobieren, ob alle Registerwerte so gesetzt
sind, wie sie es sein sollen und ob deine ISR auch wirklich
aufgerufen wird.

Hilft alles nichts. Da musst du durch und ins kalte Wasser
springen. Aber keine Angst, das ist keine Raketentechnik
und im Grunde genommen ziemlich simpel.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

1/ Wieviele LEDs hast du an PORTB, weil du den kompletten Port 
veränderst? Es würde bei einer LED reichen, einen Pin vom Port zu 
verändern.

2/ Bedeutet PORTB = 0xff; die LEDs sind AN oder sind AUS?
Wenn es eine Schaltung nach STK500 Muster ist, wären mit dieser 
Anweisung die LED(s) alle AUS, weil diese aktiv-low beschaltet sind. 
Hier ist ein Kommentar im Sourcecode hilfreich.

3/ So könnte es aussehen:
1
//
2
// Demo Timer - JannikS
3
// uC     = Atmega8515
4
// F_CPU   = 8 MHz
5
// 
6
7
#include <avr/io.h>
8
#include <avr/interrupt.h>  // Hilfsdefintionen für Interrupts
9
10
int main(void)
11
{
12
  DDRB = 0xff; // Ausgang LED
13
  
14
  /**
15
  Datenblatt: http://www.atmel.com/dyn/resources/prod_documents/doc2512.pdf
16
  Ab Seite 80: Timer0
17
18
  Als am einfachsten verstehbarer Modus wird der Normal Mode (Seite 85) 
19
  von Timer0 gewählt:
20
  
21
  Ein 8-Bit Register zahlt von einem Anfangswert (Voreinstelltung 0) 
22
  bis 0xFF hoch. Wenn 0xFF erreicht ist, führt die nächste Erhöhung um 
23
  Eins zu einem Ergebnis von 0 (neuer Startwert zum Hochzählen) und zu 
24
  dem gewünschten Overflow-Interrupt
25
  
26
  Wie das Register TCCR0 (Timer/Counter Control Register) zu setzen ist, 
27
  um den Normal Mode einzustellen steht in Table 44 bei den Bits WGM01 
28
  und WGM02
29
30
  Eine weitere Einstellmöglichkeit ist, wie schnell hochgezählt werden
31
  soll. Das kann mit der vollen Taktrate F_CPU geschehen oder indem man
32
  die Taktrate durch einen Vorteiler (Prescaler) teilt. Die möglichen 
33
  Prescaler 1, 8, 64, 256, 1024 sind in Table 48 angegeben.
34
  
35
  Berechnung der Zeit bis zum Overflow bei verschiedenen Prescaler 
36
  Einstellungen
37
  
38
  Overflow = 1/F_CPU * 256
39
  
40
  Prescaler   Overflow
41
  1             32 us
42
  8            256 us
43
  64          2048 us
44
  256         8192 us
45
  1024       32768 us = 32,768 ms
46
  
47
  1s sind aber 1000 ms bzw. 1000000 us... 
48
  d.h. man braucht mehrere Overflow Interrupts in denen die nur Anzahl 
49
  der Interrupts gezählt wird und erst wenn die Anzahl mal die Dauer 
50
  die gewünschte Sekunde ergibt, wird die LED umgeschaltet.
51
52
  Wieviele Overflows braucht man für eine Sekunde bei verschiedenen 
53
  Prescaler Werten?
54
 
55
  Anzahl_Overflows = 1s / Zeit_für_einen_Overflow
56
57
  Prescaler   Overflow  Anzahl_Overflows    
58
  1             32 us    31250
59
  8            256 us    3906,25
60
  64          2048 us    488,28125
61
  256         8192 us    122,0703125
62
  1024       32768 us    30,517578125
63
  
64
  Bzw. die Gesamtrechnung ist:
65
66
  Anzahl_Overflows = 1 * F_CPU / 256
67
68
  Hier ist der Wert bei Prescaler 1 interessant: Die Anzahl der nötigen 
69
  ist Overflows ist nämlich eine ganze Zahl und das vereinfacht das 
70
  Programmieren!
71
72
  Dieser Wert wird im Timer0-Interrupt verwendet.
73
  */
74
75
  // 8-Bit TIMER0 Normal Mode, Prescaler 1
76
  TCCR0 = (0 << WGM01) | (0 << WGM00) 
77
          | (0 << CS02) | (0 << CS01) | (1 << CS00) ; 
78
  
79
  // Und den spezellen Timer0 Overflow Interrupt nicht nur konfigurieren, 
80
  // sondern auch zulassen (enablen) d.h. das Timer/Counter Interrupt Mask 
81
  // Register setzen (Seite 93)
82
83
  TIMSK = (1 << TOIE0);
84
85
  // Alle zugelassenen Interrupts einschalten
86
  sei();
87
88
  // Endlosschleife
89
  // 1. main() nie verlassen
90
  // 2. wird vom Timer0 Overflow Interrupt unterbrochen
91
  while(1)
92
  {
93
  }
94
}
95
96
/**
97
  Dies ist die Interruptroutine, die aufgerufen wird, 
98
  wenn der eingestellte Timer einen Überlauf hat.
99
100
  Der Name ist aus Datenblatt und aus avr/iom8515.h 
101
  ersichtlich. avr/iom8515.h ist die genaue Beschreibung
102
  deines µC und wird über avr/io.h eingebunden.
103
104
  Ein möglicher Interruptvektor steht dort im Abschnitt:
105
106
  // Timer/Counter0 Overflow
107
  #define TIMER0_OVF_vect      _VECTOR(7)
108
109
  Timer0 ist ein 8-Bit-Timer mit Overflow Modus 
110
*/
111
112
unsigned int Anzahl_Overflows;
113
114
ISR(TIMER0_OVF_vect)
115
{
116
  Anzahl_Overflows++;
117
118
  // Prüfen ob 1s voll
119
  if (Anzahl_Overflows == 1 * F_CPU / 256)
120
  {
121
    // LOW/HIGH mit Hilfe der XOR Bitmanipulation umschalten
122
    // das schaltet die LED(s) AN/AUS
123
124
    // In der Simulation auf die nächste Zeile einen Breakpoint setzen (F9)
125
    // und das Programm voll laufen lassen (F5). 
126
    // Dann mit Hilfe der Stop Watch im I/O View die Zeit bis zum 
127
    // nächsten Erreichen des Breakpoints messen.
128
    // (Nicht ungeduldig werden. Das dauert auf meinem Rechner ca. 65 s)
129
    PORTB ^= 0xFF; 
130
131
    // Zurücksetzen für nächste 1s Wartezeit
132
    Anzahl_Overflows = 0;
133
  }
134
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> 3/ So könnte es aussehen:

Der Code ist bei weitem nicht optimal, sondern soll nur eine erste Idee 
geben (die Scheu vor Interrupts nehmen).

Die Nachteile sind u.a. das grobe Missverhältnis von Arbeitszeit in dem 
Hauptprogramm (zu wenig, hier stört es zum Glück nicht) zur Arbeitszeit 
in der Interruptroutine (zu viel). Sowie die Platzverschwendung mit der 
Hilfsvariable Anzahl_Overflows. Beides kann man geschickter (aber 
vielleicht weniger einsichtig) machen.

von JannikS (Gast)


Lesenswert?

Wow, vielen Dank Stefan für diese ausführliche Erklärung.
Ich werde mich dann mal im detail damit beschäftigen!

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.