Forum: Compiler & IDEs timer und prscaler


von Daniela S. (idapinky)


Angehängte Dateien:

Lesenswert?

So, da bin ich wieder mit noch dummeren Fragen!!!

Hab jetz versucht einen Timer einzubauen.

Und jetzt kommen die Fragen:

Sitz alles an der richtigen Stelle?

wo setz ich das sei(); richtig?

an der Stelle, an der ich den Prescaler setz muss ich da bei einem 
Prescaler von 1024 auch die CS21 und CS20 "definieren oder setzten oder 
wie man das nennt"?
und wenn ja wie?

Hab ich den  Prescler und Preloader für 10ms im 16bit-timer?

Bitte jeden, der irgendwas dazu weiß zu antworten?

von Johannes M. (johnny-m)


Lesenswert?

Was soll denn das mit dem
1
TCCR1 = (1024<<CS22);
?

Welche der CS-Bits gesetzt werden müssen, um einen Prescaler von 1024 
einzustellen, steht in einer Tabelle im Datenblatt. Abgesehen davon ist 
TCCR1 ein 8-Bit-Register, und da passt die Zahl 1024 gar nicht rein, 
erst recht nicht, wenn Du sie auch noch nach links schiebst! Schau Dir 
mal den Artikel zur Bitmanipulation an.

Abgesehen steht der ganze Block mit den Initialisierungen im 
Niemandsland, was nicht zulässig ist! Zuweisungen an Variablen (und dazu 
zählen auch die I/O-Register) dürfen ausschließlich innerhalb von 
Funktionen stehen. Einzige Ausnahme sind Initialisierungen von globalen 
Variablen, die in der selben Zeile deklariert werden.

Das hier:
1
TCNT1 = 65379.75
ist, abgesehen von dem fehlenden Semikolon am Ende, Unsinn. TCNT1 kann 
nur ganzzahlige Werte annehmen!

von Johannes M. (johnny-m)


Lesenswert?

Auch das hier:
1
#ifndef SIGNAL
2
#   include <avr/signal.h>
3
#endif
ist Quatsch.

Bitte lies Dir das AVR-GCC-Tutorial gründlich durch. Da sind noch 
einige Dinge, die Du offensichtlich noch nicht wirklich verstanden hast. 
Allerdings auch ein paar C-Grundlagen fehlen, also sollte auch ein 
vernünftiges C-Buch her.

von Daniela (Gast)


Lesenswert?

Muss ganz erlich gestehen ich blicks echt hinten und vorne nich, da habt 
ihr schon recht!

Wenn ich mehr Zeit hätte, würd ich mich auch vorer intensiver damit 
beschäftigen.

muss es "TCNT1 = (1<<CS22)&(1<<CS21)&(1<<CS20);" heißen?
Im Datenblatt steht für 1024 müssen alle drei "1" sein.
Ich les mal noch ein bisschen nach, is wohl besser.

von Johannes M. (johnny-m)


Lesenswert?

Daniela wrote:
> da habt ihr schon recht!
          ^^^
"ihr"? Wer ist der andere?

> muss es "TCNT1 = (1<<CS22)&(1<<CS21)&(1<<CS20);" heißen?
Nicht "&"! Es muss "|" sein! Noch mal Bitmanipulation lesen...

> Im Datenblatt steht für 1024 müssen alle drei "1" sein.
Genau. Also hast Du zumindest die Tabelle schon mal gefunden. Weiter so! 
Generell sind die AVR-Datenblätter eigentlich ziemlich übersichtlich, 
und meist gibt es ebenso übersichtliche Tabellen, in denen die 
Steuerbits stehen. Das meiste von den wirklich wichtigen Dingen kann man 
jeweils aus dem Abschnitt "Register Description" entnehmen, indem man 
einfach die dort beschriebenen Steuerregister der Reihe nach durchgeht 
und aussortiert, welche Bits man überhaupt nicht braucht und welche 
entsprechend gesetzt werden müssen.

> Ich les mal noch ein bisschen nach, is wohl besser.
Gut.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Nein, es sitzt leider gar nichts an der richtigen Stelle.

Noch mal zurück zu der ersten geänderten Version und dann die Änderungen 
einbauen für den Timer1 und zwar aus dem Code vom Countdownzähler 
(http://www.gjlay.de/pub/c-code/countdown.html). Dabei die 
Moderinisierung von SIGNAL zu ISR aus der avr-libc berücksichtigen.

Die Idee von Georg ist:

Man gibt vor, wieviele IRQs pro Sekunde kommen sollen. Z.B. willkürlich 
5000, um eine gute Zeitauflösung zu haben. So stellt man auch seinen 
Timer1 ein. Die Einstellung ist von der Taktrate (F_CPU) abhängig. Mit 
dem 16-Bit Timer und 5000 gewünschten IRQs/s kann man alle bei AVR 
möglichen MHz Taktraten abdecken. Bei anderen Werten muss man 
nachrechnen, ob man bei 16-Bit (OCR1A ) oder 8-Bit (interrupt_num_10ms) 
Ganzzahlüberläufe bekommt.

Dann weiss man auch wieviele IRQs in 10ms kommen (1/100-stel vom 1s 
Wert, hier 50). Man zählt die IRQs mit und wenn die Anzahl dem Wert bei 
10ms entspricht, ruft man die Arbeitsfunktion auf, die alle 10ms laufen 
muss.

Hätte man mehrere Arbeitsfunktionen, sollte man die etwas verteilen. Es 
werden die nicht alle bei exakt bei dem "Uhrstand" 10ms, 20ms, 30ms 
auferufen, sondern versetzt zueinander. Also z.B.

Arbeitsroutine 1 bei 10ms, 20ms, 30ms...
Arbeitsroutine 2 bei 10ms+1IRQ, 20ms+1IRQ, 30ms+1IRQ...
Arbeitsroutine 3 bei 10ms+2IRQ, 20ms+2IRQ, 30ms+2IRQ...
...
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "dcf.h"
4
5
#ifndef F_CPU
6
#define F_CPU 1000000
7
#endif
8
9
#define IRQS_PER_SECOND     5000
10
#define IRQS_PER_10MS       (IRQS_PER_SECOND / 100)
11
12
// Merkt alle 10 Millisekunden den Portzustand des DCF-Ports
13
unsigned char volatile dcf_bit = 0xff;
14
static void job_dcf_10ms(void);
15
16
ISR(TIMER1_COMPA_vect)
17
{
18
    static uint8_t interrupt_num_10ms;
19
    uint8_t irq_num = interrupt_num_10ms;
20
21
    // interrupt_num_10ms erhöhen und mit 
22
    // Maximalwert vergleichen
23
    if (++irq_num == IRQS_PER_10MS)
24
    {
25
        // 10 Millisekunden sind vorbei
26
        // interrupt_num_10ms zurücksetzen
27
        irq_num = 0;
28
    }
29
30
    if (irq_num == 0)       
31
      job_dcf_10ms();
32
33
    // hier ggf. andere Arbeitsroutinen
34
    // if (irq_num == 1)       
35
    //   job_1();
36
    // if (irq_num == 2)       
37
    //   job_2();
38
    // ...
39
40
    interrupt_num_10ms = irq_num;
41
}
42
43
void timer1_init (void)
44
{
45
    // PoutputCompare für gewünschte Timer1 IRQ-Rate
46
    OCR1A = (unsigned short) ((unsigned long) F_CPU / IRQS_PER_SECOND-1);
47
48
    // Timer1 ist Zähler: Clear Timer on Compare Match (CTC, Mode #4)
49
    // Timer1 läuft @ F_CPU: prescale = 1
50
    TCCR1A = 0;
51
    TCCR1B = (1 << WGM12) | (1 << CS10);
52
53
    // OutputCompare-Interrupt A für Timer1
54
    TIMSK = (1 << OCIE1A);
55
}
56
57
// Alle 10 Millisekunden aufrufen!
58
// Macht alle 10ms einen Schnappschuss vom DCF-Port (hier an Port B1).
59
static void job_dcf_10ms(void)
60
{
61
  unsigned char bit = 0;
62
63
  if (PIND & (1 << PD2))
64
    bit = 1;
65
66
  dcf_bit = bit;
67
}
68
69
int main(void)
70
{
71
  timer1_init();  // Timer1 für 10ms Ticken einrichten
72
  sei();          // Interrupts global enablen, d.h. Timer1 starten
73
74
  while (1)
75
  {
76
    unsigned char bit = dcf_bit;
77
78
    // Sind 10ms vergangen (also dcf_bit in {0,1}?)
79
    if (bit < 2)
80
    {
81
      // Ja:
82
      // Schnappschuss zuruecksetzen
83
      dcf_bit = 0xff;
84
85
      // Die Zeit tickt 10ms weiter
86
      time_tick_10ms (& timeinfo, bit);
87
88
      // Hier Restcode der Übersichtlichkeit wegen abgeschnitten...
89
    }
90
  } // Hauptschleife
91
92
  return 0;
93
} // main

von Daniela (Gast)


Lesenswert?

Hab die Bitmanipulation glesen, und hab in der zwischenzeit auch 
rausgefunden, dass es | und nicht & heißen müsste. Nächstes mal les ich 
erst und dann frag ich.

Auf die wirre Zahl des Preloaders bin ich durch ne Rechnung gekommen die 
ich online gefunden hab!

Schade, ich war so stolz auf mich, weil ich dachte ich hät´s halbwegs 
selbst gelöst.

Und ganz großen dank für das Program und die spitzen Erklärung dazu!
Ich hatte auch zuerst versucht es auf diesem Weg zu machen, aber dann 
bin ich auf das andere gestoßen und es hat so einfach ausgesehen. Aber 
wie man sieht konnt ich´s trotzdem nicht.

Und nochmal DANKE

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Daniela wrote:

> Schade, ich war so stolz auf mich, weil ich dachte ich hät´s halbwegs
> selbst gelöst.

Deine Idee (möglichst wenige - ideal ein - IRQ exakt zum richtigen 
Zeitpunkt bei 10ms) ist ja nicht verkehrt, nur an der Ausführung hapert 
es.

Wenn du beachtest, dass die Timer mit Ganzzahlen arbeiten und wenn du 
dich weiter in das Thema einliest (z.B. mit [[AVR - Die genaue Sekunde / 
RTC]] und Datenblatt vom AVR), kannst du deinen Weg immer noch 
schaffen.

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.