logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Pomóżcie zrozumieć kod dekodujący rc5 (sorry)

Neghe 03 Gru 2010 22:51 1508 1
REKLAMA
  • #1 8822718
    Neghe
    Poziom 10  
    Założyłem ten temat, bo chciałbym (i prawdę mówiąc muszę) zrozumieć program znaleziony, nawet chyba u Was na forum, dekodujący sygnał rc5.
    Historia jest typowa: "projekt, którego nie chcę, a który muszę."
    Dzięki z góry za pomoc. Nie besztajcie mnie zbyt mocno.

    Wspomniany kod:
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    
    
    #define RC5BitHigh()    (bit_is_set(PIND,PD3))
    #define RC5BitLow()     (bit_is_clear(PIND,PD3))
    #define WAITFORTIMER()  { while ( timerflag == 0); timerflag = 0; }
    
    // CLK = 4MHz
    #define TIMER_0_CNT 0xC9     //  111us = 1/( (CLK/8)/(0xFF-0xC9) )
    #define RC5BITREF1  6
    #define RC5BITREF2  11
    #define RC5BITREF3  14
    #define IR_int_enable GIFR|=(1<<INT1);GICR|=(1<<INT1)
    #define IR_int_disable GICR&=~(1<<INT1)
    
    
    volatile uint8_t timerflag;  
    volatile unsigned int    rc5data;
    
    
    void rc5_init()
    {
    	DDRD  &= ~(1<<PD3);           // konfiguracja PD3 jako wejście
        PORTD |= (1<<PD3);           // enable internal pull-up resistors
     
       	MCUCR|=_BV(ISC11); // ext. int. activated by falling edge
       	MCUCR&=~_BV(ISC10);
       	GIFR = (1<<INTF1); // clear ext. int. flag
       	GICR|=_BV(INT1); // enable ext. int.
    }
    
    
    SIGNAL(SIG_OVERFLOW0)  
    {
        timerflag = 1;               // set global variable
        TCNT0 = TIMER_0_CNT;         // reset counter to get this interrupt again
    }
    
    SIGNAL(SIG_INTERRUPT1)
    {
    	IR_int_disable;      //wylaczenie przerwan zewnetrznych
    	sei();
        unsigned char   timer, i;
        // init timer/Counter2   
        TCCR0 = 0x02;                    // use CLK/8 prescale
        TCNT0 = TIMER_0_CNT;             // set timer T/16 = 111us
        TIMSK |= (1<<TOIE0);             // enable TCNT0 overflow interrupt
        TIMSK &=~(1<<TOIE2);             // disable TCNT2 overflow interrupt
       
        // measure startbit
        timerflag = 0; timer = 0;
        while ( RC5BitLow() && (timer < RC5BITREF2) ) {
            WAITFORTIMER();
            timer++;
        }
        if ( (timer > RC5BITREF1) && (timer < RC5BITREF2) ) {
            // startbit ok, decode
    
            // wait T/4: synchronize in the middle of first half of second bit
            while ( timer < RC5BITREF3 ) {
                WAITFORTIMER();
                timer++;
            }
           
            // read the remaining bits
            rc5data = 1;
            for (i=0; i<13; i++) {
                rc5data <<= 1;
                if ( RC5BitHigh() ) {
                    rc5data |= 0x0001;
                    // wait max T/2 for H->L transition (middle of next bit)
                    timer = 0;
                    while ( RC5BitHigh() && (timer < 16) ) {
                        WAITFORTIMER();
                        timer++;
                    }
                }else{
                    rc5data &= ~0x00001;
                    // wait max T/2 for L->H transition (middle of next bit)
                    timer = 0;
                    while ( RC5BitLow() && (timer < 16) ) {
                        WAITFORTIMER();
                        timer++;
                    }
                }                   
                if ( timer == 16 ) {
                    rc5data = 0x0000;   // error, next bit not found
                    return;
                }
               
                // wait 3/4 T: await next bit
                for ( timer=0; timer < 12 ; timer++) WAITFORTIMER();
            }
    
        }else {
            rc5data = 0x0000;  // error, invalid RC-5 code
        }
    
        TCCR0=0;
        TIMSK &=~(1<<TOIE0);              // disable TCNT0 overflow interrupt
        TIMSK |= (1<<TOIE2);              // enable TCNT2 overflow interrupt
    	IR_int_enable;
    }
    
    int main()
    {
    	DDRD=0;;//Porty D jako wejścia
    	rc5_init();
    	sei();
    	while(1)
    	{
       		if(rc5data)
       		{
          		PORTB=0x00;
       		}
    	}
    } 
    


    Mam (w schemacie tzn) 4Mhz(atmega16a), w kodzie determinuje to wartość makra TIMER_0_CNT, dzięki któremu wypracowany będzie czas 111us, co który przepełniać się będzie 8-bitowy licznik.
    I rozumiem to tak: przychodzi przerwanie z dekodera IR(tsop1736), wywoływana jest procedura obsł. przerwania w której na początku wyłączane są przerwania zewnętrzne, żeby móc dalej zdekodować sygnał. (to jeszcze, jeszcze rozumiem).
    Pierwszy bit jest startowy, ma zawsze wartość "1"(czyli w połowie bitu zmiana 0->1) więc w pętli:
    
        while ( RC5BitLow() && (timer < RC5BITREF2) ) {
            WAITFORTIMER();
            timer++;
        }
    

    czekamy dopóki wartość na PD3 to "0" lub do 1221us(czyli mniej niż 0.75 bitu) i za pętlą mamy niby zdekodowany ten pierwszy bit startu.
    
            // wait T/4: synchronize in the middle of first half of second bit
            while ( timer < RC5BITREF3 ) {
                WAITFORTIMER();
                timer++;
            }
    

    Ta pętla, wdł. mnie czeka do 1554us, co nawet nie jest drugim bitem, natomiast z komentarza wynika, że ma to być środek połowy drugiego bitu:(
    Dalej jest niby odczytywanych 13 bitów(2gi bit startu, toggle bit, adres, komenda), tak że:
    rc5data = 1 jest przesuwane z każdym przebiegiem pętli (1 bo ten drugi bit startu chyba?) w którym sprawdzany jest stan PD3, niby w chwili T/4. Jeśli "1" to jest ustawiana jedynka w rc5data jeśli "0" to 0.
    I nawet tutaj mam wątpliwość, bo jeśli w pierwszej połowie bitu jest "1" to będzie zmiana z 1->0, czyli "0".
    Rozpieprzyło mi się to w głowie - pomóżcie.
  • REKLAMA
  • #2 8986017
    Neghe
    Poziom 10  
    Nie doczekałem się odpowiedzi. Przeczekałem to, przespałem się, siadłem do tego drugi raz i zrozumiałem. Napiszę więc co aby ew pomóc np. studentowi informatyki który nie lubi mikroinformatyki. Jednak na końcu analizowania kodu pojawiły się jeszcze niejasności, więc prosiłbym o pomoc tutaj.

    Atmega ustawiona jest tak, aby przerwanie wywoływało opadające zbocze.
    Pomóżcie zrozumieć kod dekodujący rc5 (sorry)
    Pierwsze opadające zbocze pojawia się na końcu pierwszego bitu S1. W tym momencie wywoływane jest przerwanie, w którym na początku zostaje zmodyfikowany rejestr GICR, tak aby nie były wywoływane kolejne przerwania INT1(jeśli nie korzysta się z innych przerwań można po prostu wywołać cli() która zablokuje przerwania - bit I w SREG na 0).

    Pierwsza pętla while czeka do momentu w którym na PD3 pojawi się 1 lub minie 1,221ms(1,776ms trwa bit). W ostateczności, jeśli wszystko pójdzie dobrze, jesteśmy w czasie pomiędzy 0,666ms a 1,221ms - jak pojawi się "1", czyli w połowie bitu będzie to ponad 889us.
    W drugiej pętli czekamy do czasu 1,554ms.
    Te wszystkie czasy dotyczą DRUGIEGO STARTOWEGO bitu S2.
    Dalej następuje zapis do zmiennej rc5data kolejnych bitów (13-stu): S2(zawsze "1"), Toggle Bit, 5 bitów adresu, 6 bitów komendy.

    Aha i tutaj pojawiają się jeszcze wątpliwości, związane z sytuacją, gdy np.
    Pomóżcie zrozumieć kod dekodujący rc5 (sorry)
    jesteśmy w 3/4 bitu toggle i czekamy "while ( RC5BitHigh() && (timer < 16) )".
    W połowie następnego bitu jest 0, więc pętla się kończy, a dalej w programie mamy jeszcze:
    
                for ( timer=0; timer < 12 ; timer++) 
    				WAITFORTIMER();
    

    czekanie 3/4 czasu bitu, co by się sprawdziło gdybyśmy byli na początku bitu a nie w jego połowie.
    Więc gdybyście to wyjaśnili byłoby super.

    PS.
    Czy można tak zmodyfikować ten kod, że:
    
           if (timer <= 5) {
                for ( timer=0; timer < 12 ; timer++) 
    				WAITFORTIMER();
           }
    
REKLAMA