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

[ATMEGA16][C][WINAVR] Programowe PWM, serwo stoi w miejscu

mog123 05 Wrz 2008 19:18 4040 12
  • #1 5509118
    mog123
    Poziom 15  
    Witam, napisalem prosty programik, ktory powoduje ze serwo przechodzi przez 100 pozycji a potem cofa sie na poczatek, i problem polega w tym ze serwo wchodzi na 3/4 pozycji i ja utrzymuje, nic wiecej, serwo to Esky micro serwo 8g. Oto program:

    #include <avr/io.h>
    #include <util/delay.h>
    
    int main()
    {
    	int i=0;
    	int timer=0;
    	DDRA=0xff;
    	while(1)
    	{
    		PORTA=0x01;
    		_delay_ms(1);
    		_delay_us(5*i);
    		_delay_us(5*i);
    		PORTA=0x00;
    		_delay_ms(18);
    		_delay_us(500-5*i);
    		_delay_us(500-5*i);
    		timer=timer+1;
    		}
    	if(timer==50)
    		{
    		timer=0;
    		i=i+1;
    		}
    	if(i>=100)
    		{
    		i=0;
    		}
    }
    
    


    Zeby wyprzedzic wszystkich, ktorzy chca napisac: "czemu nie uzywasz wbudowanego PWM?" To odpowiadam: Bo chce napisac programowo :)
  • #2 5509468
    bobbyAIR
    Poziom 20  
    poczytaj jakie maksymalne wartości argumentu może przyjąć _delay_us
  • #3 5509603
    mog123
    Poziom 15  
    czytalem zanim napisalem program, 768/F w MHz, czyli przy 1MHz moge otrzymac 768 us
  • #4 5509665
    riddyk
    Poziom 20  
    A więc też miałem różne problemy przy sterowaniu serwo mechanizmem (HXT 900) i PWM nie działał przy nim ( wewnętrzny kwarc 8MHz/8 ) .

    A więc tak podepnij kwarc 8MHz najlepiej można w górę, ale nie przesadzamy, na wewnętrznym kwarcu serwo trochę "pływa"

    funkcje delay w wersji us jak i w wersji ms nie dają tego czasu którego oczekujesz.

    najlepiej zrobić własne opóźnienie za pomocą pętli for i wstawki asm NOP

    np coś takiego:

    
     		for (z=0; z<10 ;z++)
    		{ asm ("nop") ;}
     


    Edit: czasy przerw należy dobrać eksperymentalnie, tak samo jak maksymalne przesunięcia serwa, bo po przekroczeniu zakresu trochę dziwnie się zachowuje.
  • #5 5509838
    mog123
    Poziom 15  
    serwo wlasnie nie zachowuje sie dziwnie, po prostu jak uruchamiam program, ono ustawia sie do pozycji jakichs pietnastu stopni i tak stoi, nawet nie drzy czy cos, a ruszyc go tez nie mozna. Dziala tak jakby wogole nie widzial if'ów i nie reagowal na nie.
  • #6 5509870
    lelekx
    Poziom 30  
    Gdybyś robił wcięcia w kodzie tak jak należy, dawno byś wiedział. Pozwolę sobie dopisać wskazówkę w komentarze:
    int main() 
    {  // otwórz 1
       int i=0; 
       int timer=0; 
       DDRA=0xff; 
       while(1) 
       { // otwórz 2
          PORTA=0x01; 
          _delay_ms(1); 
          _delay_us(5*i); 
          _delay_us(5*i); 
          PORTA=0x00; 
          _delay_ms(18); 
          _delay_us(500-5*i); 
          _delay_us(500-5*i); 
          timer=timer+1; 
          } //zamknij 2
       if(timer==50) 
          { //otwórz 2
          timer=0; 
          i=i+1; 
          } //zamknij 2
       if(i>=100) 
          { //otwórz 2
          i=0; 
          } //zamknij 2
    }//zamknij 1
  • #7 5509884
    pubus
    Poziom 30  
    No i wcale się nie dziwię...
    Instrukcje warunkowe masz poza główną pętlą programu która jest przecież nieskończona...
  • #8 5509981
    mog123
    Poziom 15  
    tak tylko zaznacze, zrobilem najprostszy program,, stan wysoki, _delay_ms(2), stan niski, _delay_ms(18) i dupa, serwo nawet w polowie nie jest, a jak dam 3 i 17 to serwo jeszcze wczesniej staje :P

    Dodano po 21 [minuty]:

    pubus napisał:
    No i wcale się nie dziwię...
    Instrukcje warunkowe masz poza główną pętlą programu która jest przecież nieskończona...


    Zauwazylem to chwile po zalozeniu tematu, i serwo z pozycji w 3/4 ruszylo na 1/4 i i tak nie rusza.
  • #9 5510040
    zerpo
    Poziom 22  
    Strzelam.
    Funkcje z pliku delay.h pobierają argument, którego wartość musi być znana w trakcie kompilacji. Stosując zmienną przy wywołaniu
    _delay_us(5*i);
    kompilator może wstawić opóźnienie o stałej, nieznanej wartości...

    Może to jest przyczyną. Jeśli tak, to musisz napisać własne funkcje opóźniające.
  • #10 5510120
    mog123
    Poziom 15  
    na AVRfreaks napisali mi ze wlasnie funkcje z util/delay.h dzialaja tylko ze stalymi, nie ze zmiennymi :p
  • #11 5510196
    pubus
    Poziom 30  
    Ja się dziwię dlaczego nie używasz timer'a do dokładnego odmierzania czasu...
    Przecież po to one są...
  • #12 5511972
    riddyk
    Poziom 20  
    To może ja pokaże jak ja wykonałem sterowanie swoich serw

    tak się prezentuje kod dla jednego serwa hxt900, czasy dobrane eksperymentalnie, częstotliwość 1MHz

    
    
    void serwo (void)
    {
    	sbi(PORTD,0);              // serwo 1
    	for (z=0; z<i ;z++)
    	{ asm ("nop") ;}	
    	cbi(PORTD,0);
    
    	for (z=0; z<1500-i ;z++)     // jeżeli obsługujemy więcej niź jedno 
    	{ asm ("nop") ;}                 // serwo odejmujemy więcej z warunku
                                                    // tyle ile trwa wysterowanie kolejnego
                                                    // serwa
    }
    
    
    void klawiatura (void)
    {
    	
    	if (PINB==0xEF)   // w lewo serwo1
    	{
    		i=i+1;
    	}
    	
    	if (PINB==0xF7)   // w prawo serwo1
    	{
    
    		i=i-1;
    	}	
    		
                    for (z=0; z<10 ;z++)   // pauza po przyciśnięciu klawisza
    		{ asm ("nop") ;}
    }
    	
    int main(void)
    {
    	DDRD = 0xff;   // port w stanie wyjść tu są podpięte serwa 
    	DDRB = 0x00;  // przyciski
    	PORTB = 0xff;  // podciągnięcie przycisków
    
    	i=137;      // to jest ustawienie środka serwa1, pozycja początkowa
    	
       for (;;)
      {
    
    	klawiatura();
    		
    	if (i<=39)   i=40;          // ustawienia krańcowe serwa 1
    	if (i>=226)  i=225;
    	
    	serwo();
    
       }
       return 0;
    }
    


    nie poleca korzystać z biblioteki delay, bo te czasy nawet nie są w przybliżeniu tej wielkości jakie chcesz osiągnąć!

    EDIT: Krok jaki możesz osiągnąć to są to czasy dyskretne które możesz osiągnąć. A więc mając wyższy kwarc jesteś w stanie uzyskać większą ilość kroków. Jeśli jesteś w stanie uzyskać przerwę 1 instrukcji a tak się dzieje jak korzystasz z NOP, to masz więcej kroków serwa.
  • #13 5512673
    mog123
    Poziom 15  
    Zrobilem na timerach i... nie dziala. Serwo na PA0 nie reaguje wogole, moge sam nim poruszac, serwo na PA1 utrzymuje pozycje 45' ;/
    Oto kod:
    #include <avr/io.h>
    
    int main (void)
    {
    	DDRA=0xff; //port d jako wyjscia
       	TCCR1B=0x01; // bez preskalera (1mhz)
    	PORTA=0xff;
    	int servo[24]={1300,1700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
       	while(1)
      		{
    		if(TCNT1>=20000)//jesli timer odliczy 20ms
    		{
    		PORTA = 0xff;
    		TCNT1=0;
    		}
    		if(TCNT1>=servo[1] && TCNT1<=20000)
    		{
    		PORTA = PORTA && 0xFE;
    		}
    		if(TCNT1>=servo[2] && TCNT1<=20000)
    		{
    		PORTA = PORTA && 0xFD;
    		}
    	}
    }
    
    


    Dodano po 7 [minuty]:

    ok, kilka poprawek i dziala :)
REKLAMA