Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[C][atmega8] generowanie fali nośnej 36kHz i wysyłanie RC5

26 Lis 2009 21:46 3355 7
  • Poziom 14  
    witam,
    zamierzam, przy użyciu timera 1 wygenerować falę nośna 36kHz a następniej wysyłać kody RC5.

    zakładając, że:
    FCPU = 8MHz
    preskaler = 8
    ze wzoru [C][atmega8] generowanie fali nośnej 36kHz i wysyłanie RC5 obliczyłem, że wartość OCRnA ~ 13.

    następnie ustawiam Timer:
    Code:

    TCCR1A = 1<<COM1A0; // toggle OC1A on Compare Match
    TCCR1A = 1<<WGM12; // CTC mode
    TCCR1B = 1<<CS11; // prescaler clk/8 przykladowo

    OCR1A = 13;


    do nóżki PB1(OC1A) podpiętą mam bazę tranzystora PNP, a dalej diodę nadwaczą IR.
    problem polega na tym, że nie wiem jak teraz wysłać ten kod. czy poprzez zmienianie stanu w taki sposób PORTB ^= _BV(1); ?
  • Moderator Mikrokontrolery Projektowanie
    Nie, funkcja portu jest przechwytywana przez timer, wiec musisz go na chwile wylaczyc, lub odlaczyc od pinu - wpisac 0 do COM1A1 i COM1A0. Albo uzyc nadajnika dzieki czemu nie bedziesz musial generowac nosnej, albo AVR z nowszej generacji, ktory moze generowac sygnal modulowany nosna.
  • Poziom 14  
    nie wiem czy dobrze rozumiem,
    czyli przy takiej konfiguracji jak podałem w pierwszym poście uC bedzie cały czas generowal sygnał 36kHz na nóżke PB1(OC1A). i podczas wysyłania RC5 jeśli będę musiał wysłać stan niski, to na tą chwilę potrzebuje wyłączyć timer, tak?

    po drugie, jak teraz myślę to będzie potrzebny jeszcze jeden timer, żeby odmierzyć te 889us (http://www.sbprojects.com/knowledge/ir/rc5.htm) ?
  • Poziom 12  
    Stworzyłeś falę nośną ale to ci wiele nie da. Zrób dokładnie tak jest napisane z tym czasem 889us taki zrób okres licznika ale nie steruj nim wyprowadzenia. Wykorzystaj to odmierzanie czasu w funkcji aby kolejno wystawiać stany takie jakie potrzebujesz. Moja koncepcja to w funkcji wysyłania ramki pętla for na początek bez przerwań dla pokazania idei:
    Code:
    for (i=0,i<14,i++)
    
    {
    maska na najmłodszy bit danej
    oczekiwanie na flage przerwania od licznika + jej skasowanie
    i ustawienie pinu w zależności od wyniku maskowania
    oczekiwanie na flage przerwania od licznika + jej skasowanie
    i ustawienie pinu w stan przeciwny niż wcześniej
    przesunięcie cykliczne maski o jeden bit w lewo
    }

    Częstotliwość nie musi być taka strasznie dokładna bo odbiornik powinien się synchronizować na zboczach a w pilotach śmiało można przyjąć błąd tej częstotliwości na poziomie 10%.
  • Poziom 42  
    esnow napisał:
    nie wiem czy dobrze rozumiem,
    czyli przy takiej konfiguracji jak podałem w pierwszym poście uC bedzie cały czas generowal sygnał 36kHz na nóżke PB1(OC1A). i podczas wysyłania RC5 jeśli będę musiał wysłać stan niski, to na tą chwilę potrzebuje wyłączyć timer, tak?

    po drugie, jak teraz myślę to będzie potrzebny jeszcze jeden timer, żeby odmierzyć te 889us (http://www.sbprojects.com/knowledge/ir/rc5.htm) ?


    Ja np zawsze tak robiłem pilota, tzn generowałem sprzętowo nośną tak jak ty tutaj a inny timer wykorzystywałem do odmierzania czasów impulsów. Zatrzymanie generatora nośnej robisz najspokojniej w świecie za pomocą wyzerowania preskalera tego tumera a wystartowanie poprzez jego ponowne ustawienie. Można sobie zresztą zdefiniować np coś takiego:

    #define NOSNA_START TCCR0x |= (1<<CS01)
    #define NOSNA_STOPC TCCR0x &= ~(1<<CS01)

    tylko podstawiasz tu sobie swój odpowiedni rejestr i odpowiedni bit lub bity preskalera.
  • Poziom 27  
    Jednym z prostszych rozwiązań jest zmienianie kierunku portu (DDR), drugim jest zmienianie wybranego rejestru Timera 1.
    Zresztą 36kHz idzie dość dokładnie uzyskac na Timerze0 (8 bitowym) w trybie CTC. Wychodzi przy 8MHz (preskaler 1, CTC, toggle) mniej więcej 36kHz przy OCRx = 110 (36036Hz).
  • Moderator Mikrokontrolery Projektowanie
    Jesli juz nie chce wykorzystac scalonego modulu nadajnika, to po prostu podlaczenie wyjscia z Timera + pinu np. TxD przez bramke AND zalatwi sprawe modulacji elegancko. Bramka AND w SOT23 miejsca nie zajmie. Ew. mozna TxD dac na baze, a przebieg z timera na emiter tranzystora PNP - w koncu i tak go ma. Nie trzeba wtedy zadnych kombinacji programowych, a i mozna wykorzystac sprzetowy UART co upraszcza program i odciaza procesor.
  • Poziom 14  
    napisałem tak i nie działa ;/
    gdzie może być błąd?
    (tranzystor PNP do OC1A - PB1 atmega8). sprawdziłem przed chwilą w bascomie, i telewizor reaguje na komendy rc5send z BASCOMA.

    Code:

    unsigned int RRR=0;

    void rc5send(void)
    {
        TCCR0 |= (1<<CS00);
        TCCR0 |= (1<<CS01);                // use CLK/64 prescale
        TCNT0 = 0x6F;                   //888 cykli dla preskalera 64 i 8MHz
        TIMSK = _BV(TOIE0);              // enable TCNT0 overflow interrupt
       timer_flag=0;
       
       RRR=0b11100000100000;  //P+ 32
       
       for (int i=0; i<14; i++)
       {
          /*maska na najmłodszy bit danej
          oczekiwanie na flage przerwania od licznika + jej skasowanie
          i ustawienie pinu w zależności od wyniku maskowania
          oczekiwanie na flage przerwania od licznika + jej skasowanie
          i ustawienie pinu w stan przeciwny niż wcześniej
          przesunięcie cykliczne maski o jeden bit w lewo*/
          

          { while ( timer_flag == 0); timer_flag = 0; }
          if(RRR & 1)
             PORTB |= _BV(1);
          else
             PORTB &= ~_BV(1);
             
          { while ( timer_flag == 0); timer_flag = 0; }
             PORTB ^= _BV(1);   

          RRR<<=1;
       }
    }


    Code:

    #define TIMER_0_SEND 0x6F   //dla clk/64  i 8MHz

    SIGNAL(SIG_OVERFLOW0)  //  przerwanie od przepelnienia timer0
    {
        timer_flag = 1;               // ustawienie 1 jako flagi globalnej

       TCNT0 = TIMER_0_SEND;
    }

    Code:

    int main(void)
    {
        DDRB  = 0xff;               // use all pins on port B for output
        PORTB = 0xff;
       
       DDRC = 0xff;
       PORTC = 0x00;
       
    TCCR1A |= 1<<COM1A0; // toggle OC1A on Compare Match
    TCCR1A |= 1<<WGM12; // CTC mode
    TCCR1B = 1<<CS11; // prescaler clk/8 przykladowo

    OCR1A = 13;
       
       USART_Init(UART_CONST);          // inicjalizacja rs'a
       
        sei();                      //globalne zezwolenie na przerwania
       
        while(1) 
        {
          rc5send();
          PORTB |= _BV(1);
          PORTC ^= _BV(5);
          _delay_ms(2000);
        }
    }