Skocz do zawartości

[C] Atmega8 nadajnik IR 36kHz i Timer0 CTC


byxu

Pomocna odpowiedź

A spróbuj sobie zamiast 13 do OCR1A wstawić 14. Bo z obliczeń wychodzi 13,8 czyli bliżej 14 a nie 13.

Na razie masz bliżej 38KHz niż 36KHz.

1 000 000 / 13 = 76923,076 / 2 (bo zmieniamy stan 2 razy) = 38461,538 czyli 38,461 KHz

dla 14 będzie:

1 000 000 / 14 = 71428,571 / 2 = 35714,285 czyli 35,714 KHz a to bliżej 36KHz.

#define F_CPU 8000000UL

#include

#include

#include

int main(void)

{

DDRD = 0xff;

DDRC = 0x00;

DDRB = 0xff;

PORTB = 0xff;

TIMSK |= (1 << OCIE1A); //inicjalizacja przerwania od CTC1A

TCCR1B |= 1<

OCR1A = 14; // f=36kHz

TCCR1B = 1<

sei();

while(1)

{

} // koniec nieskonczonej petli

} // koniec procedury glownej

ISR(TIMER1_COMPA_vect)

{

PORTB^=0x02; //odwraca wartość PB1

}

// tutaj jakieś opreracje np. obsługa czujnika tsop1736 lub sterowanie silnikami przez //mostek-h i nigdy nie używać funkcji delay

Ogólnie można przyjąć że jak z obliczeń wychodzą ułamki to do 0,5 (łącznie z 0,5) zaokrąglamy w dół np 13,5 przyjmujemy 13, a powyżej 0,5 zaokrąglamy do góry np. 13,7 przyjmujemy 14.

brak rezultatów, zasięg nadal tragiczny 🙁

[ Dodano: 30-05-2011, 14:13 ]

A zmieniłeś schemat na taki z jednym tranzystorem gdzie na bazę podajesz pin OC1A? Bo głównym problemem w twoim przypadku jest prawdopodobnie właśnie ten drugi tranzystor który wprowadza tylko zamęt. Ten kod który napisałeś zmienia wyjście OC1A z częstotliwością 36kHz, natomiast twój warunek w przerwaniu tak naprawdę cokolwiek robi tylko za pierwszym razem bo zawsze ustawiasz na nim 1. Poza tym połączenie trybu przerwaniowego i hardwarowego jest dość dziwne. Nigdy czegoś takiego nie używałem. Jesteś pewny, że tak miał działać twój program?

Proponował bym abyś zmienił schemat na taki jak opisałem na początku, a potem przerobił kod albo na obsługę czysto hardwarową albo czysto przerwaniową. Na szybko edytowałem twój kod według tych dwóch opcji. Najlepiej sprawdź z datasheetem czy wszystko jest ok.

Opcja pierwsza:

#define F_CPU 8000000UL 
#include <avr/io.h>

int main(void)
{
DDRD = 0xff;
DDRC  = 0x00;
DDRB = 0xff;
PORTB = 0xff; 

TCCR1A |= 1<<COM1A0; // toggle OC1A on Compare Match
TCCR1B |= 1<<WGM12; // CTC mode
OCR1A = 13;   // f=36kHz
TCCR1B = 1<<CS11; //prescaler clk/8 przykladowo

while(1) {}
}

Tutaj robisz metodą bez przerwań z hardwareową zmianą pinu OC1A. Dlatego niepotrzebne części kodu usuwasz. Nie potrzebujesz w tym sposobie przerwań, dlatego nie musisz nawet dodawać biblioteki interrupt.

Opcja druga:

#define F_CPU 8000000UL
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>




int main(void)
{

   DDRD = 0xff;
   DDRC  = 0x00;
   DDRB = 0xff;
   PORTB = 0xff;


TIMSK |= (1 << OCIE1A); //inicjalizacja przerwania od CTC1A   
TCCR1B |= 1<<WGM12; // CTC mode
OCR1A = 13;   // f=36kHz
TCCR1B = 1<<CS11; //prescaler clk/8 przykladowo

sei();

while(1)
{
} // koniec nieskonczonej petli       
} // koniec procedury glownej   

ISR(TIMER1_COMPA_vect)
{
PORTB^=0x02; //odwraca wartość PB1

// tutaj jakieś opreracje np. obsługa czujnika tsop1736 lub sterowanie silnikami przez //mostek-h i nigdy nie używać funkcji delay
}

Tutaj w funkcji przerwania negujesz PB1, nie potrzebujesz natomiast ustawiać COM1A0.

Mam nadzieję, że teraz będzie ok.

ale ja ten tranzystor mam po to by móc włączać diodę kiedy mi się podoba, takich diod będę miał 3 i ten tranzystor działa tylko jako klucz/przełącznik więc myślę że on wiele nie miesza w systemie, np. ten kod w moim drugim poście co podałem to działa ale on nie jest na timerze. Takie rozwiązanie jest według mnie wygodne bo nie musze generować częstotliwości na innych pinach tylko na jednym.

Link do komentarza
Share on other sites

Jeżeli chcesz kompletnie wyłączyć diodę, dajesz preskaler na 0, wtedy licznik jest wyłączony i nie zmienia wyjścia. I jeszcze dodatkowo możesz ustawić w funkcji stopu ręczne zerowanie tego pinu. Wtedy tylko jeden tranzystor ci wystarczy.

Co do tej częstotliwości bliższej 38kHz. Pisałem wyżej, żebyś dał mniejszy preskaler. Wtedy z dużo większą dokładnością możesz przybliżyć tą częstotliwość. Np jeśli dasz preskaler 1 i ustawisz OCR1A = 111 to masz częstotliwość prawie idealnie na 36kHz (8000000/(111*2) = 36.036kHz

Z tego co wiem, TSOPy są bardzo podatne na różnice częstotliwości więc być może to jest właśnie przyczyna

Link do komentarza
Share on other sites

Jeżeli chcesz kompletnie wyłączyć diodę, dajesz preskaler na 0, wtedy licznik jest wyłączony i nie zmienia wyjścia. I jeszcze dodatkowo możesz ustawić w funkcji stopu ręczne zerowanie tego pinu. Wtedy tylko jeden tranzystor ci wystarczy.

Co do tej częstotliwości bliższej 38kHz. Pisałem wyżej, żebyś dał mniejszy preskaler. Wtedy z dużo większą dokładnością możesz przybliżyć tą częstotliwość. Np jeśli dasz preskaler 1 i ustawisz OCR1A = 111 to masz częstotliwość prawie idealnie na 36kHz (8000000/(111*2) = 36.036kHz

Z tego co wiem, TSOPy są bardzo podatne na różnice częstotliwości więc być może to jest właśnie przyczyna

Czyli mam usunąć tranzystor z bazą na PD0, Za 2 godziny sprubuję jak to działa, mam jeszcze jedno pytanie, czy można ustawić np. generowanie częstotliwości na pinach np. PD7, PC2 i PB4 jednocześnie i jak to zapisać? Preskaler 1 to będzie: TCCR1B = (1<

Link do komentarza
Share on other sites

Ustawiasz timer w tryb przerwaniowy i piszesz w funkcji przerwania:

PORTD ^= 0b10000000 //zmiana wartosci pinu D7

PORTC ^= 0b00000100 //zmiana C2

PORTB ^= 0b00010000 //zmiana B4

Co do preskalera to w datasheecie atmegi jak otworzysz timer1 i register summary to tam masz taką tabelkę z rozpiską jakie ustawienie bitów konfiguracyjnych daje jaki preskaler

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

ok dzięki za jakieś 2-3 godziny się jeszcze odezwę i powiem co z tego wyszło.

[ Dodano: 30-05-2011, 17:52 ]

Zrobiłem tak jak mówiłeś, wywaliłem ten drugi tranzystor ale to praktycznie nic nie dało (wzrost zasięgu ok 5cm), Nie działa tak elegancko jak kod z mojego drugiego postu, zmieniłem prescaler na 1. Ja już sam nie wiem co jest nie tak 😥

#define F_CPU 8000000UL 
#include <stdio.h> 
#include <avr/io.h> 
#include <avr/interrupt.h>




int main(void) 
{ 

   DDRD = 0xff; 
   DDRC  = 0x00; 
   DDRB = 0xff; 
   PORTB = 0xff; 


TIMSK |= (1 << OCIE1A); //inicjalizacja przerwania od CTC1A    
TCCR1A |= 1<<COM1A0; // toggle OC1A on Compare Match 
TCCR1B |= 1<<WGM12; // CTC mode 
OCR1A = 111;   // f=36kHz // 8000000/(2+(2*36000))
TCCR1B = (1<<CS10); //prescaler clk/1 


sei(); 



while(1) 
{ 
} // koniec nieskonczonej petli        
} // koniec procedury glownej    

ISR(TIMER1_COMPA_vect) 
{ 

PORTB^=0x02; //odwraca wartość PB1 


// tutaj jakieś opreracje np. obsługa czujnika tsop1736 lub sterowanie silnikami przez //mostek-h i nigdy nie używać funkcji delay
} 
Link do komentarza
Share on other sites

wywal linijkę

TCCR1A |= 1<

i sprawdź jak będzie wtedy. Bo inaczej działania hardwarowe i przerwaniowe się znoszą. Toggle on compare ustawia bit a chwilę później przerwanie go zeruje.

Link do komentarza
Share on other sites

wywal linijkę

TCCR1A |= 1<

i sprawdź jak będzie wtedy. Bo inaczej działania hardwarowe i przerwaniowe się znoszą. Toggle on compare ustawia bit a chwilę później przerwanie go zeruje.

Bez zmian 😥

Link do komentarza
Share on other sites

Sprawdziłem w datsheecie jeszcze raz i wygląda, że wszystkie rejestry timera są dobrze ustawione. Albo jest jakiś głupi błąd którego nie widzimy (tylko gdzie on może być w takim małym programie?) albo wina nie leży po stronie softu.

Link do komentarza
Share on other sites

Sprawdziłem w datsheecie jeszcze raz i wygląda, że wszystkie rejestry timera są dobrze ustawione. Albo jest jakiś głupi błąd którego nie widzimy (tylko gdzie on może być w takim małym programie?) albo wina nie leży po stronie softu.

A możliwe że procesor nie jest naprawde taktowany 8MHz? Niby nową atmegę8 z fabrycznym zegarem 1MHz w programie mkAvrCalculator przestawiłem na wewnętrzny 8MHz. Może to ma jakieś znaczenie ale np. podłączyłem sobie też zwykłą diodę led białą do tego tranzystora i zmiana wartości OCR1A nic nie daje. Innymi słowy ustawiając różne wartości np. 650 i 50000 nie zmienia częstotliwości migania tej diody, dopiero zmiana prescalera zmienia tą częstotliwość. A może ta moja Atmega8 jest z jakąś wadą fabryczną? Czujnik tsop1736 napewno jest dobry bo sygnał z pilota do telwizora łapie z 2-3 metrów. 😥

Link do komentarza
Share on other sites

Dobra, znalazłem ten głupi błąd. Dając preskaler 1 kasujesz ustawienie CTC i licznik pracuje do przepełnienia. Spróbuj podmienić konfigurację timera na coś takiego:

TIMSK |= (1 << OCIE1A); //inicjalizacja przerwania od CTC1A

OCR1A = 111; // f=36kHz // 8000000/(2+(2*36000))

TCCR1B |= (1<

  • Lubię! 1
Link do komentarza
Share on other sites

Dobra, znalazłem ten głupi błąd. Dając preskaler 1 kasujesz ustawienie CTC i licznik pracuje do przepełnienia. Spróbuj podmienić konfigurację timera na coś takiego:

TIMSK |= (1 << OCIE1A); //inicjalizacja przerwania od CTC1A

OCR1A = 111; // f=36kHz // 8000000/(2+(2*36000))

TCCR1B |= (1<

No Wreszcie działa jak należy. 😃 Wielkie dzięki dla ciebie za pomoc i zaangażowanie. Jakby nie ty to mógłbym sobie w nosie pogrzebać a nie to oprogramować. Jeszcze jedno małe pytanko jakbym chciał w funkcji przerwania zrobić jakieś opóźnienie to muszę jakąś pętlę zastosować która mi to opÓźni? np.

for(i=0; i<100; i++)
{}
Link do komentarza
Share on other sites

a do czego miało by to opóźnienie służyć? Jak wyżej pisałem w samej funkcji przerwania nie powinieneś robić żadnych opóźnień. Jeżeli chciał byś na jakiś czas przerwać wysyłanie to najlepiej realizować to w głównej pętli i z pomocą dodatkowej zmiennej. Na przykład jak chcesz po 20 impulsach robić przerwę to piszesz:

#define F_CPU 8000000UL
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile unsigned char aaa=0;


int main(void)
{

   DDRD = 0xff;
   DDRC  = 0x00;
   DDRB = 0xff;
   PORTB = 0xff;

TIMSK |= (1 << OCIE1A); //inicjalizacja przerwania od CTC1A
OCR1A = 111; // f=36kHz // 8000000/(2+(2*36000))
TCCR1B |= (1<<WGM12) | (1<<CS10); // CTC mode i preskaler 1

sei();

while(1)
{
if(aaa>19)
  {
    TCCR1B &= 0xF8; //zamieniasz 3 ostatnie bity na 0 czyli wyłączasz preskaler
    _delay_ms(100);

/*używasz delaya w głównej funkcji a nie w przerwaniu, dzięki temu jakieś inne przerwania po rozbudowaniu programu np ADC, USART itp mogą w międzyczasie być obsługiwane */
    aaa=0;
    TCCR1B |= (1<<CS10);   //zerujesz pomocnicza zmienna i uruchamiasz timer od nowa

  }
} // koniec nieskonczonej petli       
} // koniec procedury glownej   

ISR(TIMER1_COMPA_vect)
{
aaa++; //dodajesz obsluge dodatkowej zmiennej
PORTB^=0x02; //odwraca wartość PB1


// tutaj jakieś opreracje np. obsługa czujnika tsop1736 lub sterowanie silnikami przez //mostek-h i nigdy nie używać funkcji delay
}

Pisałem ten kod z głowy więc znowu może być jakiś głupi błąd, ale mam nadzieję, że będzie ok.

Link do komentarza
Share on other sites

No dziekuję bardzo za pomoc to już mi powinno wystarczyć. Dobrze że ziemia nosi jeszcze takich ludzi jak ty. 🙂

Temat do zamknięcia.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.