Hi,
eigentlich ist eine ganz einfache Sache, den Timer0 im 8-Bit Modus zum
überlaufen zu bringen und dann per Interrupt einen Port-Pin kippen.
Aber bei mir geht das nicht mit den Zeiten die ich haben will. Auch im
AVR-Studio 4 (ganz neu installiert) geht das nicht.
Prinzip: Port D4 bis D7 Ausgänge, Timer0 Overflow Inteerrupt
abschalten, alle Interrupts freigeben, sleep()-Funktion aufrufen in
einer while(1)-Endlosschleife. In der sleep()-Funktion wird der
Prescaler auf 256 eingestellt, TOV0 Flag im TIFR0 auf 1 setzen
(Interrupt löschen), in TIMSK0 das TOIE0 Flag auf 1 (Timer Interrupt
enable). Jetzt in "if(waittime)", darin wird immer in TIMSK0 das
TOIE0 Flag auf 1 gesetzt (interrupt enable). Läuft der Timer über, soll
die ISR angesprungen werden. In der ISR wird die Variable 'waittime'
decrementiert und der PortD invertiert. Dann wieder raus in die
if(waittime)-Schleife. Ist waittime auf 0 angekommen soll der Timer0
Overflow Interrupt abgeklemmt werden. Und dann geht's wieder von vorne
los. Ergebnis: Jedesmal, wenn der Timer0 Interrupt aufkreuzt, wird der
PortD invertiert, theoretisch. Tut es auch, aber nicht mit den Zeiten,
wie es sein sollte. Wenn ich die Zeiten mittels TCNT0 Register
variieren will, dann darf ich da nur den Wert 255 reinschreiben oder
eben nix, auch keine 0. Wenn ich das mache, passiert am PortD nix mehr.
Ich habe absolut keine Erklärung dafür. Die sleep-Funktion soll hier
erstmal nur 1 ms verbummeln.
Hier der Code:
1 | #include <avr/io.h>
|
2 | #include <avr/interrupt.h>
|
3 |
|
4 | void sleep(unsigned long waittime);
|
5 | void wait(void);
|
6 |
|
7 | static volatile unsigned int waittime;
|
8 |
|
9 | int main(void)
|
10 | {
|
11 | DDRD = 0xF0; // Port D4...7 Output
|
12 | PORTD = 0xFF; // Port D4...7 aus
|
13 |
|
14 | TIMSK0 &= ~(1<<TOIE0); // Timer Overflow Interrupt Enable 0
|
15 | ausschalten
|
16 |
|
17 | sei();
|
18 |
|
19 | while(1) // Warteschleifentest, Parameter in ms
|
20 | sleep(1000);
|
21 |
|
22 | return 0; // damit der gcc nich rummotzt
|
23 | }
|
24 |
|
25 |
|
26 | void sleep(unsigned long waittime)
|
27 | {
|
28 | // Timer 0, 8-Bit initialisieren
|
29 | //TCNT0 = 255; // 29 Inkrementierungen bis Interrupt -> 29 x 34.722us
|
30 | = 1.00694 ms
|
31 | TCCR0B = (1<<CS02); // Timer 0, Prescaler = 256 f. Wartezeiten von
|
32 | 34.722 us pro TCNT0 Inkermentierung
|
33 | TIFR0 = (1<<TOV0);
|
34 | TIMSK0 = (1<<TOIE0);
|
35 |
|
36 | waittime = 1; // zu Testzwecken reingedängelt
|
37 | if(waittime)
|
38 | {
|
39 | TIMSK0 |= (1<<TOIE0); // Timer Overflow Interrupt Enable 0
|
40 | einschalten
|
41 | //asm volatile("NOP");// tu_was_gescheites();
|
42 | }
|
43 | else
|
44 | TCCR0B &= ~((1<<CS00) | (1<<CS01) | (1<<CS02)); // Timer Stop
|
45 | }
|
46 |
|
47 | // Timer 0 Overflow
|
48 | void ISR (_VECTOR(16)) // war ISR(SIG_OVERFLOW0)
|
49 | {
|
50 | //waittime--;
|
51 | PORTD = ~PORTD;
|
52 | }
|
Ich habe den COde übrigens auch schon mit AVRStudio 4 simuliert. Läuft
das TCNT0 über, wird nicht die ISR angesprungen, sondern die erste
Zeile in der main-Funktion (SW-Reset). Das passiert auch, wenn ich die
ISR-Fkt gegen die
austausche.
HW: ATmega48 auf einem STK200
SW: gcc 3.4. bzw. AVR-Studio4 & winavr (heute gezogen)