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

Sterowanie silnikiem krokowym za pomocą potencjometru[C]

nelik1987 22 Lip 2009 12:38 9686 26
  • #1 6808874
    nelik1987
    Poziom 31  
    Witam buduje układ dzięki któremu będę mógł sterować silnikiem krokowym za pomocą potencjometru. Wykorzystałem przetwornik A/D. Najpierw sprawdzany jest stan rejestru ADCW a jego wartość zapisywana jest do zmiennej value w postaci dziesiętnej. Następnie program sprawdza o ile zwiększyło się value, oblicza różnicę i zapisuje do zmiennej b jako wartość dodatnią. Wartość w zmiennej b to ilość kroków jakie trzeba wykonać. Następnie wykonywana jest część programu odpowiedzialna za obracanie silnika.

    Problem polega na tym że jeżeli wartość rejestru ADCW czyli tym samym wartość value osiągnie wartość 256 lub większą silnik kręci się cały czas i nie wychodzi z for'a odpowiedzialnego za odliczanie ilości kroków, wygląda to tak jak by wartość zmiennej b (ilość kroków) była nieskończona

    // Testowanie przetwornika analogowo/cyfrowego
    // konwersja samobieżna
    
    #include <avr/io.h>                // dostęp do rejestrów
    #include <stdlib.h>
    #include <util/delay.h>
    
    
    #define TR0_ON PORTB |= _BV(1);
    #define TR0_OFF PORTB &= ~_BV(1);
    
    #define TR1_ON PORTB |= _BV(2);
    #define TR1_OFF PORTB &= ~_BV(2);
    
    #define TR2_ON PORTB |= _BV(3);
    #define TR2_OFF PORTB &= ~_BV(3);
    
    #define TR3_ON PORTB |= _BV(4);
    #define TR3_OFF PORTB &= ~_BV(4);
    int value;
    volatile uint16_t value1;
    unsigned char y = 1;
    unsigned char a = 0;
    unsigned char b = 0;
    unsigned char i = 0;
    
    int main(void)                        // program główny
    {
      TCCR0 |= ((1 << CS00) | (1 << CS02)); 		//Ustawia timer0 z preskalerem Fcpu/1024
      DDRD = 0xFF;                         // wszystkie linie PORTD jako wyjścia
      DDRB = 0xFF;                         // wszystkie linie PORTB jako wyjścia
      ADMUX = 0;                        // wybierz kanał 0 przetwornika ADC
      ADCSR = _BV(ADEN)|_BV(ADIE)|_BV(ADFR)|_BV(ADSC)|_BV(ADPS0)|_BV(ADPS1);
                                      // włącz przetwornik ADC w trybie samobieżnym
                                      // uruchom generowanie przerwań
                                      // częstotilwość taktowania F_ADC=F_CPU/64
                                      // przy F_CPU=8MHz : F_ADC=125 kHz
    
    
      while(1)                        // pętla nieskończona
      {
      
        int value = ((ADCH << 8) | (ADCL));                        // czytaj wartość z przetwornika ADC i zapisz ją do value
    	value1 = ADCW;
        PORTD = (value1>>2);                 // wyślij przetworzoną wartość na LED
    
      b=abs(a-value);
     
      for(i=0;i<=b;i++)
      {
    
          if(a<value)
    		{
    		  y++;
    		  if(y==9)
    		  y=1;
    		}
    		
    		
          if(a>value)
    		{
    		  y--;
    		  if(y==0)
    		  y=8;
    		}
    			
    	
    	  switch(y)
    		{
    		case 1 :
    		TR0_ON;
    		TR1_OFF;
    		TR2_OFF;
    		TR3_OFF;
    		break;
    	
    		case 2 :
    		TR0_ON;
    		TR1_ON;
    		TR2_OFF;
    		TR3_OFF;
    		break;
    		
    		case 3 :
    		TR0_OFF;
    		TR1_ON;
    		TR2_OFF;
    		TR3_OFF;
    		break;
    		
    		case 4 :
    		TR0_OFF;
    		TR1_ON;
    		TR2_ON;
    		TR3_OFF;
    		break;
    		
    		case 5 :
    		TR0_OFF;
    		TR1_OFF;
    		TR2_ON;
    		TR3_OFF;
    		break;		
    		
    		case 6 :
    		TR0_OFF;
    		TR1_OFF;
    		TR2_ON;
    		TR3_ON;
    		break;
    		
    		case 7 :
    		TR0_OFF;
    		TR1_OFF;
    		TR2_OFF;
    		TR3_ON;
    		break;
    		
    		case 8 :
    		TR0_ON;
    		TR1_OFF;
    		TR2_OFF;
    		TR3_ON;
    		break;
    		}
    
    		_delay_ms(10); //czekaj 10 ms
      }  
    		a=value;
      }
    }
    
  • Pomocny post
    #2 6808904
    wdogli
    Poziom 18  
    Witam.
    Zmienna typu unsigned char jest 1 bytowa
    
    unsigned char y = 1; 
    unsigned char a = 0; 
    unsigned char b = 0; 
    unsigned char i = 0;
    

    wiec możesz do niej zapisać jedynie wartość od 0 - 255 więcej sie nie da może to jest przyczyna twojego problemu
    Pozdrawiam
  • #3 6809105
    nelik1987
    Poziom 31  
    właśnie nie wiedziałem jakie wartości może przechowywać char no i tak jak piszesz jest to 1 bajt (8 bitów czyli 0-255) , zmieniłem to na int i wszystko jest OK int przechowuje 2 bajty (16 bitów) a long int przechowuje 4 bajty (32 bity)

    dziękuję za pomoc
  • #4 6884766
    rpal
    Poziom 27  
    Ten silnik i potencjometr to układ skończony czy podlega ew. modyfikacją ? Jeśli tak to prościej będzie sterować przyciskami <- , -> obędzie się wówczas bez przetwarzania napięcia. A jeśli kolega by jeszcze chciał to udoskonalić to są gotowe scalaki które np. po I2C można sterować tak że regulują odpowienio fazy dla silnika krokowego .
  • #5 6884988
    nelik1987
    Poziom 31  
    układ był stworzony tylko i wyłącznie do sprawdzenia działania chwytaka w ramieniu robota. Wykonałem już sterowania przyciskami ale bardziej naturalne było sterowanie potencjometrem

    Oto efekty:

    Sterowanie potencjometrem






    Sterowanie przyciskami



  • #6 6885985
    rpal
    Poziom 27  
    MOżesz zawsze posłużyć się rollerem od myszy :) Będzie niby analogowo ale cyfrowo .
  • #7 6886800
    Dr.Vee
    VIP Zasłużony dla elektroda
    nelik1987 napisał:
    
          if(a<value)
    		{
    		  y++;
    		  if(y==9)
    		  y=1;
    		}
    		
    		
          if(a>value)
    		{
    		  y--;
    		  if(y==0)
    		  y=8;
    		}
    
          /* tutaj brzydki switch-case */
    

    Powyższy kod bym zamienił na:
    
            /* stałe - używamy rozrzerzenia gcc dla literałów binarnych */
            enum { max_krok = 8 };  /* potęga dwójki dla efektywnego modulo */
            const uint8_t maska_krokow = 0b1111 << 1;
            const uint8_t kroki[max_y] = {
                0b0001 << 1,
                0b0011 << 1,
                0b0010 << 1,
                0b0110 << 1,
                0b0100 << 1,
                0b1100 << 1,
                0b1000 << 1,
                0b1001 << 1,
            };
            uint8_t krok = 0;
    
            /* gdzieś dalej ... */
            if (a < value)
                krok += 1;
            else if (a > value)
                krok -= 1;
    
            krok %= max_krok;        /* kompilator optymalizuje modulo potęgi 2 */
    
            uint8_t tmp = PORTB;
            tmp &= ~maska_krokow;    /* czyść maskowane bity */
            tmp |= kroki[krok];      /* ustaw odpowiednie bity */
            PORTB = tmp;             /* zapisz do rejestru */
    

    Od razu wiadomo, o co chodzi, można szybko zmienić liczbę kroków, sekwencję
    sterującą itd.

    Pozdrawiam,
    Dr.Vee
  • #8 6942272
    xml2000
    Poziom 17  
    Witam
    Czy mozna poprosić o schemat ideowy tego sterownika ponieważ buduję wiertarkę kolumnową do zastosowania w garażu i takie sterowanie było by idealne .A autor nie ma czasu żeby odpisać na pw . :)bo jest zajęty budową robota .
  • #9 6942757
    nelik1987
    Poziom 31  
    autor nie jest aż tak zajęty :)

    tylko był na wakacjach :)

    // Testowanie przetwornika analogowo/cyfrowego
    // konwersja samobieżna
    
    #include <avr/io.h>                // dostęp do rejestrów
    #include <stdlib.h>
    #include <util/delay.h>
    
    
    #define TR0_ON PORTB |= _BV(1);
    #define TR0_OFF PORTB &= ~_BV(1);
    
    #define TR1_ON PORTB |= _BV(2);
    #define TR1_OFF PORTB &= ~_BV(2);
    
    #define TR2_ON PORTB |= _BV(3);
    #define TR2_OFF PORTB &= ~_BV(3);
    
    #define TR3_ON PORTB |= _BV(4);
    #define TR3_OFF PORTB &= ~_BV(4);
    unsigned int value;
    volatile uint16_t value1;
    unsigned int y = 1;
    unsigned int a = 512;
    unsigned int b = 0;
    unsigned int i = 0;
    
    int main(void)                        // program główny
    {
      TCCR0 |= ((1 << CS00) | (1 << CS02)); 		//Ustawia timer0 z preskalerem Fcpu/1024
      DDRD = 0xFF;                         // wszystkie linie PORTD jako wyjścia
      DDRB = 0xFF;                         // wszystkie linie PORTB jako wyjścia
      ADMUX = 0;                        // wybierz kanał 0 przetwornika ADC
      ADCSR = _BV(ADEN)|_BV(ADIE)|_BV(ADFR)|_BV(ADSC)|_BV(ADPS0)|_BV(ADPS1);
                                      // włącz przetwornik ADC w trybie samobieżnym
                                      // uruchom generowanie przerwań
                                      // częstotilwość taktowania F_ADC=F_CPU/64
                                      // przy F_CPU=8MHz : F_ADC=125 kHz
    	
      while(1)                        // pętla nieskończona
      {
      
        int value = ((ADCH << 8) | (ADCL));                        // czytaj wartość z przetwornika ADC
    	
    	value1 = ADCW;
        PORTD = (value1>>2);                 
    
    
      b=abs(a-value);
    
     
      for(i=0;i<=b/2.0;i++)
      {
    
          if(a<value)
    		{
    		  y++;
    		  if(y==9)
    		  y=1;
    
    		}
    		
    		
          if(a>value)
    		{
    		  y--;
    		  if(y==0)
    		  y=8;
    
    		}
    			
    	
    	  switch(y)
    		{
    		case 1 :
    		TR0_ON;
    		TR1_OFF;
    		TR2_OFF;
    		TR3_OFF;
    		break;
    	
    		case 2 :
    		TR0_ON;
    		TR1_ON;
    		TR2_OFF;
    		TR3_OFF;
    		break;
    		
    		case 3 :
    		TR0_OFF;
    		TR1_ON;
    		TR2_OFF;
    		TR3_OFF;
    		break;
    		
    		case 4 :
    		TR0_OFF;
    		TR1_ON;
    		TR2_ON;
    		TR3_OFF;
    		break;
    		
    		case 5 :
    		TR0_OFF;
    		TR1_OFF;
    		TR2_ON;
    		TR3_OFF;
    		break;		
    		
    		case 6 :
    		TR0_OFF;
    		TR1_OFF;
    		TR2_ON;
    		TR3_ON;
    		break;
    		
    		case 7 :
    		TR0_OFF;
    		TR1_OFF;
    		TR2_OFF;
    		TR3_ON;
    		break;
    		
    		case 8 :
    		TR0_ON;
    		TR1_OFF;
    		TR2_OFF;
    		TR3_ON;
    		break;
    		}
    
    		_delay_ms(3);
      }  
    		a=value;
      }
    }
    


    dodam tylko, że jest to program testowy wykorzystany tylko i wyłącznie do sprawdzenia jak zachwowuja się silniki, dlatego nie szukajcie w nim optymalizacji itp, tam się nawet mogą znaleść kawałki kody z innych programów, robuiłem to na szybko byle działało
  • #10 6944726
    xml2000
    Poziom 17  
    Witam czy z programu da się odczytać gdzie co jest podłączone bo męczę się od kilkunastu minut i nic konstruktywnego nie mogę wykombinować :D chyba że autor ma tez schemat to byłbym wdzięczny bo zaoszczędzi mi to sporo czasu .
  • #11 6944829
    nelik1987
    Poziom 31  
    Wszystko jest w programie, przecież trzeba zadeklarować jaki port do czego tak więc

    #define TR0_ON PORTB |= _BV(1);
    #define TR0_OFF PORTB &= ~_BV(1);
    
    #define TR1_ON PORTB |= _BV(2);
    #define TR1_OFF PORTB &= ~_BV(2);
    
    #define TR2_ON PORTB |= _BV(3);
    #define TR2_OFF PORTB &= ~_BV(3);
    
    #define TR3_ON PORTB |= _BV(4);
    #define TR3_OFF PORTB &= ~_BV(4); 


    TR0_ON / TR0_OFF oznacza załącz / wyłącz tranzystor (początkoiwo miały byc tranzystory ale wykorzystałem układ ULN2003) i jak widac wykorzystane zostały piny PB1...PB4 jako wyjscia sterujące układ ULN2003 a z wyjśc układu do silnika krokowego

    schemat podłączenia (bardzo podobny masz tutaj: http://www.wkretak.pl/readarticle.php?article_id=5 tylko zamiast portu LPT jest uC)

    potencjometr podłączasz tak jak pokazano tutaj: http://www.avr.elektroda.eu/?q=node/30

    tak jak na schemacie dodałem jeszcze diody do sprawdzania stanu rejestru przetwornika

    schematu nie ma bo wszytsko to wykonuje odrazu na płytce stykowej
  • #12 6945775
    xml2000
    Poziom 17  
    Dziękuję dokładnie o to mi chodziło bo mozna się czegos nauczyć a z gotowego schematu to tylko bym poskładał i już :).
  • #14 7548810
    Mihó
    Poziom 27  
    Hmmm... A czy rozważyłeś problem samodzielnego przemieszczenia się Twojego manipulatora ? Załóżmy, że wyłączysz urządzenie, a ktoś go poruszy. Zmieni się wówczas ilość kroków, jaka pozostała od pozycji, w której ostratnio ustawiłeś manipulator do skrajnej pozycji. Jak to można zabezpieczyć ?
  • #15 7548955
    nelik1987
    Poziom 31  
    Można to zabezpieczyć czujnikami krańcowymi. Po załączeniu robota należy wtedy wykonać inicjalizację polegającą na poruszaniu się aż do czujnika krańcowego a potem powrót do ustalonej pozycji licząc kroki. Ma to jednak wadę po podczas obracania robot może zgubić krok i wtedy obliczenia idą w łeb. Można też zastosować przetwornik obrotowo impulsowy ale są one dość drogie.
  • #16 7683420
    avo3
    Poziom 11  
    Dzień dobry,
    Jestem początkujący jeśli chodzi o programowanie up. Proszę o pomoc steruje silnikiem krokowym tak jak filmie. Układ już mam atmega zaprogramowany wszystko działa. Jednak chciał bym mieć możliwość regulacji liczby kroków, ponieważ teraz potencjometr jest zbyt czuły i przy minimalnym pokręceniu silnik robi jak do mojego zastosowania za duży obrót. Próbowałem coś zmieniać w programie, ale nic z tego nie wyszło. Czy mogl bym prosić o wyjaśnienie bądź wskazówkę co zmienić w programie.
    pzdr
  • #17 7683963
    revolt
    Poziom 34  
    A ja przeproszę, że tak z innej beczki trochę, ale pytanie idealnie pasuje do kodu. Gdzieś mi przeleciało, że zamiast switch() case lepiej zrobić odpowiednią ilość if-ów, że ma to wpływ na objętość kodu po kompilacji. Czy to prawda?
  • #19 7686856
    nelik1987
    Poziom 31  
    b=abs(a-value);


    b- to ilość krokó jaka ma wykonać silnik, a to wartość przetwornika która była odczytana wcześniej a value to wartość przetwornika doczytana przed chwilą, wystarczy podzielić b na przykład przez 2 i otrymasz 2 razy wolniejszy ruch w stosunku do obrotu potencjometrem
  • #20 7687184
    avo3
    Poziom 11  
    Bardzo dziękuję za informację czyli linia powinna wyglądać tak:

    b/2=abs(a-value)

    czy mam rację?
  • #21 7687263
    boohoo
    Poziom 12  
    avo3 napisał:

    b/2=abs(a-value)

    czy mam rację?

    Oczywiście że nie. Niepoprawnie matematycznie, co dopiero programowo.
    Powinno być:

    b=abs(a-value)/2
  • #22 7687467
    avo3
    Poziom 11  
    dziękuję za pomoc
    pzdr
  • #23 7688051
    nelik1987
    Poziom 31  
    boohoo napisał:
    avo3 napisał:

    b/2=abs(a-value)

    czy mam rację?

    Oczywiście że nie. Niepoprawnie matematycznie, co dopiero programowo.
    Powinno być:

    b=abs(a-value)/2


    a najlepiej
    b=abs(a-value)/2.0
    tak by kompilator nie zrobił problemu przy kompilacji, przynajmniej mnie tak uczyli języka C :)
  • #24 7690774
    boohoo
    Poziom 12  
    Cytat:
    a najlepiej
    b=abs(a-value)/2.0
    tab by kompilator nie zrobił problemu przy kompilacji, przynajmniej mnie tak uczuli języka C :)

    Hm, a nie będzie wtedy wyrzucało ostrzeżenia o konwersji z double do unsigned char, skoro tak zadeklarowano b? :)
  • #25 7691865
    avo3
    Poziom 11  
    boohoo napisał:
    Cytat:
    a najlepiej
    b=abs(a-value)/2.0
    tab by kompilator nie zrobił problemu przy kompilacji, przynajmniej mnie tak uczuli języka C :)

    Hm, a nie będzie wtedy wyrzucało ostrzeżenia o konwersji z double do unsigned char, skoro tak zadeklarowano b? :)

    Mogę tylko powiedzieć że program działa doskonale po przeróbce i zaprogramowaniu up. O to mi właśnie chodziło
  • #27 7995762
    icer_cmg
    Poziom 12  
    Jestem troszkę zielony jeśli chodzi o sprawy elektroniczne. Czy mógłby ktoś jednak wrzucić schemat?
REKLAMA