-
        

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 14

Thema: Probleme mit RC5 Implementierung

  1. #1

    Probleme mit RC5 Implementierung

    Anzeige

    Hallo zusammen,

    ich habe hier ein kleines Problem und zwar möchte ich einen Roboter über eine RC5-Fernbedienung steuern.
    Hardware: AT90S2313 / 4MHz

    Ich habe den Beispielcode aus dem Wiki verwendet und ein bischen angepasst an den 2313, allerdings funktioniert es nicht

    Code:
    #define F_CPU 4000000
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdint.h>
    #include <stdlib.h> // itoa
    #include <util/delay.h>
    
    #define UART_BAUD_RATE 9600
    
    #define RC5_INT0 0
    #define RC5_INT1 1
    
    #define RC5_ALL 0xff
    
    typedef struct
    {
    	uint8_t code;
    	uint8_t addr;
    	volatile signed char flip;
    } rc5_t;
    
    #ifndef RC5_INT
    #define RC5_INT      RC5_INT0
    #endif  /* RC5_INT */
      
    #ifndef RC5_PRESCALE
    #define RC5_PRESCALE 256 // default: 1024
    #endif  /* RC5_PRESCALE */
    
    /* ******************************************************************************** */
    
    rc5_t rc5;
    
    /* ******************************************************************************** */
    
    #ifndef F_CPU
    #error Please define F_CPU
    #endif /* !F_CPU */
    
    /* µs for a whole bit of RC5 (first & second part) */
    #define RC5_BIT_US   (64*27)
    
    #define RC5_TICKS \
            ((uint8_t) ((uint32_t) (F_CPU / 1000 * RC5_BIT_US / 1000 / RC5_PRESCALE)))
            
    #define RC5_DELTA \
            (RC5_TICKS / 6)
            
    typedef union 
    {
            uint16_t w;
            uint8_t  b[2];
    } code_t;
    
    static code_t code;
    static uint8_t rc5_addr;
    
    /* Number of Bits received so far */
    /* Number of Interrupts occured so far */
    static uint8_t nbits;
    static uint8_t nint;
    
    /* ******************************************************************************** */
            
    void rc5_init (uint8_t addr)
    {
            nint  = 0;
            nbits = 0;
            rc5.flip = -1;
            
            rc5_addr = addr;
            
    #if (RC5_PRESCALE==1024)
            TCCR0 = (1 << CS02) | (1 << CS00);
    #elif   (RC5_PRESCALE==256)
            TCCR0 = (1 << CS02);
    #elif   (RC5_PRESCALE==64)
            TCCR0 = (1 << CS01) | (1 << CS00);
    #else
    #error This RC5_PRESCALE is not supported
    #endif /* RC5_PRESCALE */
            
            /* INTx on falling edge */
            /* clear pending INTx */
            /* enable INTx interrupt */
    #if (RC5_INT == RC5_INT0)               
            MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
            GIFR = (1 << INTF0);
            /* ATMEGA: GICR |= (1 << INT0); */
            GIMSK |= (1 << INT0);
    #elif (RC5_INT == RC5_INT1)             
            MCUCR = (MCUCR | (1 << ISC11)) & ~ (1 << ISC10);
            GIFR = (1 << INTF1);
            GICR |= (1 << INT1);
    #else
    #error please define RC5_INT
    #endif /* RC5_INT */
    }
    
    /* ******************************************************************************** */
    
    //SIGNAL (SIG_OVERFLOW0)
    ISR(TIMER0_OVF0_vect)
    {
            TIMSK &= ~(1 << TOIE0);
            
            uint8_t _nbits = nbits;
            code_t _code = code;
            
            if (26 == _nbits)
            {
                    _nbits++;
                    _code.w <<= 1;
            }
            
            if (27 == _nbits 
                    && _code.b[1] >= 0x30 /* AGC == 3 */
                    && 0 > rc5.flip)
            {
                    uint8_t _rc5_code;
                    uint8_t _rc5_addr;
                    /* we do the bit manipulation stuff by hand, because of code size */
                    _rc5_code = _code.b[0] & 0x3f; /* 0b00111111 : #0..#5 */
                    _code.w <<= 2;
                    _rc5_addr = _code.b[1] & 0x1f; /* 0b00011111 : #6..#10 */
                    
                    if (rc5_addr & 0x80
                            || rc5_addr == _rc5_addr)
                    {
                            rc5.code = _rc5_code;
                            rc5.addr = _rc5_addr;
                            signed char flip = 0;
                            if (_code.b[1] & 0x20) /* 0b00100000 : #11 */
                                    flip = 1;
                            rc5.flip = flip;
                    }
            }
            
            nint = 0;
            nbits = 0;
            
            /* INTx on falling edge */
            /* clear pending INTx */
            /* enable INTx interrupt */
    #if (RC5_INT == RC5_INT0)               
            MCUCR = (MCUCR | (1 << ISC01)) & ~ (1 << ISC00);
            GIFR = (1 << INTF0);
            /* ATMEGA: GICR |= (1 << INT0); */
            GIMSK |= (1 << INT0);
    #elif (RC5_INT == RC5_INT1)             
            MCUCR = (MCUCR | (1 << ISC11)) & ~ (1 << ISC10);
            GIFR = (1 << INTF1);
            GICR |= (1 << INT1);
    #endif
    }
    
    /* ******************************************************************************** */
    
    #if (RC5_INT == RC5_INT0)               
    //SIGNAL (SIG_INTERRUPT0)
    ISR(INT0_vect)
    #elif (RC5_INT == RC5_INT1)             
    SIGNAL (SIG_INTERRUPT1)
    #endif /* RC5_INT */
    {
            code_t _code = code;
            uint8_t _nint = nint;
            
            uint8_t tcnt0 = TCNT0;
            TCNT0 = 0;
            
            if (0 == _nint)
            {
                    /* INTx on both edges */
    #if (RC5_INT == RC5_INT0)               
                    MCUCR = (MCUCR | (1 << ISC00)) & ~ (1 << ISC01);
    #elif (RC5_INT == RC5_INT1)             
                    MCUCR = (MCUCR | (1 << ISC10)) & ~ (1 << ISC11);
    #endif /* RC5_INT */
            
                    TIFR = (1 << TOV0);
                    TIMSK |= (1 << TOIE0);
                    _code.w = 0;
            }
            else
            {
                    /* Number of bits of the just elapsed period */
                    uint8_t n = 1;
             
                    /* Bits received so far */
                    uint8_t _nbits = nbits;
            
                    /* is TCNT0 close to RC5_TICKS or RC5_TICKS/2 ? */
                    if (tcnt0 > RC5_TICKS + RC5_DELTA)
                            goto invalid;
                    else if (tcnt0 < RC5_TICKS/2 - RC5_DELTA)
                            goto invalid;
                    else if (tcnt0 > RC5_TICKS - RC5_DELTA)
                            n = 2;
                    else if (tcnt0 > RC5_TICKS/2 + RC5_DELTA)
                            goto invalid;
                    
                    /* store the just received 1 or 2 bits */
                    do
                    {
                            _nbits++;
                            if (_nbits & 1)
                            {
                                    _code.w <<= 1;
                                    _code.b[0] |= _nint & 1;
                            }
                    } 
                    while (--n);
                    
                    if (0)
                    {
                            invalid:
                            
                            /* disable INTx, run into Overflow0 */
    #if (RC5_INT == RC5_INT0)               
                            /* ATMEGA: GICR &= ~(1 << INT0); */
                            GIMSK &= ~(1 << INT0);
    #elif (RC5_INT == RC5_INT1)             
                            GICR &= ~(1 << INT1);
    #endif /* RC5_INT */
    
                            _nbits = 0;
                    }
                    
                    nbits = _nbits;
            }
    
            code = _code;
            nint = 1+_nint;
    }
    
    
    // putc fuer AVR mit einem UART (z.B. AT90S8515)
    int uart_putc(unsigned char c)
    {
        while(!(USR & (1 << UDRE)))  /* warte, bis UDR bereit */
        {
        }
     
        UDR = c;                     /* sende Zeichen */
        return 0;
    }
      
    /* puts ist unabhaengig vom Controllertyp */
    void uart_puts (char *s)
    {
        while (*s)
        {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
            uart_putc(*s);
            s++;
        }
    }
    
    int main(void) {
    
        //char str[10] = "C:../A:..";
        char str[5];
        
        // Status Port
        DDRB = 0xFF;
        PORTB = 0x11;
    
        // RC5 Initialisierung
        DDRD &= ~(1<<PD2);          /* INT0 muss Eingang sein! */
        rc5_init(RC5_ALL);          /* Initialisierung RC5 */
    
        // UART
        UCR |= (1<<TXEN);
        UBRR = F_CPU / (UART_BAUD_RATE * 16L) - 1;
        
        sei();                      /* Interrupts zulassen */
        
        uart_puts("RC5Test running.\r\n");
        
        while (1) {
            if (rc5.flip == -1) {
                /* Mach irgendwas */
            } else {
                /* RC5 Code empfangen */
                /* Ja, dann rc5.code merken und evtl. rc5.addr */
                /* falls man die braucht und nicht sowieso schon kennt */
                //uint8_t code = rc5.code;
                //uint8_t addr = rc5.addr;
                /* und auf naechstes Zeichen warten */
                //rc5.flip = -1;
                
                //sprintf(str,"CODE: %02x / ADR: %02x\r\n",rc5.code,rc5.addr);
                uart_puts("CODE:");
                itoa(rc5.code,str,16);
                uart_puts(str);
                uart_puts(" / ADR:");
                itoa(rc5.addr,str,16);
                uart_puts(str);
                uart_puts("\r\n");
                
                
                uart_puts(str);
                rc5.flip = -1;
            }
            _delay_ms(50);
            _delay_ms(50);
            _delay_ms(50);
            _delay_ms(50);
            _delay_ms(50);
            PORTB++;
        }
    }
    Das Programm sendet jeden empfangenen Code inklusive Adresse über die serielle Schnittstelle an den PC... zumindest sollte es das.

    Vielleicht kann mir jemand mit dem Quellcode helfen. Ich bin mir sicher, dass es nicht an der Hardware liegt. Habe den Aufbau mit der Application Note AVR410 und einem AT90S1200 erfolgreich getestet.

    In dem Beispiel aus dem Wiki wird ein ATMEGA mit 16MHz verwendet. Der Prescaler wurde von mir von 1024 auf 256 reduziert => ich verwende ja schließlich nur 1/4 der Taktfrequenz.

    Wenn das Programm geladen ist erscheint wird über die serielle Schnittstelle nur die Meldung, dass das Programm läuft, allerdings wird scheinbar keine Taste erkannt.

    Bin für jede Hilfe dankbar.
    Gruß
    T.

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Du hast

    #define RC5_INT1 1

    scheinst aber Port D2 (INT0) verwenden zu wollen. Dann musst du

    #define RC5_INT0

    und RC5_INT1 *nicht* definieren, auch nicht zu 0! (Da wird nicht mit #if getestet, sondern mit #ifdef/#ifndef)
    Disclaimer: none. Sue me.

  3. #3
    Hallo SprinterSB,

    danke für die Antwort.
    Du hast schon recht, es wird INT0 verwendet, aber die #Define-Angaben sind so korrekt.
    Die Konstante die bestimmt, ob INT0 oder INT1 verwendet wird ist RC5_INT und diese Konstante kann entweder den Wert von RC5_INT1 oder RC5_INT0 annehmen.

    Weiter unten im Quellcode sind dann immer solche Abfragen vorhanden:
    #if (RC5_INT == RC5_INT0)
    ...
    #elif (RC5_INT == RC5_INT1)
    ...
    #endif /* RC5_INT */

    Über uart-Ausgaben konnte ich auch schon nachweisen, dass tatsächlich Interruptsausgelöst werden, wenn ich Tasten auf der Fernbedienung drücke.
    Ich vermute das Problem liegt eher irgendwie beim Timing oder so...

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Ja stimmt, ist ne Zeit lang her daß ich das geschrieben habe... Ich wollte es immer schon mal umschreiben so daß es besser verständlich ist.

    Bist du sicher, daß die Fernbedienung RC5 absetzt und nicht irgend nen RC5-Dialekt?

    Mit 4MHz sollte der µC eigentlich schnell genug sein. Was mit den Timimngs nicht stimmt ist so trocken schwer zu sagen.

    Um rauszufinden, was eine Fernbedienung so treibt, hab ich mal das da geschrieben. Aber Vorsicht, ist undokumentierter Hack aus der Anfängerzeit
    Angehängte Dateien Angehängte Dateien
    Disclaimer: none. Sue me.

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    08.05.2006
    Beiträge
    7

    Teilweise geht's

    Hi!

    Ich habe genau das gleiche Problem. Nur habe ich einem Atmega16 mit einem 16MHz Quarz am laufen.

    Zuerst ging mal gar nix, bis ich erstens alle Präprozessoranweisungen hinausgeschmissen habe und zweitens alle möglichen Fernbedienungen im Haus getestet hatte.

    So ein LED habe ich auch in die ISR eingebaut, leuchtet auch schön brav auf, immer und egal wo ich bei welcher fernbedienung drücke.

    nun kam ich auf die Idee mal alle knöpfe auf allen Fernbedienungen zu drücken, und siehe da, bei ein paar funktionierts glatt.

    Nur leider nur bei ein paar Knöpfen.

    Was mich noch stutzig macht, ist dass ich im Terminal verschiedene Adressen der gleichen Fernbedienung erhalte. (zb. 10 und 11)


    Es wäre super, wenn auch mir jemand helfen könnte!!

    PS. Hat sich da vieleicht in letzter Zeit der "Übertragungsstandart" geändert oder so??


    mfg

    philipp

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Ich bin grad ein neues Projekt am aufziehen und habe einen ATtiny bei F_CPU = 1MHz laufen. Funktionierte auf Anhieb der RC5-Code. Natürlich waren ein paar Anpassungen nötig, zB quick & dirty:
    Code:
    #define RC5_PRESCALE 64
    
    #ifdef __AVR_ATtiny2313__
    #define GICR GIMSK
    #define GIFR EIFR
    #endif // __AVR_ATtiny2313__
    Sowie TCCR0 --> TCCR0B.

    Hast du einen PullUp am RC5-Eingang? Evtl andere ISR-Routinen, die die IRQ-Latenz hochtreiben? Passen RC5-EMpfänger und Sender?
    Disclaimer: none. Sue me.

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    08.05.2006
    Beiträge
    7
    Hi SprinterSB!

    Ich bin auch gerade beim Zusammenbauen einer RC5-Routine, nur will sie noch nicht do richtig.

    Ich warte einfach mit dem Int0 bis eine erste fallende Flanke vom Sendor kommt. Dann starte ich damit einen Timer (T0 um genau zu sein), der nach berechneten 1328µsec das erste Viertel des nächaten Bits erreicht.
    Nach dieser Zeit schalte ich mal alle ints aus, und lese den Sensor aus. ist er eins, rotiere ich eine eins in mein MSB und schalte den ext Int auf fallende Flanke. Genau das umgekehrte tue ich bei nullsignal.

    Ich denke mal, dass da alle Lösungswege mehr oder weniger identisch sind.

    Ich werde da mal ein wenig weiterprobieren, wird schon geht!

    grüße
    philipp

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    08.05.2006
    Beiträge
    7
    Achja, noch was. Deine RC5 Funktion, synchronisiert die sich bei jeder Flanke neu, oder nur auf das erste Startbit.

    Habe eben deine noch mal probiert, bei einer Fernstuerung gingen semtliche Knöpfe, bei der anderen kein einziger!

    Könnte das vielleicht auch auf eine zu ungenaue 36khz modulation des Senders zurückzuführen sein?

  9. #9
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Falls der Sender nicht auf 36kHz moduliert (sindern zB 56kHz), bekommst du natürlich nix mit.

    Die Demodulation/Verstärkung etc erledigt der IR-EMpfänger wie TSOP17**, TSOP18**.

    Ich hatte auch schon TSOP1738 für 36kHz im Einsatz, ging auch. So schmalbandig sind die nicht, evtl. geht die Empfindlichkeit etwas runter.

    Meine RC5-Implementierung ist unabhängig von der 36kHz-Modulation. Sie geht davon aus, der der IR-Empfänger sich darum kümmert.

    Synchronisation geschieht bei jeder Flanke.
    Disclaimer: none. Sue me.

  10. #10
    Neuer Benutzer Öfters hier
    Registriert seit
    08.05.2006
    Beiträge
    7
    Ah, ok. Werde heute Abend mal Messen, ob der Sensor bei der anderen Fernsteuerung überhaupt etwas mitkriegt.

    Vielen Dank vorerst!

    Grüße
    philipp

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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