Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[AVR][C] - pilot IR Olympus

mirekk36 09 Oct 2008 12:26 3006 18
IGE-XAO
  • #1
    mirekk36
    Level 42  
    Witam,

    Coś ostatnio mało ludzi odpowiada mi na pytania w Bascomie, więc postarałem się napisać swój program w C. Liczę więc na pomoc specjalistów od GCC ;)

    chciałbym zrobić pilot IR do mojego aparatu fotograficznego Olympus. Ze stronki lirc sprawdziłem sobie co i jak ma być dla pilota RM-1. Powiem nawet że chyba rok temu zrobiłem to w assemblerze i działało, a teraz robię to (najpierw w Bascomie) w GCC i pomimo to, że na oscylu widać niby ładny przebieg to aparat ani drgnie.

    oto dane z lirca:

    Quote:
    name Olympus_RM-1
    bits 16
    flags SPACE_ENC|CONST_LENGTH
    eps 30
    aeps 100

    header 8853 4489
    one 559 1670
    zero 559 555
    ptrail 559
    repeat 8853 2259
    pre_data_bits 16
    pre_data 0x61DC
    gap 107013
    toggle_bit 0


    begin codes
    capture 0x000000000000807F
    w 0x00000000000040BF
    t 0x000000000000C03F
    - 0x00000000000020DF
    + 0x000000000000A05F
    end codes


    oto mój schemat pilocika na ATTiny2313:
    [AVR][C] - pilot IR Olympus

    a poniżej moje jedne z pierwszych poważniejszych (jak dla mnie wypocin w C):

    Code:
    #include <avr/io.h>
    
    #include <avr\interrupt.h>
    #include <inttypes.h>
    #include <util/delay.h>


    #include "makra.h"

    #define led_off PORTB |= (1<<0);
    #define led_on PORTB &= ~(1<<0);



    #define _header1  35413
    #define _header2  17956
    #define _state  2234
    #define _high  6679
    #define _low  2218
    #define _repeat = 9028



    void delayms(uint16_t del)
    {
       uint16_t i;
       for(i=0; i<del; i++) _delay_ms(1);

    }

    void timer1_start()
    {
       TCNT1 = 0;
       TCCR1B |= (1<<CS10); 
    }

    void timer1_stop()
    {
       TCCR1B &= ~(1<<CS10);
    }


    void nosna_on()
    {
       TCNT0 = 0;
       TCCR0A |= (1<<COM0A0); 
       TCCR0B |= (1<<CS00);
    }


    void nosna_off()
    {
       TCCR0A &= ~(1<<COM0A0); 
       TCCR0B &= ~(1<<CS00);
    }

    // tablica danych dla polecenia CAPTURE (0x807F)
    // łącznie z bitami poprzedzającymi pre_data (0x61DC)

    uint8_t pre_data[32] = {
       0 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 0 ,
       1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1
    };


    // tu zmienne zdeklarowałem jako volatile bo używane są w przerwaniu
    volatile uint8_t ir_count;
    volatile uint8_t nr;
    volatile uint8_t tab_cnt;





    int main(void)
    {

       // ustawienie PORTB.0 i PORTB.2 jako wyjścia
       DDRB |= (1<<0|1<<2);

       PORTB |= (1<<0|1<<2);

       // ustawienie PORTD.2 , 3 , 4 i 5 jako wejścia
       DDRD &= ~(1<<2|1<<3|1<<4|1<<5);
       // podciągnięcie wejść do 1
       PORTD |= (1<<2|1<<3|1<<4|1<<5);


       // ustawienia dla Timer0 (tryb CTC)
       OCR0A = 104; // prametr dla uzyskania częstotliwości nośnej 38kHz

       TCCR0A &= ~(1<<WGM00);
       TCCR0A |= (1<<WGM01);
       TCCR0B &= ~(1<<WGM02);


       // ustawienia dla Timer1 (tryb CTC)
       TCCR1A &= ~(1<<WGM10|1<<WGM11);
       TCCR1B |= (1<<WGM12);
       TCCR1B &= ~(1<<WGM13);

       // zezwolenie na przerwania od Compare1A
       TIMSK |= (1<<OCIE1A);


       // globalne zezwolenie na przerwania
       sei();


       while (1)
       {

          // KLAWISZ 1
          if ((PIND&0b00000100) == 0)
             {
                delayms(100);
                if ((PIND&0b00000100) == 0)
                {
                   ir_count = 66;
                   tab_cnt = 0;
                   nr = 0;
                   OCR1A = _header1;
                   TCNT1 = 0;
                   nosna_on();
                   timer1_start();
                }
             }

          // KLAWISZ 2
          if ((PIND&0b00001000) == 0)
             {
                delayms(100);
                if ((PIND&0b00001000) == 0)
                {
                   led_on;
                }
             }
       
          // KLAWISZ 3
          if ((PIND&0b00010000) == 0)
             {
                delayms(100);
                if ((PIND&0b00010000) == 0)
                {
                   led_off;
                }
             }
       }


       return 0;
    }


    SIGNAL(SIG_OUTPUT_COMPARE1A)
    {


    volatile uint8_t mbyte;


       if (ir_count == 0)
          {
             nosna_off();
             timer1_stop();
          }
          
       else if (ir_count == 66)   
          {
             nosna_off();
             OCR1A = _header2;
          }
       else if (ir_count > 1)
          {

             if (nr == 0)
                {
                   nosna_on();
                   OCR1A = _state;
                }
             else
                {
                   nosna_off();
                   mbyte = pre_data[tab_cnt];
                   tab_cnt++;
                   if (mbyte == 1)
                      {
                         OCR1A = _high;
                      }
                   else
                      {
                         OCR1A = _low;
                      }
                }

             nr++;
             if (nr > 1) {nr = 0;}

          }
       else if (ir_count == 1)
          {
             nosna_on();
             OCR1A = _state;   
          }

       ir_count--;


    }


    założenie mojego programu jest takie:

    1. Timer0 - generuje mi nośną 38kHz (działa b.ładnie)
    2. Timer1 - przerwanie od COMPARE1A ma kluczować nośną

    bitów do wysłania mamy łącznie 64, bo jest ich 16 pre_data oraz 16 polecenie.

    W związku z tym po wystartowaniu Timera1 po wciśnięciu klawisza1 , najpierw ładuję do OCR1A wartość przepełnienia dla otrzymania czasu _header1 (8853us) (wartości dla _header1, _header2, _state, _high, _low są ślicznie poobliczane)

    gdy nastąpi przepełnienie to mamy przerwanko i musi ono wystąpić 66 razy, ponieważ jest do wysłania: 1 impuls _header2, 64 impulsy dla bitów pre_data i danych, 1 impuls ptrail.

    jak widać w przerwaniu licznik impulsów ir_count jest zmniejszany i w zależności od jego wartości w przerwaniu następuje załadowanie odpowiedniej wartości do rejestru COMPARE1A aby regulować odpowiednie czasy.

    i tak po wejściu w przerwanie (wyemitowanie nośnej w czasie _header1) najpierw przy wartosci ir_count = 66 nastąpi wyłączenie nośnej i odczekanie czasu _header2

    potem w kolejnych krokach lecą nam bity 0 lub 1. Każdy bit najpierw włącza nośną na czas umownie nazwany _state (559us) a następnie w kolejnym przerwaniu wyłącza nośną na czas _high gdy bit = 1 lub na czas _low gdy bit = 0

    poniżej obrazek z oscyla - widać wręcz ślicznie bity z tablicy pre_data, _header2 itp:
    [AVR][C] - pilot IR Olympus

    a tu już sobie dokładnie liczyłem bo mi się w oczach mieszało:
    [AVR][C] - pilot IR Olympus


    .... no i na koniec, czy chciało by się komuś jakoś to przeanalizować co narobiłem i może jakiś pomysł podsunąć gdzie coś mogę robić źle? albo może jak zoptymalizować kod - bo chyba tak troszkę na zywca ze składni Bascoma to przeniosłem i podejrzewam, że można to poskracać jakoś.

    Może przerwanie za długo się wykonuje, ale z drugiej strony Timer1 cały czas tyka i podejrzewam, że najdłuższa operacja w przerwaniu robi się krócej niż czas potrzebny do kolejnego przeładowania po zaktualizowaniu OCR1A ...

    Dodano po 16 [minuty]:

    aha - dodam, że sprawdzałem też przebieg na wyjściu odbiornika podczerwieni TSOP żeby sprawdzić czy dobrze filtruje nośną - i na oscylu jest także ładny przebieg tyle że odwrócony (tak jak powinno być)

    hmmm jaki więc błąd mogę popełniać - widzi może ktoś? coś?
  • IGE-XAO
  • Helpful post
    #2
    Freddie Chopin
    MCUs specialist
    no to ja z sugestiami od poczatku kodu lece:

    0. #define led_off PORTB |= (1<<0);

    dobry zwyczaj to uzywanie wielkich literek przy define. do tego na koncu calych linijek ktore definiujesz NIGDY nie nalezy stawiac srednika. do tego zwyklo sie nazywac makro_funkcje z uzyciem nawiasow jednak czyli np LED_OFF()

    no i chyba to:

    #define _repeat = 9028

    ten znak '=' raczej niewskazany jest.

    1. w funkcji od opoznien. nie lepiej zamiast:

    Code:

       uint16_t i;
       for(i=0; i<del; i++) _delay_ms(1);


    zrobic:

    Code:

       while(del--) _delay_ms(1);


    2. tablica z wartosciami to troszke przesada [; skoro to sa bity, to uzyj do zapisu ... bitow... potem sobie w wiekszej liczby wydlubiesz to co ci trzeba za pomoca: dluga_liczba&(1<<numer_bitu), wstawiajac to do odpowiedniego IF'a zeby dostac 1 lub 0. ewentualnie wstawka asm z wyrotowywaniem. ewentualnie ciagle przesuwanie jakiejs zmiennej - wtedy np najmlodszy bit jest twoim nastepnym. ewentuanie... no ze sto sposobow [;

    3. nigdy nie pamietam jaki jest priorytet operatorow, dlatego - aby sie nad tym nie zastanawiac - wyreczam w tym kompilator, unikajac czasem dziwnych bledow:

    DDRB |= (1<<0|1<<2);
    TCCR1A &= ~(1<<WGM10|1<<WGM11);

    ja bym zrobil raczej

    DDRB |= (1<<0)|(1<<2);
    TCCR1A &= ~((1<<WGM10)|(1<<WGM11));

    zawsze to troche bezpieczniej i nawyk zostaje.

    4. ustawianie wartosci poczatkowych dla portow, ktore robisz w MAIN. po co te ORy i NANDy, skoro to pierwsza modyfikacja - mozna zrobic przypisanie normalne, po co marnowac cykle i pamiec.

    5. if ((PIND&0b00000100) == 0) troche to brzydkie [; nie lepiej zadeklarowac:

    #define KLAWISZ_1 (1<<2)

    dzieki czemu masz:

    if (!(PIND&KLAWISZ_1))

    ?

    6. obsluga przyciskow jest daleka od optymalnej. prosciej zrobic jedna funkcje, ktora odczytuje stan portu, oczekuje ilestam czasu, sprawdza czy stan jest taki sam i go zwraca:
    Code:

    u8_t debounce(void)
    {
    u8_t port;

    port=PORTx;
    delay();
    if(PORTx==x) return x;
    else return 0;
    }


    oczywiscie jesli u ciebie przycisk nacisniety to 0, to na koncu w else musisz zwrocic 0xFF

    potem w funkcji main robisz np:

    Code:

    u8_t butt;

    while(1)
    {
    butt=debounce();
    if(!(butt&KLAWISZ_1))
    costam();
    else if ()
    ...
    else
    ...
    }


    7. return 0; na koncu maina jest zbedny.

    to tyle na poczatek [; ja sie na AVRach nie znam [;

    4\/3!!
  • #3
    mirekk36
    Level 42  
    Freddie Chopin -> bardzo dziękuję za wskazówki ogólne, bardzo się przydadzą. Właśnie m.inn wkurzało mnie to, że nie mogłem dojść za bardzo jak radzić sobie z odczytem pinu na danym porcie i robiłem to wg jakiegoś kodu z netu, a ty podałeś w miarę fajny sposób. To tak na marginesie oczywiście bo - jednak to nadal nie rozwiązuje mojego głównego problemu.

    jednak bardzo przydatne są dla mnie (nadal mocno początkującego w C) np takie uwagi jak twój pomysł na skrócenie tej mojej funkcji delayms, (wyrzucenie pętli for i zastąpienie ją while - takie mechanizmy właśnie bardzo mi się podobają w C)
  • IGE-XAO
  • #4
    Freddie Chopin
    MCUs specialist
    mirekk36 wrote:
    jednak bardzo przydatne są dla mnie (nadal mocno początkującego w C) np takie uwagi jak twój pomysł na skrócenie tej mojej funkcji delayms, (wyrzucenie pętli for i zastąpienie ją while - takie mechanizmy właśnie bardzo mi się podobają w C)

    jesli wlaczyles jakakolwik optymalizacje, to wygenerowany kod tak czy siak bedzie taki sam [;

    a co do glownego problemu - jesli masz oscyloskop, to czy sprawdziles, czy czestotliwosc nosnej jest wlasciwa i czy uzyskane czasy sa takie jak nalezy? przy uzyciu oscyloskopu (chyba cyfrowego jak widze) sprawa jest przeciez bardzo prosta.

    a tak BTW to do tego odczytu portu trzeba by dodac jeszcze jakies maskowanie, tak aby odczytal tylko to gdzie sa przyciski:

    Code:

    u8_t debounce(void)
    {
    u8_t port;

    port=PORTx&(KLAWISZ_1|KLAWISZ_2|KLAWISZ_3|KLAWISZ_4);
    delay();
    if((PORTx&(KLAWISZ_1|KLAWISZ_2|KLAWISZ_3|KLAWISZ_4))==x) return x;
    else return 0;
    }


    4\/3!!
  • #5
    mirekk36
    Level 42  
    Freddie Chopin -> dzięki ponownie za uwagi,

    niestety oscyloskop jest zwykły nalogowy :( a te kreseczki i cyferki to już tak dorysowałem w kompie... więc nie jestem w stanie sprawdzić tych czasów impulsów - natomoast co do nośnej to jestem pewien na 10000% że jest dobra. Zresztą próbowałem z różnymi nośnymi od 34kHz do 40kHz ale to nie ma znaczenia.

    gorsze może być to, że w tym przerwaniu to załadowanie OCR1A może być coś nie tak.

    tak teoretycznie - nie wiem czy dobrze to rozumiem ale wydaje mi się, że gdy takie przerwanie zostaje wygenerowane to licznik Timer1 = 0 i zaczyna znowu zliczać w górę aż osiągnie wartość z OCR1A. A ponieważ te czasy impulsów są dosyć długie (najkrótszy przecież trwa 555us to przecież kod przerwania musi w tym przypadku się o wiele szybciej wykonać. Kwarc 8MHz (tzn wewn generator) więc czas 1 cyklu to tylko 125ns.

    ( z tymi klawiszami na pewno pobawię się ale później - bo na razie muszę dojść co się z tym dzieje)
  • #7
    mirekk36
    Level 42  
    kurka wodna - no więc zacząłem liczyć prawie ze szkłem powiększającym przy lampie oscyla i wychodzi na to, że ta nośna jest w miarę ok - ale nie dam rady tego dokładnie stwierdzić przy takim oscylu.

    poniżej wzór z jakiego korzystałem przy obliczaniu częstotliwości mojej nośnej na wyjściu OC0A
    [AVR][C] - pilot IR Olympus

    czyli w moim przypadku:

    36036 = 8000000 / 2 * 1 * (1 + 110)

    8000000 - to mój (teraz już kwarc)
    preskaler = 1
    OCR0A = 110

    niestety jak na oscylu dam 10us na działkę to pokazuje mi tak jakby okres miał ok 23us zamiast 28us - więc aż tak dokładny to on nie jest
  • #8
    kuba989898
    Level 19  
    Ja jak pisałem w asemblerze kod do pilota RM-1 to przy kwarcu 4 MHz
    dałem wartość dla OCR0A = 0x3c i działa z dwoma Olympusami.
    U mnie rejestr TCCR0A = 0x42. To tak co do nośnej.
    Na C nie znam się tyle żeby pomóc, ale wiem że tu trzeba dokładnie opóźnienia dobrać.

    Załączam swój program w assemblerze (ATTINY2313, kwarc 4MHz, dioda anodą do nóżki OC0A).
  • #9
    mirekk36
    Level 42  
    kuba989898 -> no rację masz na pewno co do tego, że trzeba bardzo dokładnie opóźnienia dobrać. Tym bardziej, że zaparłem się na tego pilota jak diabli (nawet pomimo to że na allegro znalazłem go za 24zł - ale już bardziej teraz mi o to chodzi, żeby zrobić to w C niż żeby mieć tanio pilota)

    tak więc odkopałem swój projekcik tegoż pilocika też w asemblerze - odpaliłem go na tiny2313 i kurna - działa! Wprawdzie zasada działania programu całkowicie inna ale ten w asm napisany przeze mnie samego ponad rok temu chula.

    no i okazał się pierwszy ZONK po porównaniu na oscylu przebiegu tego z programu napisanego w C i w ASM. Otóż ten program w C powoduje, że przebieg jest krótszy i jakby wszystko się dzieje ze 2 razy szybciej. Pomimo to , że jeden i drugi program wykorzytuje kwarc 8MHz

    wynika mi z tego, że jakąś kaszanę odstawiam z tym przeładowywaniem OCR1A w przerwaniu.

    Proszę niech mi ktoś powie czy dobrze myślę:

    Gdy ustawiam Timer1 w tryb CTC = 4 (WGM13=0, WGM12=1, WGM11=0, WGM10=0) to zapis do OCR1A nie jest buforowany, czyli powinien zmieniać się natychmiast po wpisaniu do niego wartości. Timer1 wciąż zwiększa swoją wartość o 1 i gdy osiągnie ona wartość taką jak w OCR1A to wystąpi przerwanie a Timer1 zostanie zresetowany do 0 i znowu będzie zwiększał swoją wartośćo 1. Więc w czasie tego przerwania można znowu zmienić OCR1A aby tym sposobem zmienić długość generowanego kolejnego impulsu.

    czy dobrze myślę????????
  • Helpful post
    #10
    kuba989898
    Level 19  
    mirekk36 wrote:

    Proszę niech mi ktoś powie czy dobrze myślę:

    Gdy ustawiam Timer1 w tryb CTC = 4 (WGM13=0, WGM12=1, WGM11=0, WGM10=0) to zapis do OCR1A nie jest buforowany, czyli powinien zmieniać się natychmiast po wpisaniu do niego wartości. Timer1 wciąż zwiększa swoją wartość o 1 i gdy osiągnie ona wartość taką jak w OCR1A to wystąpi przerwanie a Timer1 zostanie zresetowany do 0 i znowu będzie zwiększał swoją wartośćo 1. Więc w czasie tego przerwania można znowu zmienić OCR1A aby tym sposobem zmienić długość generowanego kolejnego impulsu.

    czy dobrze myślę????????


    No z tego co Atmel napisał w nocie katalogowej ATTNIY2313 to jest tak jak myślisz. (dół strony 98 noty katalogowej ATTINY2313)
  • #11
    mirekk36
    Level 42  
    kuba989898 -> no dzięki za potwierdzenie - bo już poplątania dostaję przez to wszystko, ale dostrzegłem chyba błąd u siebie , bo pisałem wcześniej że te czasy są dokładnie wyliczone i to jest chyba ZONK bo wyliczałem ze wzoru czas dla okresu częstotliwości więc powinienem podwoić te wartości ... i teraz się męczę z podowjeniem wartości _header1 = 35413 - bo po podwojeniu przy preskalerze 1 nie mogę uzyskać takiego czasu więc muszę albo zakombinować z dynamicznym przestawianiem preskalera albo zmniejszyć kwarc do 4MHz odpowiednio zmieniając tylko czas dla nośnej.

    a tu kolejna głupota mi wychodzi bo - przestawiłem w AVR Studio wartość kwarca na 4MHz i zbuildowałem wszystko, przestawiłem procka na 4MHz (wewn oscylator) - tylko że program jakby nie działa - żadnej reakcji. Oczywiście procek żyje bo jak przywrócę mu 8MHz to wszystko działa jak poprzednio.
  • #12
    kuba989898
    Level 19  
    Zastosuj zewnętrzny kwarc 4MHz lub 8MHz bo wewnętrzny oscylator pozostawia wiele do życzenia.
    (W Bascomie i procesorze z wewnętrznym oscylatorem komunikacja na magistrali 1-wire nie była możliwa)
    Doradzam więc stanowczo zastosowanie rezonatora kwarcowego i 2óch kondensatorów 33pF, bo możliwe że cały twój program rozjeżdża się z powodu użycia wewnętrznego oscylatora.
    Aha jak próbowałem kompilować twój program w C to w błędach kompilator wyrzucił ostrzeżenie o braku ustawienia zmiennej F_CPU dla <utlil/delay.h>

    W pierwszej linijce dopisałbym
    Code:

    #define F_CPU  4000000
    #define __OPTIMIZE__
  • #13
    mirekk36
    Level 42  
    kuba989898 -> hmm widzisz ja stosuję AVR Studio jako kompilator i tam makefile , wraz z tymi parametrami o których piszesz, jest automatycznie generowny. Tak więc próba ich dodania w kodzie powoduje czkawkę i warningi o tym, że coś jest dwukrotnie zdefiniowane itp.

    doszedłem już zgodnie z tym co mówiłem poprzednio, że jednak źle dobrałem czasy przez to że pomyliłem okres częstotliwości.

    teraz zrobiłem już tak że użyłem prekslaere 8 co w połączeniu z kwarcem 8MHz dało mi fajną podstawę czasu w Timer1 bo = 1us. W związku z tym jeśli Timer miał odmierzyć 8859us to poprostu OCR1A ustawiałem na 8859 ;) .... ale i tak kicha .... widać ten mój cały pomysł- idea aby tak wykorzystać przerwanie COMPARE1A jest do bani ;( .... bo wprawdzie czasy już się poprawiły do prawie idealnych - ale jednak nadal "prawie" - a jak to mówią "prawie" robi wielką różnicę. I tak w porównaniu do oscylogramu poprawnego programu asemblerowego ten wykonywany w C - ma ociupinkę (widać to gołym okiem na oscylu) jakby dłuższe czasy niż wynika z wyliczeń.

    czyli np gdzy przy tym presklalerze 8 dam czas 559us to na oscylu jest minimalnie więcej - ale ile? tego z analogowego oscyla się nie odczyta i nie wiem dlaczego tak jest.

    praktycznie chyba tylko czas oznaczony jako _header1, gdzie OCR1A jest ładowane przez startem Timera1 - wydaje się być taki sam. A te czasy , gdzie OCR1A ładowane jest w przerwaniu - są już jakby troszkę wysłużone. Może wynika to z tego, że następuje przerwanie i jeszcze możeileś tam cykli zegara traconych jest na IF'y , włączenie bądź wyłączenie nośnej, obliczenie kiedy co ma nastąpić itp. Tak więc - trzeba by było próbować metodą prób i błędów regulować te czasy - ale to już się robi bez sensu - taka idea wykorzystania tegoż przerwania
  • Helpful post
    #14
    kuba989898
    Level 19  
    No to ja niestety więcej tu nie pomogę bo nie znam języka C i nie przepadam za nim.
  • #15
    mirekk36
    Level 42  
    a ja jednak uczę się go - bo naprawdę - tworzenie większych projektów jest o wiele łatwiejsze przy użyciu języków wyższego poziomu niż tylko asembler. Z drugiej strony im bardziej poznaję C na procki tym bardziej dochodzę do wniosku, że bez znajomości asemblera ciężko byłoby cokolwiek nauczyć się w C. Za to całkiem inaczej jest w Bascomie - on też się nadaje na szybko do wielu małych rzeczy. Choć jak się Bascoma okrasi asemblerowymi wstawkami jak skwarkami to i większe projekciki można zrealizować ;)

    .... jednak C już od dawna mnie męczy - więc i ja go muszę zmęczyć ;)

    i tak dzięki za okazaną pomoc
  • Helpful post
    #16
    Freddie Chopin
    MCUs specialist
    no to ja mam znow pomysl na garsc poprawek [; w przerwaniu:

    1. if (nr > 1) {nr = 0;}

    jak widze nr oznacza u ciebie jakby 'faze' danego bitu. zamiast wiec kombinowac z ta cala inkrementacja i sprawdzaniem, zrob po prostu XOR'a:

    nr^=1;

    tym sposobem bedzie ta zmienna rowna na zmiane 1 i 0.

    niemniej jednak zauwaz, ze twoja zmienna nr to jest ... ostatni bit zmiennej ir_count (ewentualnie odwrocony, to juz sam wiesz lepiej, mnie sie nie chce myslec [; ), wiec w ogole zamiast tej zmiennej mozesz w warunku wstawic

    if(ir_count&1)

    2. jesli przesuniesz caly blok odpowiedzialny za:

    else if (ir_count == 1)

    powyzej tego dla ir_count>1, to w ogole mozesz zrezygnowac z warunku ir_count>1, bo jesli wszystkie pozostale warunki nie zostana spelnione, to znaczy ze en ostatni na pewno zostanie spelniony - jedno porownanie mniej.

    3. volatile uint8_t mbyte;

    zmienna ta nie musi byc volatile. volatile nalezy uzywac jedynie wtedy, gdy wiecej niz jeden proces wspoldzieli jedna zmienna w sposob NIEKONTROLOWANY. jesli masz zmienna globalna uzywana jedynie w kodzie podstawowym w 10 podfunkcjach, to nie musi byc ona volatile, bo nie ma mozliwosci, zeby nagle jedna funkcja wskoczyla w druga w sposob niekontrolowany. tutaj tez nic nie zmieni ci tej zmiennej, wiec volatile jest zbedne i uniemozliwia optymalizacje.

    4. // tu zmienne zdeklarowałem jako volatile bo używane są w przerwaniu
    volatile uint8_t ir_count;
    volatile uint8_t nr;
    volatile uint8_t tab_cnt;

    tak samo zbedne jest deklarowanie ich jako volatile. owszem - uzywane sa tez w przerwaniu, ale ich wartosc w main cie nie interesuje - zmienne te nie sa flagami, ktore sa tam caly czas sprawdzane czy cos... dopiero gdyby tak bylo, to mialoby to sens.

    5. tab_count - zauwaz ze zmienna ta jest 100% zwiazana z ir_count - jest ona rowna pewnie (65-ir_count)/2 (or sth like that)

    4\/3!!
  • #17
    mirekk36
    Level 42  
    Freddie Chopin -> hmmm takie pomysły na poprawki usprawnienia to miód dla mego serca ;) ...wielkie dzięki, już od poprzedniej wypowiedzi poprawiłem wszystkie #define wg tego co pisałeś. A teraz jeszcze kolejne takie fajne i praktyczne uwagi - wielkie dzięki.

    A tak na marginesie - wymyśliłem sobie coś takiego w moim dołączanym pliku makra.h

    Code:
    #define SET    |=
    
    #define RESET    &= ~
    #define TOGGLE    ^=


    dzięki czemu gdy np zdefiniuję sobie klawisze tak jak pisałeś:

    Code:
    #define K1 2
    
    #define KEY1 (1<<K1)


    to potem robię tak:

    Code:
       // ustawienie PORTD.2 , 3 , 4 i 5 jako wejścia
    
       DDRD    RESET    (KEY1|KEY2|KEY3|KEY4);
       // podciągnięcie wejść do 1
       PORTD    SET    (KEY1|KEY2|KEY3|KEY4);


    co mi się bardzo podoba gdyż nie muszę (narazie mało przyzwyczajony) wypisywać tych ptaszków - jak dla mnie , a i jest to też na razie dla mnie bardziej przejrzyste

    to chyba nie będzie wielkim odstępstwem od standardu dobrego pisania w C hmmm?
  • Helpful post
    #18
    Freddie Chopin
    MCUs specialist
    to jak piszesz swoje programy jest zalezne tylko od ciebie [; ja osobiscie az tak daleko bym sie nie posuwal - idzie sie przyzwyczaic do owych ptaszkow (a jak wiadomo jest ich wiecej: /=, <<=, >>=, %=, *=, +=, -=, itd...)

    zasadniczo gdy szuka sie pomocy na forum, to stosujac takie makra jak u ciebie, musisz tez wrzucac owy plik naglowkowy, zeby inni byli w stanie skumac co tam stworzyles [;

    ale jak juz powiedzialem - twoja wola [;

    wracajac zas do glownej sprawy - mowisz ze kod w ASM w ukladzie dziala, a ten w C juz nie... zapewne ten w ASM nie wykorzystuje procesora w ten sam sposob? bo jesli tak i jesli znasz asm AVRa (a znasz [; ) to zawsze mozna porownac co tam kompilator naprodukowal.

    dalej idac mozesz popelnic takie swietokradztwo jak przerobienie kodu ASM wprost na C i - jesli zadziala - usprawnianie go. zawsze to jakis punkt wyjscia, bo jak przestaje dzialac po zmianie jednej rzeczy, to wiadomo gdzie jest blad, a tutaj w sumie nie wiadomo czy bledem sa czasy, czy moze nosna, czy moze kod za wolny...

    4\/3!!
  • #19
    mirekk36
    Level 42  
    tak tak, znam ten kod asm i mam jego źródła bo sam pisałem ;) .... oczywiście, że tam właśnie działa to na innej zasadzie. I już postanowiłem tym tropem pójść, chociaż troszkę teraz to w C usprawnię mam nadzieję. W ASM zrobiłem tak, że Timer1 w zwykłym trybie i jego przerwanie służyło mi do generowania nośnej, a kluczowana ona była za pomocą opóźnień ale nie programowych - tylko generowanych za pomocą z kolei Timera0 (tylko bez przerwań - a poprzez badanie flagi TOV0).

    Teraz też tak zrobię - tylko postaram się troszkę uniwersalnie to napisać, (nie wiem czy się to uda do końca) ale tak aby można było sobie tylko wstawić dane ze stronki Lirc.org dla danego pilota - a program będzie generował dowolne kody w danym standardzie ;) ... No może aż tak uniwersalnie żeby wszystkie można było obsługiwać to się nie da - ale - dążę do tego aby móc generować w podstawowych standardach SPACE, PULSE i BIPHASE dla kilku różnych pilotów - zobaczymy

    teraz lecę już spać, ale jutro porozgryzam jeszcze co oznaczają te kolejne ptaszki, które mi tu "narysowałeś" - napewno się okażą bardzo przydatne także - a jak znam życie to za jakiś czas też na pewno się do nich przyzwyczaję

    pozdrówka