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

Dekodowanie IR RC5, Atmega32->Atmega8

bisz 25 Mar 2011 09:23 5883 10
REKLAMA
  • #1 9319782
    bisz
    Poziom 18  
    Witam. Na zlecenie piszę pewien projekt, którego częścią jest dekodowanie sygnału z pilota Rc5. Z początku zrobiłem to na mojej eksperymentalnej płytce z układem
    ATmega32, gdzie dolutowałem czujnik w powietrzu. Ustawiłem procka na wewnętrzny rezonator 4 MHz, gdyż taki udało mi się znaleźć na internecie działający przykład dekodowania Rc5, no i ruszyło, i działało prawidłowo. Rozbudowałem projekt o wszystko inne co zlecił mi zleceniodawca, aż w końcu wykonałem końcową płytkę ze wszystkimi niezbędnymi bajerami na ATmega8, którego taktowanie ustawiłem tak samo jak ATmegę32 - na 4 MHz Int RC Osc. Program skompilował się bez żadnych przeróbek - co najwyżej zmiana pinu na którym był podłączony czujnik IR, reszta bez zmian. Efekt - na Atmega8 nie działa za nic w świecie. Wypuściłem na terminal UART aby cokolwiek obserwować co dzieje się w procku ale nic. po prostu nie dekoduje. Pytanie : Czy jest jakaś różnica między tymi prockami o której nie wiem, która może mieć wpływ na niepoprawne/brak dekodowania Rc5, mimo tej samej częstotliwości oscylatora? Może kwestia jakichś innych fuse-bitów ? A może wewnętrzny oscylator ma pewną odchyłkę i z timerów nie wychodzi właściwa częstotliwość do dekodowania.

    Dla jasności załączam kod
    Plik uart.h pominę gdyż transmisja szeregowa działa prawidłowo.

    test.c :
    
    #include <inttypes.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include "uart.h"
    #include "rc5.h"
    
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    #define cbi(port, bit) (port) &= ~(1 << (bit))
    #define tbi(port,bit) port ^= _BV(bit);
    
    unsigned int rc5data;
    uint8_t kod,buffer[14];
        
    int main(void)
    {
    uart_init(UART_CONST);
    uart_puts("DZIENDOBRY\n");
    while(1) 
    {
     rc5data = rc5decode();
     if ( rc5data & 0x2000 ) {
    kod = (rc5data & 0x003f);   // output command bits of RC5 command
    uart_puts(itoa(kod,10,buffer));
      }
    }}
    


    rc5.h :

    
    #define RC5BitHigh()    (bit_is_set(PIND,PD2))
    #define RC5BitLow()     (bit_is_clear(PIND,PD2))
    #define WAITFORTIMER()  { while ( timerflag == 0); timerflag = 0; }
    
    #define TIMER_0_CNT 0xCA     //  111us with CLK/8 prescale
    #define RC5BITREF1  6  
    #define RC5BITREF2  11
    #define RC5BITREF3  14
    #define TMC8_STOP	0
    #define TMC8_CK8	_BV(CS01)
    
    unsigned int rc5decode( void );
    static volatile uint8_t timerflag;  //must be volatile because modified by interrupt handler
    
    
    SIGNAL(SIG_OVERFLOW0)
    /*
    **  signal handler for timer0 overflow interrupt
    */
    {
        timerflag = 1;               // set global variable 
    
        TCNT0 = TIMER_0_CNT;         // reset counter to get this interrupt again 
    }
    
    
    unsigned int rc5decode( void )
    /*
    **  decoded RC5 data is returned, or 0x0000 if RC5 data not recognized
    */
    {
        unsigned int    rc5data;
        unsigned char   timer, i;
        
    
        // init timer/Counter0    
        TCCR0 = TMC8_CK8;                // use CLK/8 prescale
        TCNT0 = TIMER_0_CNT;             // set timer T/16 = 111us 
        TIMSK = _BV(TOIE0);              // enable TCNT0 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
                    break;
                }
                
                // wait 3/4 T: await next bit
                for ( timer=0; timer < 12 ; timer++) WAITFORTIMER();
            }
    
        }else {
        rc5data = 0x0000;  // error, invalid RC-5 code
        }
        TCCR0 = TMC8_STOP;            // stop timer0    
        
        return (rc5data);
    
    }//rc5decode
  • REKLAMA
  • #3 9319807
    mirekk36
    Poziom 42  
    Trochę hmmm mało szczęśliwa ta obsługa RC5. Zwykle robi albo powiem inaczej warto robić na przerwaniach zamiast wszystko w pętli głównej bo działa to zdecydowanie wtedy lepiej.

    Już samą tą procedurę można byłoby mocno uprościć, żeby nawet nie korzystać w ogóle z procedury obsługi przerwania, bo po co? skoro tam jest ustawiana tylko flaga na 1. Pomijam to ładowanie wartości timera bo można to zrobić za pomocą trybu CTC (RAZ na początku programu w main), a zamiast deklarować flagę jako zmienną - wystarczy wtedy badać fizyczną flagę przerwania Compare_Match w odpowiednim rejestrze timer. Oczywiście warunek że trzeba by to było zrobić na timerze posiadającym tryb CTC.

    No ale to i tak tylko sztuka dla sztuki bo całość i tak spowalnia działanie pęti głównej na czas odbioru aż całej ramki :(

    W książce o której mowa tutaj: Link nie dość że masz rozpisane i wyjaśnione w najmniejszych szczegółach jak dekodować RC5 pięknie w przerwaniu tak żeby mogło w 100% działać w tle głównego programu i mu nie przeszkadzać, to jeszcze przy okazji wyjaśnione jest jak sobie lepiej organizować życie ;) poprzez dostosowywanie takich procedur do różnych częstotliwości taktowania. Zatem bez najmniejszego problemu używać dowolnej częstotliwości taktowania jaka tobie odpowiada, i nie musisz się martwić zależnościami czasowymi w pętli głównej tak jak w tym przypadku albo dostosowywać się na siłę do takiej częstotliwości w jakiej znalazłeś gotowe jakieś tam rozwiązanie w necie.

    Wprawdzie ten sposób o którym mówię bazuje na Timerze1 ale nie ma problemu aby przerobić sobie to na obsługę z timerem 8-bitowym i wykorzystaniem także jakiegoś przerwania typu INTx.
  • REKLAMA
  • #4 9319845
    bisz
    Poziom 18  
    Które z fuse bitów mogą za to odpowiadać ? Załączam obydwie konfiguracje :
    Fusebity atmega32:
    Dekodowanie IR RC5, Atmega32->Atmega8
    Fusebity atmega8
    Dekodowanie IR RC5, Atmega32->Atmega8
  • REKLAMA
  • #5 9498118
    bisz
    Poziom 18  
    Witam, jako że kontynuuję ten wątek, nie będę zakładał nowego. Znalazłem we wspominanej przez mirekk36 książce przykład rozwiązania dekodowania RC5.
    Problem jednak napotykam w kompilacji, dość dziwny bład.

    Zamieszcze źródła:

    main.c

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Bledy ktore napotykam przy kompilacji wygladaja tak


    
    marekd@dezintegrator:~/zacharek$ avr-gcc -mmcu=atmega32 main.c -o main.o
    In file included from main.c:4:
    /usr/lib/gcc/avr/4.3.4/../../../../avr/include/util/delay.h:89:3: warning: #warning "F_CPU not defined for <util/delay.h>"
    /usr/lib/gcc/avr/4.3.4/../../../../avr/include/util/delay.h:94:3: warning: #warning "Compiler optimizations disabled; functions from <util/delay.h> won't work as designed"
    /tmp/cc6gtD2a.o: In function `main':
    main.c:(.text+0xa): undefined reference to `ir_init'
    main.c:(.text+0x12): undefined reference to `Ir_key_press_flag'
    main.c:(.text+0x1a): undefined reference to `address'
    main.c:(.text+0x1e): undefined reference to `Ir_key_press_flag'
    main.c:(.text+0x24): undefined reference to `command'
    main.c:(.text+0x2a): undefined reference to `address'
    
  • #6 9498227
    mirekk36
    Poziom 42  
    Nie jest to dziwny błąd. Normalne błędy - bo podejrzewam, że kolega kompiluje to w jakimś Programmers Notepad gdzie dodatkowo trzeba samemu tworzyć makefile - a tu często rzadko kto wie jak zdefiniować F_CPU wewnątrz makefile - i później brak definicji tej zmiennej dla wielu plików w projekcie i bibliotecznych

    Proponuję jak najszybciej przejść na takie środowisko jak ECLIPSE. Przecież jest ono na dołączonej płycie DVD. Powiem więcej jest ono preinstalowane więc wystarczy wprost przegrać na swój dysk i OD RAZU DZIAŁA !!! ... Dzięki temu nie trzeba się męczyć z własnoręcznym tworzeniem makefile i od razu odpada milion różnych takich problemów.

    Cały projekt pięknie się skompiluje od razu w zarówno w ECLIPSE ale także spokojnie w AVR Studio 4.x jeśli się go dobrze zaimportuje. Jak tego dokonać ????? No przecież na płycie DVD są filmy/lekcje video i tam jest wszystko pięknie krok po kroku pokazane .... tym bardziej nie warto się męczyć..

    .... no chyba, że ......, że kolega działa pod linuxem, to wtedy sorki ale moje powyższe podpowiedzi niektóre są mniej aktualne - bo wszystko co na płycie jest pod Windows. Ale przecież linoxowcy nie mają problemu z instalacją Eclipse pod linuxem - więc po jego instalacji (ja nie znam się na linuxie) - dalej wszystko będzie pięknie działać
  • #7 9498230
    bisz
    Poziom 18  
    Możliwe że w eclipse wszystko ruszy, jednakoż wszystko do tej pory (a troche tego już było) kompilowałem we wspomniany sposób, i nie było takich problemów. Nie mniej, spróbuję w eclipse.
  • REKLAMA
  • #8 9498402
    mirekk36
    Poziom 42  
    ja nie mówię, że nie ruszy w twój sposób. Pewnie, że ruszy - tylko podpowiedziałem ci gdzie na pewno masz błąd. Nie masz zdefiniowanego F_CPU w makefile. Tam powinien być parametr

    -DF_CPU

    a jak sobie obejrzysz filmiki i zobaczysz jaka to wygoda pracować w Eclipse, sam spróbujesz - to później będziesz żałował, że wcześniej nie przeszedłeś na eclipsika.

    możesz przeczytać wiadomość, którą przesłałem ci na PRIV ?
  • #9 9500142
    bisz
    Poziom 18  
    Nic nie dostałem na priv.
    Sęk wtym że moja metoda obywała się bez pliku Makefile :))
  • #10 9500212
    mirekk36
    Poziom 42  
    bisz napisał:
    Nic nie dostałem na priv.
    Sęk wtym że moja metoda obywała się bez pliku Makefile :))


    To możesz do mnie napisać na maila albo podać tu swojego? Mój to: mirekk36(_at_)o2.pl

    Bo może ci jakiś filtr antyspamowy kasuje maile czy tam wiadomości z Elektrody. A wysłałem ci wiadomość przez PRIV elektrody. (to ważne więc daj jakoś znać ok?)

    a odnośnie makefile - to jest niemożliwe żeby była metoda bez tego pliku ;) co najwyżej może on być przez niektóre środowiska generowany automatycznie - jak w AVR Studio, Eclipse, CodeBlocks itp.... tyle że nadal mamy w parametrach programu możliwości ingerowania w makefile

    więc jeśli miałbym coś pomóc to opisz dokładnie jak i w czym to kompilujesz
  • #11 10323723
    bisz
    Poziom 18  
    mirekk36, udało mi się Twój projekt z książki sprowadzić do pseudo projektu bez makefile pod linuksem, wszystko się kompiluję i ładnie działa :)
REKLAMA