-         

Ergebnis 1 bis 1 von 1

Thema: Mein Dekoder für RC-5 in C im Interruptbetrieb

  1. #1
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.595

    Mein Dekoder für RC-5 in C im Interruptbetrieb

    Anzeige

    Hallo Alle,
    es wird hier eine Routine beschrieben zum Dekodieren des RC-5-Codes. Gundlage ist eine, von einem vorhandenen Timer verfügbare Zeitbasis. Der Timer kann ansonsten für andere, konstante Zeitaufgaben benutzt werden. Ein solcher Timer ist in vielen Programmen bereits vorhanden.

    Hintergrund:
    Mein bisher vorhandener RC-5-Dekoder läuft als Hauptprogramm - ich muss nach dem Aufruf warten, bis eine Taste gedrückt wird. Damit kann ich z.B. verschieden Tasks bzw. Modi in meinem MiniD0 oder WALL R starten/schalten. Ich wollte immer schon eine ähnliche Routine im Interruptbetrieb. Ich kenne den Code im RNWissen von SprinterSB - wollte aber mal versuchen, einen schlankeren Code zu schreiben, die knappe Variante von PDannegger aus mikrocontroller-nett ist mir zu undurchsichtig. Ausserdem interessierte mich die tatsächliche Codegestaltung (die einzelnen Bits) und die problemlose Ausgabe dieser Dinge auf ein übliches Terminal. Na ja, ansonsten: es gibt besser und schöner geschriebene C-Passagen.

    Der folgende Code beschreibt diese Routine(n), der "nackte" Code der Dekoder-IRS hat 23 Zeilen. Die Routine stellte das Befehlsbyte zur Verfügung, derzeit wird es in der Timer-IRS "gelöscht" - dort könnte es in eine FIFO o.ä. übertragen werden. Das ist hier nicht geschehen.

    Vielleicht nutzt jemandem das Ganze.

    Gegebenheit:
    Ein vorhandener Timer-Interrupt der als Bordzeit eingeführt wurde zur Zeitnahme verschiedener Sensoren und derzeit verschiedene Zeitabläufe steuert. Interruptabstand 50 µs, eine Zeitscheibe (zwischen zwei Interrupts) nenne ich tupsi =: Time Unit Per Sensor Interrupt.
    Der Sensor ist ein SFH5110, der in ähnlicher Schaltung wie beim asuro verwendet wird. Damit wird das Signal der Infrarotfernsteuerung invertiert auf den Controllerpin geschaltet.
    Der Code wurde für die RNControl mit mega1284/20 MHz geschrieben, ein Anpassung sollte leicht/wird möglich sein.

    Aufgabenstellung:
    RC-5-Dekoder im Interrupt
    Interruptquelle ist ein externer Interrupt, hier extINT2 am mega1284. Interruptauslöser ist ein SFH5110 in der Schaltung à la asuro.

    Erweiterte Aufgabe:
    Im Testbetrieb werden die Codebits und der Befehlscode dezimal über UART ausgegeben.

    Code:
    Das erste Codefenster zeigt die "nackte" Interruptroutine
    Das zweite Codefenster zeigt >>auszugsweise<< - aber hoffentlich komplett ALLE erforderlichen Definitionen und Deklarationen (keine Funktionsprototypen) und Codesequenzen.

    Anmerkungen:
    Die Zeit für 1 Codebit beträgt beim RC-5 1,778ms, in meinen tupsi à 50 µs sind das etwa 33 .. 38 Zeitscheiben, genauer: 35,56. Wegen der Toleranzen habe ich das entsprechende Zeitfenster - heisst bei mir RCbit_zt, auf 26 bis 44 tupsi gesetzt. Entsprechende Anpassungen sind erforderlich, wenn beim Verwenden der Routinen eine andere Zeitbasis zur Verfügung steht. Wenn innerhalb dieses zulässigen Zeitfensters eine Interrupt erfolgt, wird er ausgewertet und die Messzeit für das nächste Bit wieder auf Null gesetzt. Durch dieses Vorgehen "justiert" sich die Routine in weiten Grenzen auf die Fernsteuerung.

    Im Code wird über USART das Bitmuster des Codes ausgegeben. Es wird anschließend NUR das Befehlsbyte weiter verarbeitet (meine Billigst-IR-RC hat garkein Adressbyte) und auch das Togglebit wird nicht ausgewertet. Das Befehlsbyte wird ebenfalls auf USART ausgegeben - damit ist es einfach möglich, den Tastencode vorhandener Fernsteuerungen zu analysieren. Schließlich wird die Gesamtdauer eines Signalzyklus einer Fernsteuerung im Rahmen der Zeitbasis angegeben, damit die mögliche Reaktionszeit des Codes und Abweichungen der Fernsteuerung von der Standardfrequenz abgeschätzt werden können.

    Für Risiken und Nebenwirkungen wird nicht gehaftet. Eine kommerzielle Nutzung ist ausschließlich nur nach Rücksprache und meiner Zustimmung erlaubt.

    Codefenster eins
    Code:
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Start RC5-Decoding: Level (RC5prt & (1<<RC5pin)) ist low
    // =====               RC-5-DECOding-Byte (RCDECO) ist Null
    //                     RCvorsc >= 99  -- nur dann ist "vorher" länger high
    //              Es folgen 23 Zeilen relevanter Code zum Dekodieren
      if ((!(RC5prt & (1<<RC5pin))) && (!RCDECO) && (RCvorsc > 99))  //
      {                             //
        RCges_zt    =  18;          // ?? Gesamtzeit in tupsi f EINEN kplt CodeSATZ
        RCBptr      =  13;          // RC-5-Code: Bitpointer (0..13) f RC-5-Code-Word
        RCDECO |= ((uint16_t)1<<13 );        //
        sendUSART ("\t1");          //
        RCBptr      =  12;          // ... und pointer auf nächstes Bit
        RCbit_zt    =   0;          // Zeit für 1 Codebit 1,778ms, in tupsi 33 .. 38
      }                             //
      if (RCBptr >= 0)              //
      {                             //
        if ((RCbit_zt>26) && (RCbit_zt < 44)) // <<## gute Funktion, so bleibts
        {                             // Ist ein gültiges Bit erkannt worden ?
          if (!(RC5prt & (1<<RC5pin)))                // High oder low level ?
          {                         //
            RCDECO |= ((uint16_t)1<<RCBptr );  // Bei LOW schreib "1" weg
            sendUSART ("1");        //
          }                 // Ende if (!(RC5prt & (1<<RC5pin))) : High oder low
          if (RC5prt & (1<<RC5pin))  sendUSART ("0");
          RCBptr      -- ;            // ... und pointer auf nächstes Bit
          RCbit_zt    =   0;          // Zeit für 1 Codebit 1,778ms, in tupsi 33 .. 38
        }                   // Ende if ((RCbit_zt>26) && (RCbit_zt < 48))
      }             // Ende if (RCBptr >= 0)
    Codefenster zwei
    Code:
     #define        LCg     6       // gnLED2 auf PC6 - onboard RNControl
     volatile int16_t Izeit_1;      // Wertbereich int16: 32.767. uint16: 65.535
     volatile int16_t Izthrznt;     // Der zeitliche Horizont, z.B. 20000 für 2 sec
     volatile int16_t Isecundn;     // Sekunden Programmlaufzeit, 32.767 sec sind
                                    // 546,117 Minuten bzw. 9 Std
     volatile int16_t icntdwn;      // Countdownzähler (max 32767 = 9 Std)
    // ============================================================================== =
    // ===  RC-5_Daten, Daten fürs RC-5 Decoding
    // ============================================================================== =
     #define  RC5prt   PINB         // Eingangsport für RC5-Decoding
     #define  RC5pin   PB2          // Pointer auf gewählten Sensorpinn für RC-5
     volatile int16_t  RCCODE [12]; // 12 Words für komplette Codes + Flags + Reserve
     volatile uint8_t  RCCptr;      // Pointer auf den aktuellen Code
     volatile int16_t  RCDECO;      // Word für EINEN komplett dekodierten Code
     volatile int8_t   RCBptr;      // RC-5-Code: Bitpointer für RC-5-Code-Word
                                    //      beim Dekodieren. Beginn: 14 für Startbit 1
     volatile uint8_t  RC5roff;     // RC5-read-off    aus- (=1) / ein- (=0) -schalten
                                    // roff = 0 <=> Lesen ist ein, 1 <=> Lesen ist aus
    // - - - - - - - - - - - - - - -
    //      Zeiten
     volatile int16_t  RCbit_zt;    // Zeit für EIN Codebit 1,778ms, in tupsi 35,56
                                    //   <=> mit Toleranz 33 .. 38
     volatile int16_t  RCges_zt;    // ?? Gesamtzeit in tupsi für einen kplt. CodeSATZ
     volatile uint16_t RCvorsc;     // Vorstartcounter - TupsiZeit vor dem ersten Bit
     volatile uint16_t RCzeit1;     // RC-5-zeit. Wird im main genullt und im timer
                    // freilaufend+unkontrolliert hochgezählt wird bis zum Überlauf
    // ============================================================================== =
    // ============================================================================== =
    
    // ============================================================================== =
    // ===  Initialisierung fuer Timer2 mega168, m328, m1284 und Ähnliche
     void TC2TMR_init(void)         // Init Tmr/Cntr 2, 8-Bit auf 20 kHz = 50 µs
     {                         //
      TCCR2A |= (1<<WGM21);         // Timer im CTC-Mode, Top=OCR2A           doc S 157
      TCCR2B |= (1<<CS21);          // Prescaler 1/8 / Clock <- CPU           doc S 158
      OCR2A   = 124;                // Preset 124 für 50µs bei 20Mhz
      TIMSK2 |= (1<<OCIE2A);        // Tmr/Cntr2 CompareA interrupt enabled
      Izeit_1 = 0;                  // Laufzeit nullen - unabhängig von Isecndn !!
     }                      // Ende void TC2TMR_init(void)
    // ============================================================================== =
     
    // ============================================================================== =
    // ===  Nicht unterbrechbare ISR für timer2 => zählt hoch im Takt 20 kHz = 50 µs
     ISR(TIMER2_COMPA_vect)         // Vektor 7
     {                              //
      if (Izeit_1 <= Izthrznt)      //Interrupt-Timer = 1 ... 20 000 ... (1 sec blink)
      {                             //
        Izeit_1 ++;                 // Izeit_1 bleibt bis 32000 in der int16-Grenze
      }                             //
      else                  // in if (Izeit_1 <= Izthrznt) 
      {                             // ... Eine Sekunde ist voll =>
        Izeit_1 = 1;                // ansonsten: Rückstellen auf Eins
        icntdwn = icntdwn + 1;      // Countdownzähler hoch(!!)zählen
        PORTC ^=  (1<<LCg);         // gnLED auf Pin PC6 toggeln <=> Heartbeat
        Isecundn ++;                // Sekundenzähler hochtackern, max 9 Std
      }                     // Ende if (Izeit_1 < Izthrznt)
    // - -  Ende der eigentlichen Timer2-ISR
    // - - - - - - - - - - - - - - -
    // - -  Jetzt für RC-5-Analyse Zeiten etc.
      if (RC5prt & (1<<RC5pin))     // WENN RC5-pinn high; Encoder empfängt nichts
      {                             //      => zähle Vorstartcounter hoch
                                    // Vorstartcounter in IRS(INT2_vect) nullen
        RCvorsc ++;                 // RC-5-Vor-Sequenz-Counter bis 100 hochzählen
        if (RCvorsc > 100) RCvorsc = 100;     // Begrenze RCvors
      }                     // Ende if (RC5prt & (1<<RC5pin))
    // - - - - - - - - - - - - - - -
      RCbit_zt     ++;            // Zeit für 1 Codebit 1,778ms, in tupsi 33 .. 38
      RCzeit1      ++;            // Tupsicounter uint16_t für RC-5-Decoding
      RCges_zt     ++;
      if (RCges_zt >= 490 && RCDECO) // Endemarkierung RC-5-Deco  27Nov2012-15:22
      {                             //
        RCDECO      = 0;            //
      }                             //
      if ( RCzeit1 > 2000)          // "Reset" Dekodierung bei einer zehntel Sekunde
      {                             //
        RC5roff = 1;                //
        RCzeit1 = 0;                //
      }                             //
    // - - - - - - - - - - - - - - -
     return;                        //
    }                       // Ende ISR(TIMER2_COMPA_vect)
    // ============================================================================== =
    
    // ============================================================================== =
    // ===  Initialisierung fuer EXT_INT2 auf Pin PB2 bei m1284 für 
    //  Vector 4 {1-35}, Progr.addr. $0006 INT2 External Interrupt Request 2
    // ============================================================================== =
     void XTI_2_init( void )        // Init. INT 2 auf any edge für RC-5
     {    //   d.h. EICRA ISC20 = 1                   doc S67
    // - - - - - - - - - - - - - - - -
      EICRA   |= (1<<ISC20);        // Interrupt auf any edge
      EIMSK   |= (1<<INT2);         //  und erlaube INT2 in EIMSK
     }                      // Ende void XTI_2_init( void )
    // ============================================================================== =
    
    // ============================================================================== =
    // ===  ISR für EXT_INT2 auf Pin PB2 zum Dekodieren von RC-5
     ISR (INT2_vect)                //
     {                              //
      int16_t RCbb;  
      char wortadc[12];     // Übersetzungsfeld für Werteausgabe
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Start RC5-Decoding: Level (RC5prt & (1<<RC5pin)) ist low
    // =====               RC-5-DECOding-Byte (RCDECO) ist Null
    //                     RCvorsc >= 99  -- nur dann ist "vorher" länger high
      if ((!(RC5prt & (1<<RC5pin))) && (!RCDECO) && (RCvorsc > 99))  //
      {                             //
        RCges_zt    =  18;          // ?? Gesamtzeit in tupsi f EINEN kplt CodeSATZ
                            //  hier ein offset, weil ja 1/2 Bit vorbei ist
        RCBptr      =  13;          // RC-5-Code: Bitpointer (0..13) f RC-5-Code-Word
                    //   fängt auf Position 14! an mit >>13<< (0..13) für Startbit 1!
    //      Hauptaufgabe: Schreibe Bit ins Target
        RCDECO |= ((uint16_t)1<<13 );        //
        sendUSART ("\t1");
        RCBptr      =  12;          // ... und pointer auf nächstes Bit
        RCbit_zt    =   0;          // Zeit für 1 Codebit 1,778ms, in tupsi 33 .. 38
      }                             //
    // - - - - - - - - - - - - - - - -
      if (RCBptr >= 0)              //
      {                             //
        if ((RCbit_zt>26) && (RCbit_zt < 44)) // <<## gute Funktion, so bleibts
        {                             // Ist ein gültiges Bit erkannt worden ?
          if (!(RC5prt & (1<<RC5pin)))                // High oder low level ?
          {                         //
            RCDECO |= ((uint16_t)1<<RCBptr );  // Bei LOW schreib "1" weg
            sendUSART ("1");        //
          }                 // Ende if (!(RC5prt & (1<<RC5pin))) : High oder low
          if (RC5prt & (1<<RC5pin))  sendUSART ("0");
          RCBptr      -- ;            // ... und pointer auf nächstes Bit
          RCbit_zt    =   0;          // Zeit für 1 Codebit 1,778ms, in tupsi 33 .. 38
        }                   // Ende if ((RCbit_zt>26) && (RCbit_zt < 48))
      }             // Ende if (RCBptr >= 0)
    // - - - - - - - - - - - - - - - -
    //      TESTWEISE Ausgabe Codewort und Zeitbedarf
      if ((RCBptr < 0) && (RCges_zt < 1000))
      {                             //
        RCBptr      = 0;            // doppelte Ausgabe verhindern
        sendUSART("  => dez: ");    // Ausgabezeile eröffnen
        //  lo = word & 0x7f;  0x7F  wegen 7 Bit Befehlsbyte
        RCbb        = RCDECO & 0x7F;
        itoa(RCbb, wortadc, 10);    // aktueller Wert
        sendUSART(wortadc);         //  ... ausgeben.
        sendUSART(" , RCges_zt = ");    //  Neue Zeile
        itoa (RCges_zt, wortadc, 10);   // aktueller Wert
        sendUSART(wortadc);             //  ... ausgeben.
        sendUSART("\r\n");          //  Neue Zeile
      }                 // Ende if (RCBptr < 0)
    // - - - - - - - - - - - - - - - -
     }              // Ende ISR (INT2_vect)
    // ============================================================================== =
    So wie im Codefenster unten sieht ein Testlauf aus mit Ausgabe am Terminal von br@y. Die Ausgabe nach "... Aktion" wird vom vorgestellten Code geliefert : Bitmuster der gesamten Codesequenz, dezimale Entsprechung des sechsbittigen Befehlsbytes, Zeitdauer der Dekodierung vom Beginn des Codes bis zum Ende. Man kann auch schön die Funktion des Toggelbits (Bit 3) erkennen.

    Zum Zeitbedarf, hier in 50µs-tupsi: 482 tupsi zu 50 µs sind 24,2 ms; da das erste Halbbit fehlt - es kann ja erst auf die erste Flanke des Datentelegramms getriggert werden, die ist aber in der Mitte vom Startbit 1 - komme ich ziemlich genau auf die fast 25 ms der gesamten Telegrammlänge.

    Code:
     C501 R5M_x15 m1284p/20MHz 27Nov2012 15:28
     I2C >>400kHz [t05], I2C mit Taste [gelb], dann [OK] zu MoCo328
     Motoren rauf+runter mit Taste [P100]
     I2C-Slave ist Adresse :  132 dez = 0x84 ,
     Gute Funktion mit extINT2 für RC-5
     Aktuell - Zur-Verfügung-Stellung des RC-5-Code
    
     Aktiv :  Taste [MIX], [P100], [9] und [gelb]
    
    Bitte um Aktion _
     11000000010100  => dez: 20 , RCges_zt = 483
     11100000011001  => dez: 25 , RCges_zt = 482
     11000000100011  => dez: 35 , RCges_zt = 482
     11100000011011  => dez: 27 , RCges_zt = 482
     11000000001010  => dez: 10 , RCges_zt = 484
     11100000000110  => dez: 6 , RCges_zt = 483
    Rückmeldungen sind erwünscht.
    Geändert von oberallgeier (26.02.2013 um 14:25 Uhr) Grund: Richtigstellung : Befehlsbyte hat sechs Bits, nicht sieben :-/
    Ciao sagt der JoeamBerg

Ähnliche Themen

  1. RC5 Dekoder aus empfängt nur Nullen
    Von martin02 im Forum C - Programmierung (GCC u.a.)
    Antworten: 1
    Letzter Beitrag: 14.09.2010, 12:31
  2. SIRCS Dekoder!
    Von stowoda im Forum PIC Controller
    Antworten: 5
    Letzter Beitrag: 20.10.2005, 11:29
  3. Hilfe bei einem Telemetrie-Dekoder
    Von ricoderrichter im Forum Elektronik
    Antworten: 0
    Letzter Beitrag: 16.08.2005, 21:53
  4. [ERLEDIGT] Duo-LED durch Dekoder mit negativem Strom ansteuern?
    Von Iwan im Forum Elektronik
    Antworten: 6
    Letzter Beitrag: 10.08.2004, 14:22
  5. ACS Interruptbetrieb invertieren
    Von mgsimon im Forum Robby CCRP5
    Antworten: 1
    Letzter Beitrag: 07.03.2004, 18:57

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •