Skocz do zawartości

[C] Problem z sterowanie serwomechanizmem.


pawel

Pomocna odpowiedź

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.

Link do komentarza
Share on other sites

 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.

  • Pomogłeś! 1
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

/* 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:

Link do komentarza
Share on other sites

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.

Link do komentarza
Share on other sites

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.

Link do komentarza
Share on other sites

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]

Link do komentarza
Share on other sites

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?

Link do komentarza
Share on other sites

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 🙂

Link do komentarza
Share on other sites

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...

Link do komentarza
Share on other sites

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.

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.