Forum: Compiler & IDEs Daewoo-Fernbedienungscode / Interrupt lässt sich nicht ausschalten


von Guido S. (Gast)


Angehängte Dateien:

Lesenswert?

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

von Uwe N. (ulegan)


Lesenswert?

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

von Guido S. (Gast)


Lesenswert?

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

von Uwe N. (ulegan)


Lesenswert?

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

von Guido S. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.