shaslyk135 Napisano Luty 4, 2015 Udostępnij Napisano Luty 4, 2015 Witam wszystkich Uprzedzam, że nie mam dużego doświadczenia w programowaniu. Atmega328P taktowana jest kwarcem 16MHz. Chcę wygenerować fast PWM (tryb 7) na timerze0 o częstotliwości 36kHz dla diody czujnika odbiciowego. Zastanawia mnie jednak czy to wogóle jest to możliwe na timerze 8 bitowym? Poniżej przedstawię jak ja to sobie wyobrażam. Obliczenia: 16000 000Hz/36000Hz≈444.(4) - Timer ma pojemność 255 więc muszę podzielić preskalerem. Najmniejsza wartość to 8 więc: 444/8≈55 16000 000Hz/8/55≈36 363Hz Około 36kHz czyli się zgadza. Według noty wartość maksymalna jest określana rejestrem OCRA (myślę, że działa to tak samo jak w timerze1). Wstawiam screeny z noty katalogowej. TRYBY TIMERA0 TRYBY TIMERA1 (fragment) Niestety po ustawieniu tego rejestru na wartość 55 Atmel Studio wyświetla błąd: Error 1 'OCRA' undeclared (first use in this function) Wrzucam kod #define F_CPU 16000000UL #include <avr/io.h> #include <util/delay.h> int x=1; int main(void) { DDRB |= 0xFF; //wszystkie porty jako wyjśćia DDRC |= 0xFF; DDRD |= 0xFF; PORTB^= (1<<PB5); //dioda kontrolna /*ustawienie trybu*/ TCCR0A |= (1<<WGM02) | (1<<WGM01) | (1<<WGM00) ; //tryb 7 fastPWM TOP=OCRA TCCR0A |= (1<<COM0A1); //Clear OC0A on Compare Match, set OC0A at BOTTOM, (non-inverting mode). TCCR0A |= (1<<COM0B1); // Jak wyżej tylko OC0B /*preskaler*/ TCCR0B |= (1<<CS01); //clkI/O/8 (From prescaler) OCRA = 55; //wartosc maksymalna (tu wywala błąd) OCR0A = 22; //wypelnienie poczatkowe /* Początek nieskończonej pętli */ while(1) { PORTB ^= (1<<PB5); //kontrolne miganie diody _delay_ms(20); /* fragment poniżej służył mi do testów czy PWM jest generowany wtedy nie wpisywałem nic do rejestru OCRA OCR0A+=x; if(OCR0A==250) x*=-1; if(OCR0A==0) x*=-1; */ } } Domyślam się, że nie można zmienić wartości maksymalnej tak jak w timerze1, ale proszę o opinię kogoś kto lepiej się zna. Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Luty 4, 2015 Udostępnij Luty 4, 2015 W tabelce jest drobna nieścisłość: timer 0 nie ma rejestru nazywającego się OCRA i nic dziwnego, że kompilator tej nazwy nie zna. Chodzi tu o rejestr OCR0A i jeśli chcesz, by Twój PWM miał ustawianą zarówno częstotliwość jak i wypełnienie, to rzeczywiście musisz użyć trybu 7. Ponieważ wtedy okres całego Timera 0 programujesz za pomocą OCR0A, to do generacji PWM zostaje tylko kanał B z jego rejestrem OCR0B i wyjściem na pinie OC0B (PD5). Oba kanały (a kanał A w szczególności) możesz wykorzystać jedynie w przypadku pracy w trybach gdzie TOP=0xFF, bo do tego nie trzeba marnować żadnego rejestru. ---------------------- EDIT: Zapomniałem dodać, że oczekując podziału przez 55, do rejestru OCR1A musisz wpisać 54, bo licznik timera jest zerowany dopiero po komparacji z OCR1A. Łącznie ze stanem 0 daje to 55 stanów licznika. 1 Cytuj Link do komentarza Share on other sites More sharing options...
shaslyk135 Luty 4, 2015 Autor tematu Udostępnij Luty 4, 2015 Dziękuję za odpowiedź. Dziwne, że ten błąd nie został poprawiony przez producenta. Muszę wygenerować dwa przebiegi równocześnie, więc chyba nie pozostaje mi nic innego jak wykorzystać timer1. Rozumiem, że błąd ten występuje też w tabelce dotyczącej timera2 ponieważ jest tam rejestr OCRA Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Luty 4, 2015 Udostępnij Luty 4, 2015 Potrzebujesz dwóch przebiegów o tej samej częstotliwości i różnym wypełnieniu? To faktycznie tylko Timer 1 - ma tryb 14 w którym okres jest programowany rejestrem ICR, niepotrzebnym do PWM. Wtedy oba OCR1x zostają do regulacji wypełnienia. 1 Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. 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
shaslyk135 Luty 4, 2015 Autor tematu Udostępnij Luty 4, 2015 Jak napiszę kod to wstawię go tu w celu weryfikacji 🙂 [ Dodano: 05-02-2015, 15:46 ] Przerobiłem kod timera0 na PWM silników robota i użyłem timera1 do generowania PWMa dla diod IR. #define F_CPU 16000000UL /**************moje definicje*************/ #define SILNIK1_PWM OCR0A #define SILNIK2_PWM OCR0B #define IR1_PWM OCR1A #define IR2_PWM OCR1B /**************moje definicje*************/ #include <avr/io.h> #include <util/delay.h> static inline void pwm_silniki_init (void) { /*ustawienie trybu*/ TCCR0A |= (1<<WGM02) | (1<<WGM01) | (1<<WGM00) ; //tryb 7 fastPWM TOP=OCRA TCCR0A |= (1<<COM0A1); //Clear OC0A on Compare Match, set OC0A at BOTTOM, (non-inverting mode). TCCR0A |= (1<<COM0B1); // Jak wyżej tylko OC0B /*preskaler*/ TCCR0B |= (1<<CS01) | (1<<CS00); //clkI/O/64 (From prescaler) ~976 Hz SILNIK1_PWM = 0; //wypelnienie poczatkowe SILNIK2_PWM = 0; } static inline void pwm_tsop_init (void) { //częstotliwość PWM-------> 16000 000/preskaler/max+1 //16000 000/1/443+1=36.036kHz TCCR1A |= (1<<COM1A1) | (1<<COM1B1); //Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM (non-inverting mode) TCCR1A |= (1<<WGM13) | (1<<WGM12) | (1<<WGM11); //tryb 14 fastPWM top=ICR1 TCCR1B |= (1<<CS10); //clk/1 (No prescaling) ICR1 = 443; //wartość maksymalna IR1_PWM = 0; //wypelnienie początkowe IR2_PWM = 0; } uint8_t x=1; uint8_t y=1; /*funkcja główna*/ int main(void) { DDRB |= 0xFF; //wszystkie porty jako wyjścia DDRC |= 0xFF; DDRD |= 0xFF; PORTB^= (1<<PB5); //dioda kontrolna pwm_silniki_init(); pwm_tsop_init(); /* Początek nieskończonej pętli */ while(1) { PORTB ^= (1<<PB5); //kontrolne miganie diody _delay_ms(20); SILNIK1_PWM+=x; SILNIK2_PWM= ~SILNIK1_PWM; //stan przeciwny do powyższego if(SILNIK1_PWM==250) x*=-1; if(SILNIK1_PWM==0) x*=-1; IR1_PWM +=y; IR2_PWM = IR1_PWM; if(IR1_PWM==443) y*=-1; if(IR1_PWM==0) y*=-1; } } Teraz mam wątpliwości jakie wypełnienie dać dla diod podczerwieni żeby były wykrywane przez czujnik TSOP. Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Luty 5, 2015 Udostępnij Luty 5, 2015 Odpowiedź nie jest prosta. Po pierwsze nie wiemy jak mocno tą diodą sterujesz a po drugie... spróbuj przeczytać ten post i kilka następnych: https://www.forbot.pl/forum/topics34/teoretyzowanie-przed-praktyka-1-podczerwien-w-robotyce-amatorskiej-vt9084,113.htm Cytuj Link do komentarza Share on other sites More sharing options...
shaslyk135 Luty 5, 2015 Autor tematu Udostępnij Luty 5, 2015 Nie wiem czy to coś zmieni ale zapomniałem wspomnieć, że chodzi mi jedynie o wykrywanie ścian w robocie. Atmega ma generować PWM dla diody IR podłączonej przez tranzystor, a czujnik TSOP (nie wiem czy TSOP4836 się nada) w razie wykrycia przeszkody generowałby odpowiedni sygnał. Docelowo mają być dwa czujniki na dwóch osobnych diodach i TSOPach. Chciałbym osiągnąć taki efekt jak na filmiku. Myślałem, że jest to łatwe do zrealizowania, ponieważ sygnał na filmie był nadawany przez NE555. Czy bardzo się mylę co do metody nadawania sygnału? Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Luty 5, 2015 Udostępnij Luty 5, 2015 Acha, czyli nie zadałeś sobie trudu żeby przeczytać i próbować zrozumieć wskazany tekst ani nie zajrzałeś do danych katalogowych swojego TSOPa. Dlaczego ma mi się chcieć odpowiadać na Twoje pytania? Wierz mi, że zadałbyś inne gdybyś przeczytał. 1 Cytuj Link do komentarza Share on other sites More sharing options...
shaslyk135 Luty 5, 2015 Autor tematu Udostępnij Luty 5, 2015 Zobaczyłem że to dłuższy temat i chciałbym się zapoznać z całością, więc zostawiłem lekturę na później. Przepraszam za brak tej informacji. Dzisiaj w nocy zapoznam się z tym tekstem i mam nadzieję, że rozjaśni mi tą kwestię. Cytuj Link do komentarza Share on other sites More sharing options...
shaslyk135 Luty 6, 2015 Autor tematu Udostępnij Luty 6, 2015 Dobra przeczytałem fragment z linku, ale zrozumiałem tylko część. Zacząłem eksperymentować. Poniżej są moje spostrzeżenia. Dla testu podłączyłem wyjście TSOPa do buzzera przez BC557. Na osobnej płytce przez tranzystor wysyłałem czysty sygnał 36kHz (kod z wcześniejszego posta) z różnymi wypełnieniami. Nadajnik i odbiornik były na przeciwko siebie, ale tylko na początku było słychać "piknięcie" oznaczające stan niski. Również po zasłonięciu i ponownym odsłonięciu nadajnika występował ten sam efekt. Dla porównania wziąłem pilota TV i naciskałem klawisz. W tym przypadku dźwięk buzzera powtarzał się co bardzo krótki okres. Jeśli dobrze rozumiem to muszę zasymulować transmisję danych, teraz tylko nie wiem jak to zrobić. Nigdy wcześniej nie nadawałem ani nie dobierałem danych przez podczerwień. Z podlinkowanego tematu wynika, że do przebiegu 36kHz muszę dodać modulację. Teraz zasadnicze pytanie - czy da się to zrobić w łatwy i szybki sposób. Jeśli nie to dam sobie póki co z tym spokój i lepiej zapoznam się z tematem. Cytuj Link do komentarza Share on other sites More sharing options...
Bobby Luty 8, 2015 Udostępnij Luty 8, 2015 Musisz włączać i wyłączać modulację co jakiś czas, np 15 paczek. Najprościej możesz to zrobić włączając i wyłączając timer w pętli głównej z delayem, ale to mało eleganckie rozwiązanie. 1 Cytuj Link do komentarza Share on other sites More sharing options...
shaslyk135 Luty 8, 2015 Autor tematu Udostępnij Luty 8, 2015 Dziękuję za odpowiedź. Jak ma wyglądać każda paczka? Czy sygnał tak jak z artykułu Opis standardu RC5 będzie wykrywany przez czujnik TSOP? Cytuj Link do komentarza Share on other sites More sharing options...
aixI Luty 8, 2015 Udostępnij Luty 8, 2015 Ostatnio (po wielu nieudanych próbach i długich przerwach) popełniłem czujnik optyczny na ATtiny13 i odbiorniku podczerwieni TSOP4836. Jak chcesz mogę pokazać kod (jest napisany w C). Jak chodzi o paczkowanie, to na trzeciej stronie DS'a masz pokazane na wykresach jak to ma wyglądać. DS --> http://www.farnell.com/datasheets/30500.pdf Ja w pętli głównej zrobiłem tak: - Włączam diodę IR - Czekam 600us - Sprawdzam stan na TSOP'ie - Wyłączam diodę IR - Czekam 600us Mam nadzieję, że pomogło. 1 Cytuj Link do komentarza Share on other sites More sharing options...
shaslyk135 Luty 9, 2015 Autor tematu Udostępnij Luty 9, 2015 Kod byłby mile widziany 😃 Jeśli możesz to wrzuć Cytuj Link do komentarza Share on other sites More sharing options...
aixI Luty 9, 2015 Udostępnij Luty 9, 2015 Proszę bardzo 🙂 // Podstawowe biblioteki #include <avr/io.h> #include <avr/pgmspace.h> #include <avr/interrupt.h> #include <stdlib.h> #include <util/delay.h> // Główna funkcja programu int main(void) { DDRB |= (1<<PB0); // OC0A DDRB |= (1<<PB1); // OC0B // Jeżeli czujnik wykrył przeszkodę - wieci dioda LED // DDRB |= (1<<PB2); // PB2 jako wyjcie - dioda LED - blue // Wyjcie czujnika // DDRB |= (1<<PB3); // PB3 jako wyjcie - dioda LED - red PORTB |= (1<<PB3); // Wewnętrzyny rezystor podciągający pull-up DDRB &= ~(1<<PB4); // TSOP4836 - PB4 jako wejcie PORTB |= (1<<PB4); // Wewnętrzyny rezystor podciągający pull-up OCR0B = 16; OCR0A = 16; TCCR0A |= (1<<WGM01) | (1<<COM0A0) |(1<<COM0B0); // COM0B0:Toggle OC0B on Compare Match TCCR0B |= (1<<CS00) | (1<<WGM02); // CS00:clkI/O/(No prescaling) //sei; while(1) { PORTB |= (1<<PB3); // Włączam diodę IR _delay_us(600); // Czekam 600us if(!(PINB & (1<<PB4))) { PORTB |= (1<<PB2); // Wyjście = 1 } else { PORTB &= ~(1<<PB2); // Wyjście = 0 } PORTB &= ~(1<<PB3); // Wyłączam diodę IR _delay_us(600); // Czekam 600us } } 1 Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
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!