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

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

esnow 26 Lis 2009 21:46 3580 7
  • #1 7313116
    esnow
    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:
    
    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); ?
  • #2 7313509
    tmf
    VIP Zasłużony dla elektroda
    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.
  • #3 7313636
    esnow
    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) ?
  • #4 7314065
    fazolek
    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:
    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%.
  • #5 7314179
    mirekk36
    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.
  • #6 7314487
    OldSkull
    Poziom 28  
    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).
  • #7 7314759
    tmf
    VIP Zasłużony dla elektroda
    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.
  • #8 7318255
    esnow
    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.

    
    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;
    	}
    }
    


    
    #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;
    }
    

    
    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);
        }
    }
    
REKLAMA