Hallo Hallo Ich habe mir das AVR Bord von Pollin besorgt und schreibe gerade meine ersten Programme in C. Besser gesagt mein erstes Programm in C. Als Mikrocontroller benutze ich den Maga8. Software AVR Studio 4 zum Brennen bnutze ich PonyProg2000 Und hier das überarbeitete Programm Das Alte ist unter LED zu finden. #include <avr/io.h> #include <avr/iom8.h> #include <avr/interrupt.h> #ifndef F_CPU #warning "F_CPU nicht definiert!!!" #define F_CPU 12000000UL #endif int i,a,b,erg; ISR (TIMER0_OVF_vect) { PORTD^= (1<< PD5)|(1<< PD6); } void zeit (void) { DDRD|= (1<<DDD5) | (1<<DDD6); TCCR0|= (1<<CS00)|(1<<CS02); sei(); TIMSK|= (1<<TOIE0); } int main(void) { while (1) { zeit(); b++; a=b+1; if (a>=2000) { PORTD|=(1<<PD6); PORTD&=~(1<<PD5); i++; i=i+1; } if (i==2000) { PORTD|=(1<<PD5); PORTD&=~(1<<PD6); a=0; b=0; i=0; } } } Sorry, das ich da etwas unstrukturiert bin. Ich werden auch einen neuen Beitrag anfangen. Aber zu vor möchte ich gerne deine Fragen (von Karl siehe LED) die du mir gestellt hast beantworten. > > > TIMSK|= (1<<TOIE0); > TIMSK&= ~(1<<TOIE0); > > > den Overflow Interrupt freizugeben und danach gleich wieder zu sperren? > Ich bin davon ausgegangen, dass der Overflow dann gelöscht wird, beziehungsweise rückgesetzt wird. > Woran machst du fest, dass dein Prescaler nicht funktioniert? > Auf wieviel hast du ihn den eingestellt? Wie oft wird daher die ISR > aufgerufen? Den Prescaler habe ich auch schon auskommentiert und da hat sich nix geändert beim Blinken. Einstellung hatte ich auf 1024 eingestellt. Siehe Datenblatt http://www.atmel.com/dyn/resources/prod_documents/... Die ISR wird einmal aufgerufen, wenn ich das richtig verstanden habe, oder??? Gibt es da zu auch gute Bücher, um einen den Einstieg zu erleichtern??? Vielen Dank! Friedrich
Friedrich schrieb: > #ifndef F_CPU > #warning "F_CPU nicht definiert!!!" > #define F_CPU 12000000UL > #endif F_CPU wird nur von den Headerdateien <util/delay.h> und <util/setbaud.h> benutzt, die du beide nicht einbindest. Damit ist dieses #define nutzlos. > zeit(); > b++; > a=b+1; All dein Herumopern auf den Variablen wird der Compiler bei eingeschalteter Optimierung herauswerfen (bzw. die Ausdrücke drastisch vereinfachen), da er feststellen kann, dass die Variablenwerte anschließend sowieso nicht benutzt werden. Wenn du eine definierte Verzögerung haben willst, dann nimm die Funktionen aus <util/delay.h> (aber bitte die Optimierung einschalten!). Wenn du die Übung durch hast, nimmst du dann gleich einen Timer. ;-) >> TIMSK|= (1<<TOIE0); >> TIMSK&= ~(1<<TOIE0); > Ich bin davon ausgegangen, dass der Overflow dann gelöscht wird, > beziehungsweise rückgesetzt wird. Datenblatt lesen: deine Annahme ist falsch. Ein gesetztes IRQ-Flag wird nicht einfach dadurch gelöscht, dass man den IRQ verbietet und wieder freigibt. Im Datenblatt steht auch drin, wie man es wirklich löscht:
1 | TIFR = (1 << TOV0); |
Hallo Jörg! Ja, ich bin da etwas unstrukturiert. Ich möchte halt nur den Timer erst mal verstehen, wie man ihn einstellt. Klar kann ich auch die Headerdateien <util/delay.h> nehmen dann kann ich direkt die Zeit einstellen. Aber ich möchte mir schon gerne eine eigne Funktion schreiben. Vieles findet man ja auch im AVR-GCC-Tutorial. Vielen Dank! Ich werde erst mal deine Vorschläge umsetzen und dann ausprobieren. Wie bekomme ich denn, eine farbliche Hinterlegung des Quelltextes hier hin?? Bis dann Friedrich
Friedrich schrieb: > Wie bekomme ich denn, eine farbliche Hinterlegung des Quelltextes hier > hin? Indem du beim Schreiben deines Beitrags mal ein paar Zeilen nach oben scrollst und dir die Bemerkungen unter "Formatierung" ansiehst.
Hallo Jörg! Ein großes Dankeschön an Dich! Jetzt blinken die LEDs! Aber ich weiß immer noch nicht ob der Vorteiler (Prescaler) funktioniert. Hier noch mal mein Programm.
1 | #include <avr/io.h> |
2 | #include <avr/iom8.h> |
3 | #include <avr/interrupt.h> |
4 | |
5 | int i,a; |
6 | |
7 | void zeit (void) |
8 | {
|
9 | DDRD|= (1<<DDD5) | (1<<DDD6); |
10 | sei(); |
11 | TIMSK|= (1<<TOIE0); |
12 | TIFR=(1<<TOV0); |
13 | }
|
14 | |
15 | int main(void) |
16 | |
17 | |
18 | {
|
19 | TCCR0|= (1<<CS00)|(1<<CS02); |
20 | while (1) |
21 | {
|
22 | zeit(); |
23 | a++; |
24 | |
25 | if (a==2000) |
26 | |
27 | |
28 | PORTD ^=(1<<PD6); |
29 | else
|
30 | i++; |
31 | |
32 | if (i==2000) |
33 | {
|
34 | PORTD ^=(1<<PD5); |
35 | a=0; |
36 | i=0; |
37 | |
38 | }
|
39 | |
40 | |
41 | }
|
42 | }
|
Hoffe das es jtzt o.k. ist Vielen Dank! Friedrich
Was die Funktion zeit() genau machen soll, ist mir nicht klar. Eine bestimmte Zeit warten wird sie jedenfalls nicht. Das Schlimmste aber ist: du schaltest einen Interrupt frei (den Overflow-Interrupt von Timer 0), hast aber keine ISR dafür. Das führt zum Ausführen der default-ISR, und die springt auf Adresse 0, d. h. sie bewirkt einen Neustart des Programms. Vielleicht beschreibst du ja erst einmal, was du mit dem Timer genau bezweckst. Deine Einrückung passt übrigens nicht zu dem, wie die hintereinander stehenden if-Anweisungen ausgeführt werden.
Hallo Jörg! Im Prinzip möchte ich den Timer und Vorteiler bzw. Interrupt verstehen, wie diese Komponenten zusammenspielen. Im ersten Schritt wollte ich einfach zwei LEDs blinken lassen in einer bestimmten Zeit. (<util/delay.h> möchte ich aber nicht verwenden) Dann wollte ich über eine Tastenabfrage die LEDs unterschiedlich schnell blinken lassen, aber dazu muss ich ja erst den Timer verstehen. Ich sehe es schon ich bin ein hoffnungsloser Fall. Ich möchte dir aber für deine Geduld und Hilfe nochmals Danken! Friedrich
Friedrich schrieb: > Ich sehe es schon ich bin ein hoffnungsloser Fall. Keineswegs, aber du solltest zumindest eine Idee im Kopf haben, wie du den Timer dafür benutzen willst. Im Moment wirfst du ihn nur an. Dann rennt er los, das macht er natürlich völlig parallel zur CPU. Nur, danach kümmerst du dich nie wieder um den Timer. Irgendwie musst du ja dessen Ergebnis mal auswerten.
1 | /*
|
2 | Im ersten Schritt wollte ich einfach zwei LEDs blinken lassen in einer
|
3 | bestimmten Zeit. (<util/delay.h> möchte ich aber nicht verwenden)
|
4 | |
5 | Hardware: Atmega8
|
6 | */
|
7 | #include <avr/io.h> |
8 | #include <avr/interrupt.h> |
9 | |
10 | int main(void) |
11 | {
|
12 | // Ausgänge einrichten
|
13 | DDRD|= (1<<DDD6)|(1<<DDD5); |
14 | |
15 | /*
|
16 | Timer0 einrichten
|
17 | |
18 | Angenommene Taktfrequenz des Atmega8 1000000 Hz (Werkseinstellung)
|
19 | |
20 | Bei Prescaler 1024 kommen pro Sekunde 976,5625 Takte, d.h ein Takt
|
21 | kommt alle 1/976,5625s = 1,024 ms
|
22 | |
23 | Der Zähler von Timer0 ist 8-Bit breit, d.h. nach 2^8 = 256
|
24 | Zählschritten läuft der Zähler über. Beim Überlaufen kann ein
|
25 | OVERFLOW Interrupt ausgelöst werden. 1,024 ms * 256 = 250 ms
|
26 | |
27 | Wir lassen die LED an PD5 bei jedem Overflow an oder aus gehen.
|
28 | Wir lassen die LED an PD6 alle 5 Sekunden an oder aus gehen....
|
29 | */
|
30 | TCCR0 |= (1<<CS02)|(1<<CS00); // Prescaler 1024 |
31 | TIFR = (1<<TOV0); // Timer0 Overflow Interrupt Flag löschen |
32 | TIMSK|= (1<<TOIE0); // Timer0 Overflow Interrupt zulassen |
33 | |
34 | // Interrupts global einschalten
|
35 | sei(); |
36 | |
37 | while(1) |
38 | {
|
39 | // Der Timer0 läuft hier parallel zum (leeren)
|
40 | // Anweisungsblock in dieser while-Schleife!
|
41 | }
|
42 | }
|
43 | |
44 | ISR(TIMER0_OVF_vect) |
45 | {
|
46 | static uint8_t zaehler_bis_5s = 0; |
47 | |
48 | // LED an PD5 bei jedem Interrupt toggeln
|
49 | PORTD ^= (1<<PD5); |
50 | |
51 | // LED an PD6 alle 5s toggeln
|
52 | // 5000 ms = X * 250 ms => X = 20
|
53 | zaehler_bis_5s += 1; |
54 | if ( zaehler_bis_5s == 5000/250 ) |
55 | {
|
56 | PORTD ^= (1<<PD6); |
57 | zaehler_bis_5s = 0; |
58 | }
|
59 | }
|
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.