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

[C]ATmega 8 i TSOP1736 nadajnik/odbiornik

gjanek 22 Cze 2009 20:04 6555 40
  • #1 6689789
    gjanek
    Poziom 12  
    Witam wszystkich.
    Prosiłbym o pomoc. .Postanowiłem sobie zrobić nadajnik i odbiornik na podczerwień. Temat nadawani i odbierania był już na forum, jednakże z tych informacji, które znalazłem i tak nie che mi wyjść. Napisałem program na podstawie jakiś innych programów znalezionych na sieci.
    Mam problem z odbiorem z pilota.
    Kod pilota:

    fusbity ustawione na 2Mhz
    
    # define F_CPU  1690000L
    #include <avr/io.h>
    #include <util/delay.h>
    
    int main(void){ //pocztek funkcji main
    DDRD=0x00;	//PD0 wejściowy
    PORTD=0xFF;	//z podciąganiem
    
    DDRB=00000000;	//Pb6 wejściowy
    PORTB=0xfF;	//z podciąganiem
    int stan=0;
    int stan1=0;
    int i, ii;
    int tab[14]= {1,1,1,0,1,1,0,1,1,0,1,0,0,1}; //pierwszy przycisk
    int tab1[14]={1,1,1,0,0,1,0,1,1,0,1,0,0,1}; //drugi przycisk
    
    //generacja fali nonej 36kHz
        while(1)
    	{
    PORTD&= ~_BV(PD6);
    //****************************************Pierwszy przycisk*****************************************************************
    
    			  if((bit_is_clear(PIND,PD0)) && (stan==0))   //jeżeli poprzednio nie był wciśnięty
    				{
    				_delay_us(30);                            //czekaj aż się uspokoją drgania styków
    						if(bit_is_clear(PIND,PD0))               //jeżeli ciągle wciśnięty
    						{
    								
    								
    							for(ii=0;ii<14;ii++)
    							{
    								if(tab[ii]==1)
    								{
    									for (i=0;i<100;i++)
    									{										
    										PORTD|=_BV(PD6);
    										_delay_us(13);
    										PORTD&= ~_BV(PD6);
    										
    										_delay_us(13);
    									}
    								
    								}else
    								_delay_us(2600);
    								
    							_delay_us(2600);
    					        }
    									stan=1;         //oflaguj jako wciśnięty
    						}		 		
    				}
    			
    				
    				
    				
    				 if (bit_is_set(PIND,PD0))
    				 stan=0;    //jeżeli przycisk jest zwolniony zeruj flagę wciśnięcia
    				
    //************************************Drugi przycisk*********************************************************************
    
     if((bit_is_clear(PIND,PD3)) && (stan1==0))   //jeżeli poprzednio nie był wciśnięty
    				{
    				_delay_us(30);                            //czekaj aż się uspokoją drgania styków
    						if(bit_is_clear(PIND,PD3))               //jeżeli ciągle wciśnięty
    						{
    								
    								
    							for(ii=0;ii<14;ii++)
    							{
    								if(tab1[ii]==1)
    								{
    									for (i=0;i<100;i++)
    									{										
    										PORTD|=_BV(PD6);
    										_delay_us(13);
    										PORTD&= ~_BV(PD6);
    										
    										_delay_us(13);
    									}
    								
    								}else
    								_delay_us(2600);
    								
    							_delay_us(2600);
    					        }
    									stan1=1;         //oflaguj jako wciśnięty
    						}		 		
    				}
    			
    				
    				
    				
    				 if (bit_is_set(PIND,PD3))
    				 stan1=0;    //jeżeli przycisk jest zwolniony zeruj flagę wciśnięcia
    //*********************************************************************************************************				
    
       }
    return 0;
    }
    
    
    

    Pilot działa i nadaje sygnał.


    Prosiłbym ludzi dobrej woli o sprawdzenie kodu odbiornika.
    Pozdrawiam i dziękuję.
  • #2 6691013
    Kolek
    Poziom 25  
    Możliwe że problem jest głębszy, ale zastanawia mnie dlaczego dla 2MHz taktowania deklarujesz 1,69 MHz czyli o około 15% mniej.
    # define F_CPU  1690000L 

    Nie wiem jak tolerancyjny jest odbiornik ale to spora różnica.
  • #3 6691416
    gjanek
    Poziom 12  
    Dzięki za odpowiedź.

    Tak musialem taktować, żeby dostać czestotliwość ok 36 Khz. Później zamieszcze przebieg pilota z programu VMlab. Może się myle ale pilot raczej działa dobrze. Wydaje mi się, że błąd istnieje w odbiorniku.
  • #4 6691937
    Brutus_gsm
    Poziom 25  
    Prawdopodobnie kod nadajnika masz błędny. Lepiej zrobić tę funkcję na timerach. ;) Będzie ładniej i stabilniej. Funkcje delay mają dużą tolerację, za dużą. I to, że w programie ustawisz F_CPU jako 16900000 nie znaczy, że procesor działa z takim taktowaniem ;) Musisz mieć taki kwarc. Zmienna ta jest tylko pomocna przy niektórych obliczeniach dla kompilatora ;)

    Teraz widzę jeszcze coś. Dla ciebie 1 w rc5 to nadawanie nośnej 36kHz a 0 to przerwa w nadawaniu. Przynajmniej tak widzę w kodzie. A tak wcale nie jest ;) Poczytaj o rc5 tutaj: http://www.sbprojects.com/knowledge/ir/rc5.htm ;) To jest prostsze niż się wydaje ;)

    Podpowiem, że aby wysłać logiczne zero, to przez 889µs musisz podawać na diodę nośną 36kHz a później, przez 889µs nośna ta musi być wyłączona. Aby wysłać jedynkę, to najpierw musi być "pusto" przez 889µs a następnie, przez ten sam czas trzeba podawać nośną. To proste ;)

    Napisz najpierw działający pilot, to później pomyślimy nad odbiornikiem ;) Najprostszy sposób na sprawdzenie działania, to wysyłanie kodu np VOLUME DOWN i sprawdzenie, czy telewizor reaguje na niego ;)

    I tak przy okazji. Zmienić stan pinu możesz trochę inaczej niż masz ;) Wystarczy wykonać funkcję XOR (znak ^ w AVR_GCC) na odpowiednim bicie rejestru ;) Np PORTB ^= 1<<2; Zmieni zawsze pin 2 portu B na przeciwny, niezależnie, czy jest na nim stan 0, czy 1 ;)

    A co to ma być w ogóle? Możesz mnie oświecić?
    overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
                      overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest  
  • #5 6695759
    gjanek
    Poziom 12  
    overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
                      overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest    
             overflow=250;                        // inicjuj zmienną overflow
             while(overflow);                // zmienna overflow jest  
    [/quote]

    Już wyjaśniam, dalem sobie opóźnienie. Wcześniej na dwóch diodach wyświetlam sobie zawartość tab_odbioru.

    Poprawie kod pilota.
    Sprawdzałem przebieg pilota na oscylatorze i nie wygladalo na to, że źle nadaje.
  • #6 6696550
    Brutus_gsm
    Poziom 25  
    Ale przecież ten kawałek kodu nie ma najmniejszego sensu. Nie wiem, co ty chcesz osiągnąć przez ciągłe powielanie tych samych poleceń :/

    Pilot ten pilot nie działa poprawnie. Nie może działać, bo to nawet nie przypomina rc5. Poczytaj sobie o rc5. Koniecznie.

    http://www.sbprojects.com/knowledge/ir/rc5.htm
  • #7 6697254
    gjanek
    Poziom 12  
    ok, zatem biorę się za poprawienie kodu pilota.
  • #8 6699612
    gjanek
    Poziom 12  
    witam,
    Napisałem nowy kod pilota:
    Mam nazieję, że teraz to jest RC5.
    Mogę prosić o sprawdzenie.

    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    
    #define tau0 238;	//stała czasowa dla 36kHZ @8MHz
    volatile uint8_t licz;
    int main(void){ //pocztek funkcji main
    
     
    DDRD=0x00;	//PD0 wejściowy
    PORTD=0xFF;	//z podciąganiem
    
    DDRB=0x00;	//Pb6 wejściowy
    PORTB=0xfF;	//z podciąganiem
    
    TCNT0=tau0;    //wpisz stałą czasową dla zadanego interwału
    //TCNT0=238;    //wpisz stałą czasową dla zadanego interwału
    TCCR0=2;       //timer0 będzie pracował z preskalerem Fosc/8
    
    
    int stan=0;
    //int stan1=0;
    int i;
    int tab[14]= {1,1,1,0,1,1,0,1,1,0,1,0,0,1}; //pierwszy przycisk
    //int tab1[14]={1,1,1,0,0,1,0,1,1,0,1,0,0,1}; //drugi przycisk
    licz=0;
    
    //generacja fali nonej 36kHz
        while(1)
    	{
    PORTD&= ~_BV(PD6);
    //****************************************Pierwszy przycisk*****************************************************************
    
    			  if((bit_is_clear(PIND,PD0)) && (stan==0))   //jeżeli poprzednio nie był wciśnięty
    				{
    					for ( i= 0;i<14;i++)
    					{
    						if(tab[i]==0)
    							{	
    								while (licz<50){
    									while(bit_is_clear(TIFR,TOV0));	//czekaj na ustawienie flagi
    																	//TOV0 (przekręcenie licznika)
    									PORTD^= _BV(PD6);
    									TCNT0=tau0;	//wpisz stałą czasową
    									TIFR=1<<TOV0; //kasuj flagę przepełnieni
    									licz++;
    									}
    										licz=0;
    										
    								while (licz<50){
    									while(bit_is_clear(TIFR,TOV0));	//czekaj na ustawienie flagi
    																	//TOV0 (przekręcenie licznika)
    									TCNT0=tau0;	//wpisz stałą czasową
    									TIFR=1<<TOV0; //kasuj flagę przepełnieni
    									licz++;	
    								}
    								licz=0;	
    							}
    						if(tab[i]==1)
    							{	
    								while (licz<50){
    									while(bit_is_clear(TIFR,TOV0));	//czekaj na ustawienie flagi
    																	//TOV0 (przekręcenie licznika)
    									TCNT0=tau0;	//wpisz stałą czasową
    									TIFR=1<<TOV0; //kasuj flagę przepełnieni
    									licz++;
    									}
    										licz=0;
    										
    								while (licz<50){
    									while(bit_is_clear(TIFR,TOV0));	//czekaj na ustawienie flagi
    																	//TOV0 (przekręcenie licznika)
    									PORTD^= _BV(PD6);
    									TCNT0=tau0;	//wpisz stałą czasową
    									TIFR=1<<TOV0; //kasuj flagę przepełnieni
    									licz++;	
    								}
    								licz=0;	
    							}
    					}
    /*
    								while(bit_is_clear(TIFR,TOV0));	//czekaj na ustawienie flagi
    																	//TOV0 (przekręcenie licznika)
    								PORTD^= _BV(PD6);
    								TCNT0=tau0;	//wpisz stałą czasową
    								TIFR=1<<TOV0; //kasuj flagę przepełnieni
    */
    				}
    			
    				
    				
    				
    				 if (bit_is_set(PIND,PD0))
    				 stan=0;    //jeżeli przycisk jest zwolniony zeruj flagę wciśnięcia
    
       }
    return 0;
    }
    


    Przebieg pilota w programie VMLAB wyglada następująco:

    [C]ATmega 8 i TSOP1736 nadajnik/odbiornik
  • #9 6700774
    Brutus_gsm
    Poziom 25  
    Trochę przekombinowany ten kod ;) Ale powinien działać, bo przebieg faktycznie wygląda na rc5 ;)

    Najlepiej zmontuj sobie przystawkę igorplug pod com do tego program girder. Koszt 5zł a zaoszczędzi ci wiele nerwów ;)
  • #10 6700781
    gjanek
    Poziom 12  
    Miałbyś moze jakieś pomysł jak go mniej przekombinowac??
    No i jeszcze jedno pytanie odnośnie pilota:
    Jak chę uzyskać przebieg o czestotliwości 1 Khz to musze stan portu zmieniac co 500us ( np. ze stanu wyskoniego na niski) czyli caly okres trwa 1 ms.
    W przypadku 36 khz to muszę stan portu zmieniac co 18us ( połowa okresu) ???

    Teraz czas zając sie odbiornikiem, co moge mieć źle?
  • #11 6704063
    Brutus_gsm
    Poziom 25  
    Wykorzystaj jeden z timerów do generowania nośnej, a drugi np do ustalania opóźnień ;) Ja tak zrobiłem w swoim pilocie. ;)

    Timer w trybie CTC zmienia stan na jednej z nózek procesora (poszukaj w nocie jakiej) co przepełnienie. W Datacheecie znajdziesz jak ustawić odpowiednią częstotliwość. Jest odpowiedni wzór ;) Wszystko to jest proste, wystarczy doczytać ;) Jak coś, to pytaj.
  • #12 6705761
    gjanek
    Poziom 12  
    Spoko poczytam i napisze. Niestety teraz jestem zmuszony zawiesić temat na ok 1 tyg. ponieważ nie bedzie mnie na sieci.
  • #13 6706509
    Brutus_gsm
    Poziom 25  
    A i jeszcze jedno. Sterując diodą musisz ustawić kierunek portu jako wyjściowy ;)
  • #14 6708660
    gjanek
    Poziom 12  
    Zgadza się, że mussi być wyjściowy.
  • #15 6711580
    Brutus_gsm
    Poziom 25  
    Więc musisz go ustawić jako wyjściowy. A nie jak masz do tej pory:
    DDRD=0x00;   //PD0 wejściowy
    PORTD=0xFF;   //z podciąganiem
    
    DDRB=0x00;   //Pb6 wejściowy
    PORTB=0xfF;   //z podciąganiem 
  • #16 6746689
    gjanek
    Poziom 12  
    Witam.
    Znowu jestem na sieci to zabieram się dalej za projekt.
    Masz może gdzieś przykładowy program, na którym mógłbym się wzorować odnośnie Timera w trybie CTC, bądź jakieś dobre materiały?
    Z tego co w googlach znajduje to jakoś nic konkretnego - no chyba, że to ja nie mam szczęścia.
    Co do wyjść to masz racje, jakaś pomyłka mi się wdarła.
  • #17 6746699
    Brutus_gsm
    Poziom 25  
    Naprawdę wszystko jest w nocie katalogowej. Wystarczy przeczytać ;) Wszystko jest podane na tacy. Wystarczy skonfigurować kilka rejestrów i to wszystko ;) Jak coś to pytaj.
  • #18 6750941
    gjanek
    Poziom 12  
    Kurde juz nie wiem?

    Mam licznik z CTC napisany w ten sposób:

    
    void SINGAL (SIG_OUTPUT_COMPARE1A)
    {
    PORTB^= _BV(PB1);//generacja fali nonej 36kHz
    //OCR1A = 2800;
    }
    
    


    a w main :
    
    TIMSK = (1<<OCIE1A); 
    TCCR1A = (0<<COM1A0); 
    TCCR1B = (1<<WGM12)|(1<<CS11);
    OCR1A = 13; // ms
    
    sei();
    


    Sam licznik działa ok ale jak go połączę z kodem tym wcześniejszym to czasy rozjeżdżają się??
    co jest nie tak?
    Masz może gdzieś skonfigurowany ten licznik, bo już sam nie wiem.
  • #19 6751161
    Brutus_gsm
    Poziom 25  
    W trybie CTC nie robi się obsługi przerwania. Po prostu konfiguruje się timer i on zajmuje się generowaniem przebiegu prostokątnego na odpowiedniej nóżce procesora. W programie po prostu na odpowiedni czas się go włącza i później wyłącza. U mnie na attiny2313 wygląda to tak.

    void start_freq(void) // generowanie nosnej
    {
    	TCCR0A = 1<<COM0A0 | 1<<WGM01; 	// CTC mode timer 0 toggle 0C1A 
    	TCCR0B = 1<<CS00; 					// clk / 8
    	OCR0A = 110; 						// f = 36kHz
    }
    
    void stop_freq(void) // wylaczenie nosnej
    {
    	TCCR0A = 0;							// wylaczenie timera 0
    	TCCR0B = 0;							// wylaczenie timera 0
    	OCR0A = 0;
    }


    I później tymi funkcjami w odpowiednich miejscach w odpowiednim czasie włączam i wyłączam sobie nośną 36kHz na diodę ;) W trybie CTC (Clear Timer On Compare Match) nie używa się przerwań. Wszystko jest w nocie, razem ze wzorem na częstotliwość. ;)

    Dodano po 23 [minuty]:

    Dla Atmegi8 może to wyglądać np tak (wg noty katalogowej)

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


    [C]ATmega 8 i TSOP1736 nadajnik/odbiornik

    Gdzie N to preskaler. W naszym wypadku 8. FclkI/O to taktowanie procesora.

    To tylko przykład. Żeby ustawić f=36kHz musisz przekształcić wzór na OCRxA.
  • #20 6761137
    gjanek
    Poziom 12  
    Dzięki za satysfakcjonującą odpowiedź.

    Zastosowałem sie do Twojej rady. Timer w trybie CTC działa bardzo ładnie generuje falę nośną 36KHz.
    Drugi Timer również działa dobrze.
    Natomiast jak je połączę w całość to się wszystko rozjeżdża???
    Jest możliwość żeby jeden z tych timerów miał wpływ na drugi?
  • #21 6765454
    Brutus_gsm
    Poziom 25  
    Nie, timery działają niezależnie od siebie. Pokaż kod, może jeszcze coś zdziałamy ;)
  • #22 6771016
    gjanek
    Poziom 12  
    Chyba poradziłem sobie. Wygląda to obiecująco
    Jeszcze muszę to przetestować na żywym obiekcie.

    Jak będzie to działało, to jeszcze zostaje mi odbiornik.
  • #23 6775842
    gjanek
    Poziom 12  
    Zaczełem to sprawdzać na żywym obiekcie i mam cos takiego:
    Pilotem wysylam:
    1,0,0,0,0,0,1,1,0,1,1,1,1,1 - kod pilota, którego używam do TV - jest sprawny bo przełącza mi TV

    Po wklepaniu tego kodu do pilota, którego właśnie robie - otrzmuje:

    1,1,1,0,0,0,0,0,1,1,0,1,1,1,1,1
    Skad pojawiają sie te dwie jedynki??
  • #24 6775845
    Brutus_gsm
    Poziom 25  
    Niestety wróżki wyjechały na urlop ;) Nikt bez kodu nic nie zdziała. A tak w ogóle, to dwa pierwsze bity muszą być jedynkami jeśli wysyłasz rc5. Taki standard ;)
  • #26 6782168
    gjanek
    Poziom 12  
    Znalazłeś tam może jakis błąd?
  • #27 6782516
    Brutus_gsm
    Poziom 25  
    Wybacz, nie miałem czasu zajrzeć w kod (obejrzę go później), ale pierwsze co, to musisz zmienić kod wysyłany przez pilot. Mówiłem Ci, że pierwsze dwa bity MUSZĄ być jedynkami. Tego wymaga standard, inaczej odbiornik ci zgłupieje.
  • #28 6782726
    gjanek
    Poziom 12  
    ok,
    będzie tak jak mówisz. Poprawie to.
  • #29 6783417
    Brutus_gsm
    Poziom 25  
    Przeglądając pobieżnie kod, to powinno być wszystko w porządku ;) Nie zagłębiałem się w obliczenia, ale powinno być w porządku.

    Funkcja dlugosc_impulsu() trochę przekombinowana, ale przeliczona na szybko powinna działać ;) Ale skoro przełącza Ci telewizor, to powinno być ok.

    Pamiętaj tylko o tych dwóch startowych bitach. ;)

    Proponowałbym jednak zamienić timery rolami. Timer 1 jest 16bitowy, więc przy preskalerze 8 możesz sobie spokojnie odczekać te 889us bez kombinowania ;) Po prostu pusta pętla while podczas, gdy wartość timera jest mniejsza niz te 889, a następnie jego zerowanie ;) A timer 0 wystarczy do generowania nośnej 36kHz.
  • #30 6783861
    gjanek
    Poziom 12  
    Dzięki za sprawdzenie kodu.

    Juz chyba nie będę kombinował. Nie przełącza mi TV :( Mój pilot chyba nadaje w standardzie "NEC",
    Nic biorę się za odbiornik.
    Wiesz może gdzie są jakieś dobre materiały do napisanie odbiornika?
REKLAMA