-         
Ergebnis 1 bis 9 von 9

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
    8.181

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

    Anzeige

    Praxistest und DIY Projekte
    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 13:25 Uhr) Grund: Richtigstellung : Befehlsbyte hat sechs Bits, nicht sieben :-/
    Ciao sagt der JoeamBerg

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

    Optimierung der RC-5-IR-Fernsteuerung für Roboter etc.

    Ein paar Schräubchen gedreht an der IR-Fernsteuerung (Schlechtwetterbeschäftigung).

    Seit meinen ersten Robotern – Dottie über WALL R und archie – erfolgt deren Steuerung mit ner alten TV-Fernbedienung von einem längst entsorgten Fernseher. Dessen IR-Code ist Philips RC-5, siehe z.B. Unterlagen von San Bergmans hier – mit den Feinheiten zum Manchestercode auf 36 kHz-Basis.

    Code:
    /* ============================================================================= =
       ============================================================================= =
            Beispiele für RC-5-Signalgang/Manchester-Codierung
     
      |       |  |       |  Bitdauer 2x889 µs (2*17,78 tupsi) => 1,778 ms/35,56 tupsi
      +---+   |  |   +---+  Für den Wert des Bits ist Übergang in Bitmitte massgebend
      |HHH|   |  |   |HHH|  
      |HHH+---+  +---+HHH|  ==> Übergang von 1 nach Null <=> Bitwert 0
      |Logic 0|  |Logic 1|  ==> Übergang von 0 nach 1    <=> Bitwert 1
                           
      Beispiel (Graphik zeigt neun Bits) :     
         |   |   |   |   |   |   |   |   |   | 
         | +-+-+ | +-+-+ | +-+ +-+-+ +-+ +-+ |  1 Bit   1,778 ms /  35,56 tupsi < s.u.
         | | | | | | | | | | | | | | | | | | | 14 Bit  24,892 ms / 497,84 tupsi
         +-+ | +-+-+ | +-+-+ +-+ | +-+ +-+ +-+    Gap 114     ms / 2800   tupsi
    Bit- |   |   |   |   |   |   |   |   |   | 
    Wert   1   0   1   0   1   1   0   0   0   
    // - - - - - - - - - - - - - - -
        Der Rest der RC-Variablen (die folgenden) ist im Prinzip unnötiger Schotter
        und wurde am 08 Nov 2013 entfernt (bis Rev. ~x30 enthalten)
    >>>>    Messung (26.6.2020) mit DISCOVERY_2 am Steckbrett mit zwei parallel     <<
    >>>>    geschalteten SFH5110 zeigt eine Varianz der Pulse zwischen              <<
    >>>>    ca. 850 µs und 980 µs  >>  entsprechend 17 (34) und 19,6 (39) tupsi     <<
        tupsi sind 50µs-Zeitscheiben einer Interruptroutine für heartbeat etc.
       ============================================================================= =
       =============================================================================*/
    Die Bedienung ist ab archie angepasst an die übliche TV-Fernbedienung: es gibt einerseits Ein-Tasten-Befehle (mute, START/STOP, vor(auf), zurück(ab), links, rechts, swap uvm). Implementiert ist aber auch die übliche 3-Ziffern-Kombination, die ich RC5-3 nenne. RC5-3 läuft bei archie wie beim Fernseher – wird eine Ziffer gedrückt, wartet der (Befehls-) Empfänger ne Weile auf eine zweite, danach ne Weile auf ne dritte Ziffer. Wird statt einer Ziffer eine andere Taste gedrückt, wird die laufende 3-Ziffern-Eingabe abgebrochen. Ist der 3ziffrige Befehl eingetippt, wird er sofort angesteuert/eingeleitet. Dauert die Pause nach einer Zifferneingabe zu lange, wird die laufende Eingabe abgebrochen. Als optische Eingabekontrolle dient eine grobpixelige LED-anzeige (12x10-Matrix – ne ehemalige PingPongPlatine), die auch in der untersten LED-Reihe einen kleinen „Strich“ als Busymarke beim RC5-3 zeigt.

    Zusätzlich ist bei archie natürlich zu wünschen, dass Befehle aus beliebigen Richtungen (rundum) empfangen werden. Es ist daher auf einen zuverlässigen Rundum-Empfang der Steuercodes zu achten. Dies erfolgt durch mehrere IR-Empfängerplatinchen. Verwendet werden die ICs SFH5110 oder nach dessen Abkündigung TL1838.

    Weiter soll der Decoder das Doppeln von Tasten verhindern.

    Grobskizze des Decoders:
    - IR-Decoding vom IR-Empfänger auf einem PCINT
    - Start Timer sobald ein Signal (LOW) erkannt wird nach einer Pause von mind. 4,95 ms.
    ..Durch diese Pause ist sichergestellt, dass kein Zeichen "kurz vorher" akzeptiert wird.
    - Decodieren der 14 Bits des Manchestercodes
    - Wird danach ein Zifferncode erkannt –
    ..weiter zu RC5-3 Abschnitt, sonst Befehlsaufruf je nach Codewert.
    Probleme machte mir bisher z.B. das Doppeln – wenn man zu lange drückt oder die Fernsteuertasten „doppeln“. Der Code wurde dahin überarbeitet. Dazu wurden einige längst beabsichtigte Messungen mit zwei verschiedenen IR-Empfängertypen durchgeführt. Der Signalausgang dieser Empfänger wurde am Eingangsport des Controllers zusammengeschlossen.

    Die Messungen (ANALOG-DIGILENT2) zeigen Signalgänge:
    1. Zwei TL1838 an EINEM Controllerport – Abgriff am Porteingang; 1 ms/DIV.

    2. Zwei TL1838 an EINEM Controllerport – Abgriff am Porteingang; 100 µs/DIV.

    3. High-Low-Übergang von TL1838-bl und SFH5110-ge; 1 µs/Div. Der modernere
    ..…TL1838 (blaue Linie) schaltet viel sauberer.

    4. IR-Sendediode (in der Fernbedienung) und TL1838. Der IR-Empfänger schaltet
    …..nach ca. 8 36-kHz-Pulsen auf low. 100 µs/DIV.

    5. IR-Sendediode (in der Fernbedienung) und SFH5110. Der IR-Empfänger schaltet
    ..…nach ca. 6 36-kHz-Pulsen auf low. 100 µs/DIV.

    Schaltung des IR-Empfängers :
    . . . . . Vcc . . . . > . . 100R . . - . . > . .SFH5110/Vcc . . . sinngemäß mit TL1838
    . . . . . GND . . . . > . . SFH5110/GND . . . . . . . . . . . . . . sinngemäß mit TL1838
    . . . . . SigOut . . .> . .SFJ5110/SigOut < 22k>Vcc-in . . .. sinngemäß mit TL1838
    =>=>=> Diese Schaltung mit dem kleinen Vorschaltwiderstand und dem 22k-PullUp bietet eine sehr sichere Funktion.
    Kondensatoren (z.B. lt. Datenblatt) stören ! ! !

    Vielleicht interessiert´s.
    Ciao sagt der JoeamBerg

  3. #3
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.858
    Zitat Zitat von oberallgeier Beitrag anzeigen
    Rückmeldungen sind erwünscht.
    Nur mal eine Sache: Du bist sehr großzügig mit volatile. Ist das wirklich nötig? Das bremst den Optimizer komplett aus. Und du gibst Strings im Interrupt-Handler über die serielle aus. Das könnte dir deinen 50µs Interrupt ziemlich aus dem Tritt bringen.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.181
    Danke Klebwax für Deine Rückmeldung.

    .. Du bist sehr großzügig mit volatile. Ist das wirklich nötig? Das bremst den Optimizer komplett aus ..
    Es ist sicher nicht immer nötig. Ach wenns nur das wäre. Meine C-Kenntnisse gehen ja zurück auf einen autodidaktischen Crashkurs vor etlichen Jahren. Wenig gelernt und inzwischen manches vergessen; ich nenne das ja eher Cäh als C. Ja, vergessen ist keine Entschuldigung - und manchmal mühe ich mich wegen irgendwelcher (mir) unerklärlicher Fehler lange ab . . . In meinem Fall macht selbst Übung nicht mehr den Meister. Deiner Anmerkung werde ich aber mal gewissenhaft nachgehen.

    .. du gibst Strings im Interrupt-Handler über die serielle aus. Das könnte dir deinen 50µs Interrupt ziemlich aus dem Tritt bringen ..
    Das tuts sicher - auch wenn ich z.B. mein PingPong-Display mit 256 KBd anspreche. Dabei ist der Standardstring drei Zeichen lang - an die 120 µs - siehe hier. Abgesehen von dieser Display-Anzeige wird im Standardbetrieb kaum was über UART gesendet, da läuft fast alles per I²C - sicher auch nicht problemlos. Allerdings meine ich, dass meine Zeitmessung den Verlust von manchem Takt verkraften kann bzw. verkraftet - jedenfalls merke ich den meisten Bewegungen von archie nicht wirklich irgendwelche Taktlosigkeiten an.

    .. Das könnte dir deinen 50µs Interrupt ziemlich aus dem Tritt bringen ..
    Noch schlimmer: meine Regelungsroutine läuft alle 10 ms >innerhalb< der ansonsten sehr kurzen Timer-ISR. Dazu mal n Zitat aus meinem Laborbuch (-file) :

    ............30. August 15; MoC4_x26 Messung Umfangsgeschwindigkeit
    ........................// Der Zeitbedarf für die Regelung wurde gemessen: MoC4_tmr26.c, GOULD 20 MHz
    ........................// rgl_nn-Aufruf und regelpre..=0 ohne Regelung 1,5 µs, mit Regelung 5,1 µs
    ............Bei Aufruf Regelung void rgl_12(void) OHNE Geschwindigkeitsvorgabe (bzw sspeed <= 3) wird
    ............ja die Funktion sofort wieder verlassen, siehe Quellcode in ~mot~.
    ............Die gemessene Zeit ist unabhängig davon, ob in den Regelfunktionen rgl_nn der Interrupt erlaubt
    ............wird (sozusagen nested interrupts) oder nicht ! ! !

    Aber meine Controller laufen ja mit 20 MHz; fast durchwegs Atmel, auch nanoclones etc.

    Danke Klebwax!
    Geändert von oberallgeier (28.06.2020 um 09:46 Uhr)
    Ciao sagt der JoeamBerg

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von Moppi
    Registriert seit
    18.03.2018
    Beiträge
    1.980
    Blog-Einträge
    15
    Meine Faustregel:

    Volatile immer bei allen Variablen, die in einer Interrupt-Service-Routine genutzt werden, außerhalb der ISR deklariert sind (Zählervariablen z.B.) und deren Inhalt nicht verloren gehen darf, wenn die ISR beendet wird.

    Variablen die nur innerhalb der ISR gebraucht werden, solange die ISR ausgeführt wird, würde ich, für mich, innerhalb der ISR deklarieren (ohne volatile). Dann könnten sie vom Compiler optimiert werden, dass evtl. nur Register- statt Speicherzugriffe stattfinden.

    Ich habe ein RETURN gefunden, ich glaube, das ist nicht notwendig:

    // - - - - - - - - - - - - - - -
    return; //
    } // Ende ISR(TIMER2_COMPA_vect)

    MfG

    - - - Aktualisiert - - -

    Zitat Zitat von oberallgeier Beitrag anzeigen
    Aber meine Controller laufen ja mit 20 MHz; fast durchwegs Atmel, auch nanoclones etc.!
    Würde ich prüfen, ob das notwendig ist. Ich meine, mit steigernder Geschwindigkeit steigt i.R. auch der Strombedarf. Muss man mal im Datenblatt schauen.

  6. #6
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.181
    Nur mal eine Sache: Du bist sehr großzügig mit volatile. Ist das wirklich nötig? Das bremst den Optimizer komplett aus ..
    So, die Geschichte mit dem volatile hab ich mal (wieder :-/ ) durchgeackert. Ich hoffe, dass ich dieses Typenattribut (type qualifier) zukünftig auf wirklich notwendige Fälle beschränken werde und mit der Zeit die vorhandenen, unnötigen Fälle vollständig entferne. Ich halte es im Auge.

    .. Ich habe ein RETURN gefunden, ich glaube, das ist nicht notwendig ..
    Stimmt, unnötig. Ein Relikt aus gaaanz frühen Jahren. Aber ein Vergleich der *.lls-Datei zeigt, dass der Compiler sich damit zu keiner unnötigen Aktion verleiten lässt.

    .. Controller laufen ja mit 20 MHz; .. prüfen, ob das notwendig ist .. mit steigernder Geschwindigkeit steigt i.R. auch der Strombedarf ..
    Was heißt notwendig? Die ganze Controllersammlung im archie (aktuell neun Platinen - ein Master und 8 Slaves) hat ne Menge zu tun. Zusammen mit den Motoren ist der gesamte Leistungsbedarf bei knapp 10 Watt - in Ruhe, bei Bewegung (Gestik) bis über vierzig Watt, im Fahrbetrieb darüber - da sind ein paar Milliwatt mehr ohne Bedeutung. Der Vorteil liegt nicht zuletzt darin, dass z.B. die Kommunikation UART und I²C durch den gleichen, hohen Quarztakt nach meiner Erfahrung ziemlich sicher wurde - trotz der Durchseuchung mit Interrupts.
    Geändert von oberallgeier (28.06.2020 um 16:09 Uhr)
    Ciao sagt der JoeamBerg

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von Moppi
    Registriert seit
    18.03.2018
    Beiträge
    1.980
    Blog-Einträge
    15
    Was heißt notwendig?
    Manchmal braucht man die hohe Frequenz für die Aufgaben gar nicht, da tut es auch weniger.
    Wenn es um Störanfälligkeit geht, wird es mit zunehmender Frequenz i.R. nicht besser, sondern eher ist das Gegenteil der Fall.


    MfG

  8. #8
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.858
    Zitat Zitat von Moppi Beitrag anzeigen
    Volatile immer bei allen Variablen, die in einer Interrupt-Service-Routine genutzt werden, außerhalb der ISR deklariert sind (Zählervariablen z.B.) und deren Inhalt nicht verloren gehen darf, wenn die ISR beendet wird.
    Da hat volatile nichts zu suchen und bewirkt auch nichts. Variablen, die die Laufzeit einer Funktion überleben sollen ansonsten aber nur von ihr verwendet werden, erzeigt man local und macht sie static.

    Volatile ist dann nötig, wenn sowohl main() als auch der Interrupthandler sie verwenden. Oder wenn zwei Interrupthandler auf sie zugreifen. Allgemeiner, wenn man damit rechnen muß, daß sich eine Variable außerhalb des gerade laufenden Programmkontextes ändert, muß sie volatile (unbeständig) deklariert werden.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  9. #9
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.181
    .. Volatile ist dann nötig, wenn .. Oder wenn zwei Interrupthandler .. Allgemeiner, wenn man ..
    Ich freue mich. Ich habs ja nur mit den Quellen Kernighan/Ritchie, im microcontroller.net (z.B. hier), im RNWissen, z.B. hier und bei den AVR-Freaks durchgearbeitet. Aber ziemlich so hatte ich das verstanden (Verwendung in UND ausserhalb einer ISR und so . . .).
    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, 11:31
  2. SIRCS Dekoder!
    Von stowoda im Forum PIC Controller
    Antworten: 5
    Letzter Beitrag: 20.10.2005, 10:29
  3. Hilfe bei einem Telemetrie-Dekoder
    Von ricoderrichter im Forum Elektronik
    Antworten: 0
    Letzter Beitrag: 16.08.2005, 20:53
  4. Antworten: 6
    Letzter Beitrag: 10.08.2004, 13:22
  5. ACS Interruptbetrieb invertieren
    Von mgsimon im Forum Robby CCRP5
    Antworten: 1
    Letzter Beitrag: 07.03.2004, 17:57

Berechtigungen

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