Hallo! Folgendes kleines Programm habe ich geschrieben, um einen Fernbedienungscode zu empfangen und zu entschlüsseln. So wie das Programm dort steht, funktioniert es. Allerdings hätte ich gerne den Timerinterrupt gesperrt, wenn der Code komplett empfangen wurde. Leider zeigen die Befehle "TIMSK &= ~(1 << OCIE1A);" und "cli();" keine Wirkung. Woran könnte das liegen. Ich möchte eigentlich nur den Timerinterrupt sperren - das wäre also "TIMSK &= ~(1 << OCIE1A);". Kann ich das während des externen Interrupts nicht machen? Warum? Wenn ihr dieses Verhalten testen möchtet, dann könnt ihr am Anfang des Quelltextes wahlweise "#define Test_OCIE1A", "#define Test_CTC" oder "#define Test_CLI" herein- oder herausnehmen. Bei mir wird der Timerinterrupt (Compare) auch ausgelöst, wenn ich "cli();" benutze. Kann mir jemand dieses Verhalten erklären? Danke und Gruß aus Oranienburg Guido
Ein cli()im Interrupt geht nicht, da der reti Befehl am Ende der ISR den gesperrten Interrupt wieder freigibt. Siehe http://www.mikrocontroller.net/articles/AVR-Tutorial:_Interrupts Gruß Uwe
Hallo! @Uwe Danke für die Antwort. Mir ist bekannt, dass ein RETI den Interrupt wieder freigibt. Doch aber nur für den Vektor der Interruptroutine, die damit beendet wird. Einen Einfluss auf das globale Interruptregister hat RETI doch nicht? Oder ist es in C anders als in ASM? Das würde ja bedeuten, dass ein Interrupt nicht durch einen anderen Interrupt unterbrochen werden kann. Ist das so? Gruß Guido
Im Instruction set steht: RETI Returns from interrupt. The return address is loaded from then STACK and the Global Interrupt Flag is set. Beim Eintritt in die ISR wird das globale Flag gelöscht und durch den RETI wieder gesetzt. Also kann eine ISR nicht durch einen anderen Interrupt unterbrochen werden. Es sei denn, man hat selbst das Flag durch sei() innerhalb der ISR wieder gesetzt. So ist es auch in der AVR libc Dokumentation beschrieben. Gruß Uwe
Das mit dem I im SREG habe ich inzwischen mit Hilfe von AVR Studio herausbekommen. Trotzdem großen Dank. Ich habe jetzt verstanden, dass beim AVR ein INT nicht durch einen anderen unterbrochen werden kann. Es sei denn, ich erlaube es explizit. Warum ich den Timer-INT nicht abschalten konnte, kann ich trotzdem nicht erklären. Da der Timer Interrupt für dieses Programm nicht wirklich benötigt wird, habe ich ihn entfernt. Ich danke Allen, die sich mit mir Gedanken gemacht haben. Hier ist noch der geänderte Code. Viel Spaß bei der weiteren Verwendung. Ach, wen es interessiert: auf meiner Universalfernbedienung (URC22D-8A) ist der DEAWOO-Code auf VCR mit dem Code 040.
1 | /*#########################################################################################
|
2 | |
3 | Auswertung des Daewoo-Fernbedienungscodes
|
4 | |
5 | Achtung! Dies ist nur eine Studienversion, die noch keine weitere Funktionalität hat.
|
6 | |
7 | Das Programm wurde erstellt von Guido S.
|
8 | |
9 | ATMega8
|
10 | |
11 | #########################################################################################*/
|
12 | |
13 | #include <avr/io.h> |
14 | #include <avr/interrupt.h> |
15 | |
16 | uint8_t FlankenZaehler; |
17 | uint16_t Adr_OPCode; |
18 | uint16_t VergZeit; |
19 | |
20 | |
21 | void Ausgabe(uint8_t Wert) |
22 | {
|
23 | // an PortB2 bis B6 und PortC0 bis C2 sind LEDs angeschlossen
|
24 | // somit kann ein Byte angezeigt werden
|
25 | |
26 | // Aufbereitung der Daten und Ausgabe an die richtigen Pins
|
27 | // die Bits werden negiert, damit man auf eine richtige Darstellung kommt
|
28 | // => Bit von Wert = "1" - LED an; Bit von Wert = "0" - LED aus
|
29 | PORTB = ~((Wert << 1) & 0b00111110); |
30 | PORTC = ~(Wert >> 5); |
31 | }
|
32 | |
33 | |
34 | ISR(INT1_vect) |
35 | {
|
36 | /* Interrupt Code */
|
37 | |
38 | // hier findet die Zeitmessung statt
|
39 | // Messung beginnt beim Eintreffen des ersten EXT1-Interrupts
|
40 | |
41 | void Fehlerbehandlung(void) |
42 | {
|
43 | // Flankenzähler wird auf 0 gestellt - eine neue Sequenz kann beginnen
|
44 | FlankenZaehler = 0; |
45 | }
|
46 | |
47 | // Timer auslesen
|
48 | VergZeit = TCNT1; // Read TCNT1 // seit dem Int ist TCNT1 um 43 erhöht |
49 | TCNT1 = 0; // Timer soll von 0 beginnen; für diesen Befehl werden weitere 6 Takte benötigt |
50 | |
51 | #define Tolleranz 8 // Werte zwischen 5 und 15 haben sich als sinnvoll gezeigt
|
52 | |
53 | #if (F_CPU <= 6553500)
|
54 | // Diese Berechnung geht nur bis 6,5535 MHz
|
55 | #define T10ms (F_CPU/100)
|
56 | #define T8msh (((F_CPU/1000)*8)+((F_CPU/10000)*Tolleranz))
|
57 | #define T8msl (((F_CPU/1000)*8)-((F_CPU/10000)*Tolleranz))
|
58 | #define T4msh (((F_CPU/1000)*4)+((F_CPU/10000)*Tolleranz))
|
59 | #define T4msl (((F_CPU/1000)*4)-((F_CPU/10000)*Tolleranz))
|
60 | #define T055msh (((F_CPU/100000)*55)+((F_CPU/100000)*3*Tolleranz))
|
61 | #define T055msl (((F_CPU/100000)*55)-((F_CPU/100000)*3*Tolleranz))
|
62 | #define T045msh (((F_CPU/100000)*45)+((F_CPU/100000)*3*Tolleranz))
|
63 | #define T045msl (((F_CPU/100000)*45)-((F_CPU/100000)*3*Tolleranz))
|
64 | #define T145msh (((F_CPU/100000)*145)+((F_CPU/100000)*3*Tolleranz))
|
65 | #define T145msl (((F_CPU/100000)*145)-((F_CPU/100000)*3*Tolleranz))
|
66 | #else
|
67 | // Bei F_CPU > 6,5535 MHz wird der Vorteiler auf 8 gestellt und die Zeiten berechnen sich so:
|
68 | #define T10ms (F_CPU/800)
|
69 | #define T8msh (((F_CPU/8000)*8)+((F_CPU/80000)*Tolleranz))
|
70 | #define T8msl (((F_CPU/8000)*8)-((F_CPU/80000)*Tolleranz))
|
71 | #define T4msh (((F_CPU/8000)*4)+((F_CPU/80000)*Tolleranz))
|
72 | #define T4msl (((F_CPU/8000)*4)-((F_CPU/80000)*Tolleranz))
|
73 | #define T055msh (((F_CPU/800000)*55)+((F_CPU/800000)*3*Tolleranz))
|
74 | #define T055msl (((F_CPU/800000)*55)-((F_CPU/800000)*3*Tolleranz))
|
75 | #define T045msh (((F_CPU/800000)*45)+((F_CPU/800000)*3*Tolleranz))
|
76 | #define T045msl (((F_CPU/800000)*45)-((F_CPU/800000)*3*Tolleranz))
|
77 | #define T145msh (((F_CPU/800000)*145)+((F_CPU/800000)*3*Tolleranz))
|
78 | #define T145msl (((F_CPU/800000)*145)-((F_CPU/800000)*3*Tolleranz))
|
79 | #endif
|
80 | |
81 | // hier beginnt die Abfrage des Flankenzählers
|
82 | if (FlankenZaehler == 0) |
83 | {
|
84 | // Timer 1 einstellen - Timer wird als CTC genutzt
|
85 | // Mode 4
|
86 | // CLKi/o / 1 oder CLKi/o / 8
|
87 | TCCR1A = 0; |
88 | #if (F_CPU <= 6553500)
|
89 | TCCR1B = (1 << WGM12) | (1 << CS10); |
90 | #else
|
91 | TCCR1B = (1 << WGM12) | (1 << CS11); |
92 | #endif
|
93 | FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten |
94 | }
|
95 | else if (FlankenZaehler == 1) |
96 | { // die erste Periode müssen 8 ms lang sein |
97 | if ((VergZeit > T8msl) & (VergZeit < T8msh)) |
98 | {
|
99 | FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten |
100 | }
|
101 | else
|
102 | {
|
103 | // Flanke ist nicht im erwarteten Zeitraum gekommen
|
104 | Fehlerbehandlung(); |
105 | }
|
106 | }
|
107 | else if ((FlankenZaehler == 2) | (FlankenZaehler == 20)) |
108 | { // diese Perioden müssen 4 ms lang sein |
109 | if ((VergZeit > T4msl) & (VergZeit < T4msh)) |
110 | {
|
111 | FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten |
112 | }
|
113 | else
|
114 | {
|
115 | // Flanke ist nicht im erwarteten Zeitraum gekommen
|
116 | Fehlerbehandlung(); |
117 | }
|
118 | }
|
119 | else if ((FlankenZaehler & 1) == 1) |
120 | { // wenn Flankenzähler ungerade, dann muss die Zeit 0,55 ms sein |
121 | if ((VergZeit > T055msl) & (VergZeit < T055msh)) |
122 | {
|
123 | if (FlankenZaehler == 37) |
124 | { // wenn Flankenzähler 37 ist, dann ist das Stopp-Bit erreicht |
125 | // hier wird nicht mehr auf die nächste Flanke gewartet,
|
126 | // da das Stopp-Bit nur eine halbe Welle ist
|
127 | // an dieser Stelle wurde der Code komplett empfangen
|
128 | // JUCHU!!!
|
129 | TCCR1A = 0; // CTC abschalten |
130 | TCCR1B = 0; // CTC abschalten |
131 | Ausgabe((uint8_t)(Adr_OPCode >> 8)); // Ausgabe des OP-Codes |
132 | //Ausgabe((uint8_t)(Adr_OPCode)); // das ist die Geräteadresse
|
133 | FlankenZaehler = 0; |
134 | }
|
135 | else
|
136 | { // bei allen anderen Flanken ist alles OK und der Flankenzähler wird erhöht |
137 | FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten |
138 | }
|
139 | }
|
140 | else
|
141 | {
|
142 | // Flanke ist nicht im erwarteten Zeitraum gekommen
|
143 | Fehlerbehandlung(); |
144 | }
|
145 | }
|
146 | else if ((FlankenZaehler & 1) == 0) |
147 | { // hier kommt die Auswertung der 2. Halbwelle, die die Information beinhaltet, |
148 | // ob es eine eine "0" oder "1" ist
|
149 | if ((VergZeit > T045msl) & (VergZeit < T145msh)) |
150 | {
|
151 | FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten |
152 | if ((VergZeit > T045msl) & (VergZeit < T045msh)) |
153 | // das erkannte Bit ist eine "0"
|
154 | {
|
155 | Adr_OPCode = (Adr_OPCode >> 1); |
156 | }
|
157 | else if ((VergZeit > T145msl) & (VergZeit < T145msh)) |
158 | // das erkannte Bit ist eine "1"
|
159 | {
|
160 | Adr_OPCode = (Adr_OPCode >> 1) | (1 << 15); |
161 | }
|
162 | else
|
163 | {
|
164 | // Flanke ist nicht im erwarteten Zeitraum gekommen
|
165 | Fehlerbehandlung(); |
166 | }
|
167 | }
|
168 | else
|
169 | {
|
170 | // Flanke ist nicht im erwarteten Zeitraum gekommen
|
171 | Fehlerbehandlung(); |
172 | }
|
173 | }
|
174 | }
|
175 | |
176 | |
177 | int main(void) |
178 | {
|
179 | // Variablen initialisieren
|
180 | FlankenZaehler = 0; |
181 | |
182 | // Interrupts initialisieren
|
183 | MCUCR |= (1 << ISC10); MCUCR &= ~(1 << ISC11); //EXT1 soll bei jeder Flanke ausgelöst werden |
184 | GICR |= (1 << INT1); // EXT1 Interrupt erlauben |
185 | sei(); // global Interrupt erlauben |
186 | |
187 | // Ports initialisieren
|
188 | // PB1 bis PB5 als Ausgang; an diesen Ports ist je eine LED mit Vorwiderstand gegen +5V angeschlossen
|
189 | DDRB |= (1 << PB1) | (1 << PB2) | (1 << PB3) | (1 << PB4) | (1 << PB5); |
190 | // PC0 bis PC2 als Ausgang; an diesen Ports ist je eine LED mit Vorwiderstand gegen +5V angeschlossen
|
191 | DDRC |= (1 << PC0) | (1 << PC1) | (1 << PC2); |
192 | |
193 | // diese Ausgabe ist nur zum Test und soll mir zeigen, dass die CPU bereit ist
|
194 | Ausgabe(0b10100101); |
195 | |
196 | // Das Hauptprogramm ist eine Endlosschleife, es wird durch Interrupts unterbrochen
|
197 | while(1) |
198 | {
|
199 | }
|
200 | }
|
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.