/*######################################################################################### Auswertung des Daewoo-Fernbedienungscodes Achtung! Dies ist nur eine Studienversion, die noch keine weitere Funktionalität hat. Das Programm wurde erstellt von Guido S. ATMega8 #########################################################################################*/ #include <avr/io.h> #include <avr/interrupt.h> // die nächsten Zeilen sind nur zur Veranschaulichung meiner Frage //#define Test_OCIE1A // Werte können sein: CTC, CLI oder OCIE1A #define Test_CTC // Werte können sein: CTC, CLI oder OCIE1A //#define Test_CLI // Werte können sein: CTC, CLI oder OCIE1A uint8_t FlankenZaehler; uint16_t Adr_OPCode; uint16_t VergZeit; void Ausgabe(uint8_t Wert) { // an PortB2 bis B6 und PortC0 bis C2 sind LEDs angeschlossen // somit kann ein Word angezeigt werden // Aufbereitung der Daten und Ausgabe an die richtigen Pins // die Bits werden negiert, damit man auf eine richtige Darstellung kommt // => Bit von Wert = "1" - LED an; Bit von Wert = "0" - LED aus PORTB = ~((Wert << 1) & 0b00111110); PORTC = ~(Wert >> 5); } ISR(INT1_vect) { /* Interrupt Code */ // hier findet die Zeitmessung statt // Messung beginnt beim Eintreffen des ersten EXT1-Interrupts void Fehlerbehandlung(void) { // Flankenzähler wird auf 100 gestellt und dient der weiteren Bearbeitung // FlankenZaehler = 100; #if defined (Test_OCIE1A) // Werte können sein: CTC, CLI oder OCIE1A TIMSK &= ~(1 << OCIE1A); // Timer-Interrupt sperren #endif #if defined (Test_CTC) // Werte können sein: CTC, CLI oder OCIE1A TCCR1A = 0; // CTC abschalten TCCR1B = 0; // CTC abschalten #endif #if defined (Test_CLI) // Werte können sein: CTC, CLI oder OCIE1A cli(); // Disable interrupts #endif FlankenZaehler = 0; } // Timer auslesen cli(); // Disable interrupts VergZeit = TCNT1; // Read TCNT1 // seit dem Int ist TCNT1 um 43 erhöht TCNT1 = 0; // Timer soll von 0 beginnen; für diesen Befehl werden weitere 6 Takte benötigt sei(); // Enable interrupts #define Tolleranz 8 // Werte zwischen 5 und 15 haben sich als sinnvoll gezeigt #if (F_CPU <= 6553500) // Diese Berechnung geht nur bis 6,5535 MHz #define T10ms (F_CPU/100) #define T8msh (((F_CPU/1000)*8)+((F_CPU/10000)*Tolleranz)) #define T8msl (((F_CPU/1000)*8)-((F_CPU/10000)*Tolleranz)) #define T4msh (((F_CPU/1000)*4)+((F_CPU/10000)*Tolleranz)) #define T4msl (((F_CPU/1000)*4)-((F_CPU/10000)*Tolleranz)) #define T055msh (((F_CPU/100000)*55)+((F_CPU/100000)*3*Tolleranz)) #define T055msl (((F_CPU/100000)*55)-((F_CPU/100000)*3*Tolleranz)) #define T045msh (((F_CPU/100000)*45)+((F_CPU/100000)*3*Tolleranz)) #define T045msl (((F_CPU/100000)*45)-((F_CPU/100000)*3*Tolleranz)) #define T145msh (((F_CPU/100000)*145)+((F_CPU/100000)*3*Tolleranz)) #define T145msl (((F_CPU/100000)*145)-((F_CPU/100000)*3*Tolleranz)) #else // Bei F_CPU > 6,5535 MHz wird der Vorteiler auf 8 gestellt und die Zeiten berechnen sich so: #define T10ms (F_CPU/800) #define T8msh (((F_CPU/8000)*8)+((F_CPU/80000)*Tolleranz)) #define T8msl (((F_CPU/8000)*8)-((F_CPU/80000)*Tolleranz)) #define T4msh (((F_CPU/8000)*4)+((F_CPU/80000)*Tolleranz)) #define T4msl (((F_CPU/8000)*4)-((F_CPU/80000)*Tolleranz)) #define T055msh (((F_CPU/800000)*55)+((F_CPU/800000)*3*Tolleranz)) #define T055msl (((F_CPU/800000)*55)-((F_CPU/800000)*3*Tolleranz)) #define T045msh (((F_CPU/800000)*45)+((F_CPU/800000)*3*Tolleranz)) #define T045msl (((F_CPU/800000)*45)-((F_CPU/800000)*3*Tolleranz)) #define T145msh (((F_CPU/800000)*145)+((F_CPU/800000)*3*Tolleranz)) #define T145msl (((F_CPU/800000)*145)-((F_CPU/800000)*3*Tolleranz)) #endif // hier beginnt die Abfrage des Flankenzählers if (FlankenZaehler == 0) { // Timer 1 einstellen - Timer wird als CTC genutzt // Mode 4 // CLKi/o / 1 oder CLKi/o / 8 OCR1A = T10ms; // entspricht 10 ms TCCR1A = 0; #if (F_CPU <= 6553500) TCCR1B = (1 << WGM12) | (1 << CS10); #else TCCR1B = (1 << WGM12) | (1 << CS11); #endif TIMSK |= (1 << OCIE1A); // Timer-Interrupt erlauben FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten } else if (FlankenZaehler == 1) { // die erste Periode müssen 8 ms lang sein if ((VergZeit > T8msl+43) & (VergZeit < T8msh+43)) { FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten } else { // Flanke ist nicht im erwarteten Zeitraum gekommen Fehlerbehandlung(); } } else if ((FlankenZaehler == 2) | (FlankenZaehler == 20)) { // diese Perioden müssen 4 ms lang sein if ((VergZeit > T4msl) & (VergZeit < T4msh)) { FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten } else { // Flanke ist nicht im erwarteten Zeitraum gekommen Fehlerbehandlung(); } } else if ((FlankenZaehler & 1) == 1) { // wenn Flankenzähler ungerade, dann muss die Zeit 0,55 ms sein if ((VergZeit > T055msl) & (VergZeit < T055msh)) { if (FlankenZaehler == 37) { // wenn Flankenzähler 37 ist, dann ist das Stopp-Bit erreicht // hier wird nicht mehr auf die nächste Flanke gewartet, // da das Stopp-Bit nur eine halbe Welle ist // an dieser Stelle wurde der Code komplett empfangen // JUCHU!!! #if defined (Test_OCIE1A) // Werte können sein: CTC, CLI oder OCIE1A TIMSK &= ~(1 << OCIE1A); // Timer-Interrupt sperren #endif #if defined (Test_CTC) // Werte können sein: CTC, CLI oder OCIE1A TCCR1A = 0; // CTC abschalten TCCR1B = 0; // CTC abschalten #endif #if defined (Test_CLI) // Werte können sein: CTC, CLI oder OCIE1A cli(); // Disable interrupts #endif Ausgabe((uint8_t)(Adr_OPCode >> 8)); // Ausgabe des OP-Codes //Ausgabe((uint8_t)(Adr_OPCode)); // das ist die Geräteadresse FlankenZaehler = 0; } else { // bei allen anderen Flanken ist alles OK und der Flankenzähler wird erhöht FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten } } else { // Flanke ist nicht im erwarteten Zeitraum gekommen Fehlerbehandlung(); } } else if ((FlankenZaehler & 1) == 0) { // hier kommt die Auswertung der 2. Halbwelle, die die Information beinhaltet, // ob es eine eine "0" oder "1" ist if ((VergZeit > T045msl) & (VergZeit < T145msh)) { FlankenZaehler++; // Flankenzähler erhöhen und auf neue Flanke warten if ((VergZeit > T045msl) & (VergZeit < T045msh)) // das erkannte Bit ist eine "0" { Adr_OPCode = (Adr_OPCode >> 1); } else if ((VergZeit > T145msl) & (VergZeit < T145msh)) // das erkannte Bit ist eine "1" { Adr_OPCode = (Adr_OPCode >> 1) | (1 << 15); } else { // Flanke ist nicht im erwarteten Zeitraum gekommen Fehlerbehandlung(); } } else { // Flanke ist nicht im erwarteten Zeitraum gekommen Fehlerbehandlung(); } } } ISR(TIMER1_COMPA_vect) { // Der Timer ist auf 10ms eingestellt // Wenn der Interrupt ausgelöst wird, ist die max. Zeit weit überschritten // Die Zeit wird gemessen, indem der Zählerstand des Timers ausgelesen wird // Flankenzähler zurückstellen, um auf eine neue Sequenz zu warten FlankenZaehler = 0; // diese Ausgabe soll mir signalisieren, dass ich in dieser Interruptroutine war Ausgabe(0b11111111); // EXT1 Interrupt erlauben GICR |= (1 << INT1); } int main(void) { // Variablen initialisieren FlankenZaehler = 0; // Interrupts initialisieren MCUCR |= (1 << ISC10); MCUCR &= ~(1 << ISC11); //EXT1 soll bei jeder Flanke ausgelöst werden GICR |= (1 << INT1); // EXT1 Interrupt erlauben sei(); // global Interrupt erlauben // Ports initialisieren DDRB |= (1 << PB1); // PB1 als Ausgang; an diesem Port ist eine LED mit Vorwiderstand gegen +5V angeschlossen DDRB |= (1 << PB2); // PB2 als Ausgang; an diesem Port ist eine LED mit Vorwiderstand gegen +5V angeschlossen DDRB |= (1 << PB3); // PB2 als Ausgang; an diesem Port ist eine LED mit Vorwiderstand gegen +5V angeschlossen DDRB |= (1 << PB4); // PB2 als Ausgang; an diesem Port ist eine LED mit Vorwiderstand gegen +5V angeschlossen DDRB |= (1 << PB5); // PB2 als Ausgang; an diesem Port ist eine LED mit Vorwiderstand gegen +5V angeschlossen DDRC |= (1 << PC0); // PB2 als Ausgang; an diesem Port ist eine LED mit Vorwiderstand gegen +5V angeschlossen DDRC |= (1 << PC1); // PB2 als Ausgang; an diesem Port ist eine LED mit Vorwiderstand gegen +5V angeschlossen DDRC |= (1 << PC2); // PB2 als Ausgang; an diesem Port ist eine LED mit Vorwiderstand gegen +5V angeschlossen // diese Ausgabe ist nur zum Test und soll mir zeigen, dass die CPU bereit ist Ausgabe(0b10100101); // Das Hauptprogramm ist eine Endlosschleife, es wird durch Interrupts unterbrochen while(1) { } }