pawel Napisano Styczeń 3, 2010 Udostępnij Napisano Styczeń 3, 2010 Natrafiłem dzisiaj na problem sterowania serwomechanizmem w c. Do sterowania używam PWM'u. PWM podczas sterowania silnikami działa normalnie, czyli z tym niema problemu, a jak napisałem program w bascomie do obsługi serw, to wszystko działało. Czyli serwa też są dobre. Serwa cały czas ustawiają się w maksymalnym wychyleniu w jedną stronę. Program może nie wygląda tak jak powinien, ale są to moje początki w c pod AVR. #define F_CPU 4000000 #include <avr/io.h> int main(void) { TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10)|(1<<WGM11); TCCR1B = (1<<CS10)|(1<<WGM12); DDRB = 0xFF; OCR1A = 90; OCR1B = 90; }; Z góry dziękuje za pomoc.
sobal44 Styczeń 4, 2010 Udostępnij Styczeń 4, 2010 int p = 1000; DDRD = 0x20;//wyjscie serwa PORTD = 0x20; ICR1 = 10000; //ustawienie dzielnika by uzyskac 50Hz F=f_uc/2*preskaler*dzielnik OCR1A = p;//wypełnienie // Tryb PWM phase and frequency correct , patrz str. 93 ATmega8 datasheet TCCR1A|=(0<<COM1A0)|(1<<COM1A1)|(0<<COM1B0)|(0<<COM1B1)| (0<<FOC1A)|(0<<FOC1B)|(1<<WGM11)|(0<<WGM10); TCCR1B|=(0<<ICNC1)|(0<<ICES1)|(1<<WGM13)|(1<<WGM12)| (0<<CS12)|(0<<CS11)|(1<<CS10);//preskaler 1 proszę tu masz kod obsługi serwa, ICR1 i preskaler ustawiasz odpowiednio by uzyskać 50Hz później tylko wstaw za p odpowiednia wartość z przedziału (1000-2000) a serwo ci się ustawia jak mu karzesz. np. #define F_CPU 1000000UL #include <avr/io.h> #include <util/delay.h> #include <avr/signal.h> void Inicjalizacja(void) { int p = 1000; DDRD = 0x20; PORTD = 0x20; ICR1 = 10000; OCR1A = p; /* Tryb PWM phase and frequency correct , patrz str. 93 ATmega8 datasheet */ TCCR1A|=(0<<COM1A0)|(1<<COM1A1)|(0<<COM1B0)|(0<<COM1B1)| (0<<FOC1A)|(0<<FOC1B)|(1<<WGM11)|(0<<WGM10); TCCR1B|=(0<<ICNC1)|(0<<ICES1)|(1<<WGM13)|(1<<WGM12)| (0<<CS12)|(0<<CS11)|(1<<CS10);//preskaler 1 } int main(void) { Inicjalizacja(); for (;;) { _delay_ms(1000); p=1000; _delay_ms(1000); p=2000; } } serwo będzie ci się co sekundę ustawiać raz w jedna a raz w drugą strone zazwyczaj serwa można ustawiać w większym przedziale spróbuj. pozdrawiam i życzę powodzenia. 1
SeerKaza Styczeń 4, 2010 Udostępnij Styczeń 4, 2010 ICR1 = 10000; //ustawienie dzielnika by uzyskac 50Hz F=f_uc/2*preskaler*dzielnik zapomniałeś by odejmować jeden czyli ICR1 = 9999. Ponieważ bit 0 także ma wartość TOP
pawel Styczeń 4, 2010 Autor tematu Udostępnij Styczeń 4, 2010 sobal44, Wielkie dzięki, teraz wszystko działa, chociaż musiałem trochę z tym jeszcze pobawić, jeśli chodzi o te wartości.
regrom Styczeń 15, 2010 Udostępnij Styczeń 15, 2010 /* Tryb PWM phase and frequency correct , patrz str. 93 ATmega8 datasheet */ TCCR1A|=(0< (0< TCCR1B|=(0< (0< } PWM phase and frequency correct - czy aby napewno? Według noty WGM10 na 0 , WGM11 na 1, WGM12 na 1, WGM13 na 1 oznacza tryb Fast PWM chyba że się mylę. Strona 97 tabela 39 wiesz 14:
noobek Czerwiec 28, 2011 Udostępnij Czerwiec 28, 2011 Witam, może podłączę się do tematu, zamiast zakłądać nowy. Otóż bazując na tym temacie umieściłem na procku taki kod: #define F_CPU 1000000L #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> int p = 1000; void Inicjalizacja(void) { DDRB = 0b00000100; PORTB = 0b00000100; ICR1 = 9999; OCR1A = p; /* Tryb PWM phase and frequency correct , patrz str. 93 ATmega8 datasheet */ TCCR1A|=(0<<COM1A0)|(1<<COM1A1)|(0<<COM1B0)|(0<<COM1B1)| (0<<FOC1A)|(0<<FOC1B)|(1<<WGM11)|(0<<WGM10); TCCR1B|=(0<<ICNC1)|(0<<ICES1)|(1<<WGM13)|(1<<WGM12)| (0<<CS12)|(0<<CS11)|(1<<CS10);//preskaler 1 } int main(void) { DDRA = 0b11111000; //diody jako wyjscia PORTA = 0b11111000; //swieca na starcie DDRB = 0b00000100; PORTB = 0b00000100; while(1) { Inicjalizacja(); _delay_ms(300); //PORTA = 0b11111000; //diody _delay_ms(1100); PORTA = 0b00000000; _delay_ms(1000); p=1000; _delay_ms(1000); p=2000; } } Pytanie moje brzmi co robię nie tak, gdyż serwo nie rusza się z jednego położenia do drugiego. Właściwie nic nie robi. Gdzie popełniłem błąd? Czy wynika to z faktu, iż u siebie korzystam z ATMegi32 i trzeba coś inaczej ustawić? Serwo mam podpięte do portu PB2. Sprawdzając sobie miernikiem wyjścia z wtyczki znajdującej się na płytce mam +5 V na linii Vcc oraz +5 na linii sygnałowej. Z góry wielkie dzięki za odpowiedzi.
pawel Czerwiec 28, 2011 Autor tematu Udostępnij Czerwiec 28, 2011 Na pewno masz złą wartość w rejestrze ICR1, powinno być tam 20000. Nie rozumiem, dlaczego za każdym razem wywołujesz funkcje inicjalizacja, wywołujesz raz, a potem zmieniasz tylko zawartość rejestru OCR1A.
Harnas Czerwiec 28, 2011 Udostępnij Czerwiec 28, 2011 Nigdzie w pętli nie masz ponownego OCR1A = p; Musisz to umieścić w pętli głównej albo operować bezpośrednio na rejestrze OCR1A zamiast na zmiennej p.
dondu Czerwiec 28, 2011 Udostępnij Czerwiec 28, 2011 Mało istotna dla Twojego problemu poprawka: UL a nie L #define F_CPU 1000000UL W jakim środowisku programujesz?
noobek Czerwiec 29, 2011 Udostępnij Czerwiec 29, 2011 Oczywiście racja, w złym miejscu umieściłem inicjalizacje. Co do wartości 20000 to nie trzeba przypadkiem od niej odjąć 1? Dodatkowo czy dobrze rozumiem - na wyjściu sygnałowym dla serwa powinno być +5 V? Taka wartośc jest, mam jeszcze 2 inne wyjścia na 2 inne serwa i ich nie wysterowuję, toteż na wyjściu sygnałowym mają napięcie 0V. Co ciekawe to gdy przytykam lekko wtyczkę serwa do gniazdka na płytce(takie zwykłe 3 piny wystające) to słychać drobny ruch w serwie - coś tam się jakby rusza. I to niezależnie, czy przytykam do tego gniazda gdzie jest napięcie, czy też do tych 2 innych, gdzie napięcia w ogóle nie ma na linii sygnałowej. Czy to normalne? Wracając do samego programu, czy teraz jest ok?: #define F_CPU 1000000UL #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> int p = 1000; void Inicjalizacja(void) { DDRB = 0b00000100; PORTB = 0b00000100; ICR1 = 20000; OCR1A = p; /* Tryb PWM phase and frequency correct , patrz str. 93 ATmega8 datasheet */ TCCR1A|=(0<<COM1A0)|(1<<COM1A1)|(0<<COM1B0)|(0<<COM1B1)| (0<<FOC1A)|(0<<FOC1B)|(1<<WGM11)|(0<<WGM10); TCCR1B|=(0<<ICNC1)|(0<<ICES1)|(1<<WGM13)|(1<<WGM12)| (0<<CS12)|(0<<CS11)|(1<<CS10);//preskaler 1 } int main(void) { //DDRA = 0b11111000; //diody jako wyjscia //PORTA = 0b11111000; //swieca na starcie Inicjalizacja(); while(1) { _delay_ms(300); //PORTA = 0b11111000; //diody _delay_ms(1100); //PORTA = 0b00000000; _delay_ms(1000); p=1000; OCR1A = p; _delay_ms(1000); p=2000; OCR1A = p; } } Ps. Środowisko to WinAvr[Programmers Notepad]
dondu Czerwiec 29, 2011 Udostępnij Czerwiec 29, 2011 1. Pokaż schemat swojego układu. 2. Masz jakiś oscyloskop lub analizator stanów logicznych? 3. Przy okazji zainstaluj AVR Studio.
noobek Czerwiec 29, 2011 Udostępnij Czerwiec 29, 2011 Ad1 Schemat: Ad2 Nie posiadam takiego sprzętu Czyli, że program jest na 100% ok? być może po prostu płytka jest zwalona? Ad3 W jakim celu wgrywać AVR Studio? coś może pomóc samo środowisko?
dondu Czerwiec 29, 2011 Udostępnij Czerwiec 29, 2011 Ad. 1 Schemat i program przeglądnę jeszcze dzisiaj, ale nieco później Ad. 2 masz tylko o tym nie wiesz: Darmowy oscyloskop i analizator stanów logicznych Ad. 3 WinAVR do AVR Studio, to jak DOS do Windows. Napisałem "przy okazji" bo nie rozwiąże to Twojego problemu, ale pomoże Ci i zmniejszy ilość problemów występujących podczas pisania i kompilowania programów. [ Dodano: 30-06-2011, 02:37 ] Odpowiadając na pytanie czy coś trzeba zmienić przerabiając kod na Atmega32, musisz w sobie wyrobić nawyk, sprawdzania datasheet-y obu układów. Na początek drobne uwagi: - Rezystory przy LED-ach nie są za małe? - Ze schematu wynika, że silniki zasilać będziesz z tego samego stabilizatora co mikrokontroler. Mogą być niezłe zakłócenia pomimo, że dajesz (jak sądzę) C3 i C5 blisko nóżek zasilających mikrokontroler. Wypadałoby nieco oddzielić zasilanie mikrokontrolera. Tryb pracy ustawiany przez WGMxx to FAST PWM, a nie jak pisze w komentarzu, co zauważył i pokazał ładnie kol. regrom. To dość istotna różnica dla mikrokontrolera, ale dla Ciebie czytaj serwa, nie ma znaczenia (chyba). Czym się różnią te dwa przebiegi możesz zobaczyć tutaj: http://mikrokontrolery.blogspot.com/2011/04/pwm-co-to-takiego.html Znajdziesz tam także filmik tłumaczący jak działa PWM (j.ang.) A teraz najważniejszy problem. Podłączyłeś tak sobie serwa pod port B, ale w programie tymi pinami nigdzie nie sterujesz. Jakim cudem więc autorowi tematu serwo działa? No to musisz popatrzeć na schemat Timer1 którego używasz: Zauważysz na nim 2 piny OCnA i OCnB i odpowiadające im rejestry odpowiednio OCRnA i OCRnB. Dlaczego Ci je pokazuję? Ponieważ to właśnie te dwa piny dostarczają sygnał PWM na zewnątrz mikrokontrolera. Ale nie znajdziesz ich na schemacie pinologii układu, ponieważ tam są oznaczenia odpowiednio OC1A i OC1B (dla Timera1). Teraz popatrzmy co ustawiasz bitami COM1A1 i COM1A0 ustawionymi binarnie na 10 (zaznaczone na czerwono) w tabelce poniżej: Ustawiając tak COM1A1 i COM1A0 wybrałeś : Clear OC1A/OC1B on compare match (Set output to low level). Czyli ustawianie zera logicznego na pinie OC1A w momencie gdy OCR1A zrówna się z ICR1 (patrz tabelka wybranego trybu FAST PWM). Czyli tak skonfigurowany Timer1: - ustawia 1 na wyjściu OC1A gdy licznik timera TCNT1 = 0 - ustawia 0 na wyjściu OC1A gdy licznik timera TCNT1 = OCR1A - liczy dalej aż do momentu gdy TCNT1 = ICR1 gdy następuje przepełnienie i zerowanie licznika I tak w kółko. W ten sposób masz na wyjściu OC1A falę prostokątną PWM jak na załączonym wyżej linku. A ponieważ w pętli głównej zmieniasz od czasu do czasu wartość OC1A stąd zmieniasz wypełnienie (duty cycle) wykresu tak jak na animacjach z linku. W konsekwencji serwo będzie miało różny kont wychylenia przy różnym wypełnieniu sygnału PWM. Teraz na zielono zaznaczony jest tekst informujący, że takie ustawienie powoduje automatycznie zmianę funkcji pinu na OC1A. Ale na żółto jest informacja, że DDR tego pinu musi być ustawiony na wyjście. I to w zasadzie wszystko abyś mógł sam już napisać poprawnie program do obsługi 1 serwa na pinie OC1A dla Atmega32. Zapytasz a co z pozostałymi serwami? Do tego dojdziemy, gdy zrozumiesz i napiszesz poprawnie obsługę tego pierwszego serwa. Mam nadzieję, że nic nie pokiełbasiłem
noobek Czerwiec 30, 2011 Udostępnij Czerwiec 30, 2011 Dzięki za odpowiedź. Oto co spłodziłem: Kod: #define F_CPU 1000000UL #include <avr/io.h> #include <util/delay.h> #include <timer8x.h> #include <avr/interrupt.h> void Init(void) { DDRB = 0b00000010; PORTB = 0b00000010; TCCR1A|=(1<<COM1A1)|(1<<WGM11); //Fast PWM TCCR1B|=(1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10); //prescaler=64 FAST PWM ICR1=3124; //fPWM=50Hz (Period = 20ms Standard). DDRB|=(1<<PB1); //PWM Pins as Out } int main(void) { DDRA = 0b11111000; //diody jako wyjscia PORTA = 0b11111000; //swieca na starcie //DDRB = 0b00000001; //PORTB = 0b00000001; Init(); while(1) { _delay_ms(300); PORTA = 0b11111000; //diody _delay_ms(1100); PORTA = 0b00000000; OCR1A=18; _delay_ms(1000); OCR1A=32; _delay_ms(1000); } } ICR1 to wartość TOP ze wzoru na fpwm. Częstotliwość użyta u mnie to 1 Mhz. Wybieram prescaler jako 64 i COM1A oraz COM1B na stan wysoki. TOP wychodzi mi w tym momencie 3124 i tak ustawiam ICR1. Dalej używam trybu fast pwm ustawiając wgmy na 1 1 1 0. Czy to powinno działać? Co do schemtu - te diody to takie zwykłe czerwone diody więc wydaje mi się, że oporniki dają radę. Co do zakłóceń - to mogą występować dopiero przy włączonych silnikach? Pytam, bo teraz z tym programem jak sobie serwo przytknę do gniazdka to jak nim ruszam to serwo wykonuje ruch. tak jakby raz był styk a raz nie. A jak je po prostu wepnę do gniazdka to rusza się tylko w momencie gdy włączam zasilanie. Czy może po prostu coś z płytką jest nie tak? Byłbym bardzo wdzięczny jakbyś dał znać czy ten program powinien serwo obracać a jeśli nie, to co jest nie tak. Przynajmniej mając pewność, że program jest ok mógłbym jakąś ewentualność wyeliminować. Bardzo proszę o pomoc bo jestem już dość zdesperowany...
dondu Lipiec 1, 2011 Udostępnij Lipiec 1, 2011 Zanim sprawdzę kod pytania: - jak wygląda aktualny schemat? - uruchomiłeś oscyloskop lub analizator? Jeżeli tak to pokaż przebiegi. Diody - daj rezystory 330R bo 120R powoduje spory prąd całkiem niepotrzebnie. Pamiętaj także, że poszczególne piny mikrokontrolera oraz cały mikrokontroler, mają ograniczenia prądowe których nie wolno przekraczać, bo grozi to uszkodzeniem mikrokontrolera. Co do zakłóceń - jeżeli pytasz o zakłócenia od silników, to oczywiście dopiero po ich podłączeniu. Sam mostek zakłóceń nie wygeneruje.
Pomocna odpowiedź
Bądź aktywny - zaloguj się lub utwórz konto!
Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony
Utwórz konto w ~20 sekund!
Zarejestruj nowe konto, to proste!
Zarejestruj się »Zaloguj się
Posiadasz własne konto? Użyj go!
Zaloguj się »