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?
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!
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.
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.
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.
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 |
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.