• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
sterowanie silnikiem krokowym
#1
Zbudowałem układ sterowania silnikiem krokowym za pomocą Arduino Uno. Ogólnie wszystko działa, ale mam problem z zaprogramowaniem układu. Sterowanie ma wyglądać mniej więcej w ten sposób, że najpierw silnik obraca się z pełnym krokiem i zmienia kierunek obrotu, następnie zmienia się podział kroku na 1/2 np. na 3 s następnie na 1/4 3s, 1/8 3s, i 1/16 3s.

Problem wygląda tak, że jak napisałem prosty kod w oparciu o delay to nie mogę zmieniać częstotliwości obrotów silnika za pomocą potencjometru, dlatego próbowałem napisać program w oparciu o funkcję millis, jednak chyba nie rozumiem do końca tej funkcji gdyż nie potrafię zaprogramować układu tak, aby chodził jak w  oparciu o delay. W programie z funkcją millis podział kroku nie zmienia się tak jak w programie z delay. Będę bardzo wdzięczny jeśli ktoś pomorze mi to odpowiednio zaprogramować Smile



Kod:
#include <Stepper.h>

#define PIN_KROK 2 /* impuls sterujacy*/
#define PIN_ODCZYT A0 /* odczyt z potencjometru*/
#define MAX 800   /* max obroty */
#define PIN_KIERUNEK 1 /*zmiana kierunku DIR */
#define PIN_STOP 6 /* zatrzymanie */
#define PIN_MS 5 /* MS1 pół krok*/
#define PIN_MS 4  /* MS2 1/4 krok*/
#define PIN_MS 3   /* MS3 */


void setup() {

pinMode (PIN_KROK, OUTPUT);
pinMode (PIN_KIERUNEK, OUTPUT);
pinMode (PIN_MS, OUTPUT);
 }

void loop()
{
unsigned int potencjometr = map(analogRead(PIN_ODCZYT),0,1023,0,MAX);
tone (PIN_KROK, potencjometr);
digitalWrite(1,HIGH);
delay(1000);
digitalWrite(1,LOW);
delay(1000);
/*--------------------------------------------------------------------- */
 digitalWrite(5, HIGH); /* zmiana na pół krok*/
 delay(2000);
 digitalWrite(5, LOW);  /* powrót do 200 kroków*/
 
/*----------------------------------------------------*/
 digitalWrite(4, HIGH); /* zmiana na 1/4 kroku*/
 delay(2000);

/*----------------------------------------------------*/
 digitalWrite(5, HIGH); /* zmiana na 1/8 kroku*/
 delay(2000);
/*----------------------------------------------------*/
 digitalWrite(3, HIGH); /* zmiana na 1/16 kroku*/
 delay(2000);
/*----------------------------------------------------*/
 digitalWrite(3, LOW); /* powrót do 200 kroków */
 digitalWrite(4, LOW);
 digitalWrite(5, LOW);
 }


Niedziałający program z funkcją millis.
Kod:
#include <Stepper.h>
#include <AccelStepper.h>

#define PIN_KROK 2 /* impuls sterujacy*/
#define PIN_ODCZYT A0 /* odczyt z potencjometru*/
#define MAX 800   /* max obroty,  */
#define PIN_KIERUNEK 1 /*zmiana kierunku DIR */
#define PIN_STOP 6 /* zatrzymanie */
#define PIN_MS 5 /* MS1 pół krok*/
#define PIN_MS 4  /* MS2 1/4 krok*/
#define PIN_MS 3   /* MS3 */
#define RESET 7   /* reset pololu */

int potencjometr;

unsigned long aktualnyCzas ;
unsigned long zapamietanyCzas ;
unsigned long zapamietanyCzas1 ;
unsigned long zapamietanyCzas2 ;
unsigned long zapamietanyCzas3 ;
unsigned long zapamietanyCzas4 ;
unsigned long zapamietanyCzas5 ;


void setup() {
 
 pinMode (PIN_KROK, OUTPUT);
 pinMode (PIN_KIERUNEK, OUTPUT);
 pinMode (PIN_MS, OUTPUT);
}

void loop()
{
 potencjometr = map(analogRead(PIN_ODCZYT), 0, 1023, 0, MAX);
 tone (PIN_KROK, potencjometr);

 aktualnyCzas = millis();
 

if (aktualnyCzas - zapamietanyCzas >= 1000UL) {
    zapamietanyCzas = aktualnyCzas;
    digitalWrite(1, HIGH);
  }
if (aktualnyCzas - zapamietanyCzas1 >= 2000UL) {
    zapamietanyCzas1 = aktualnyCzas;
    digitalWrite(5, HIGH);
  }
if (aktualnyCzas - zapamietanyCzas2 >= 3000UL) {
    zapamietanyCzas2 = aktualnyCzas;
    digitalWrite(5, LOW);
    digitalWrite(4, HIGH);}

if (aktualnyCzas - zapamietanyCzas3 >= 4000UL) {
    zapamietanyCzas3 = aktualnyCzas;
    digitalWrite(5, HIGH);}

if (aktualnyCzas - zapamietanyCzas4 >= 5000UL) {
    zapamietanyCzas4 = aktualnyCzas;
    digitalWrite(3, HIGH); }

if (aktualnyCzas - zapamietanyCzas5 >= 6000UL) {
    zapamietanyCzas5 = aktualnyCzas;
    digitalWrite(5, LOW);
    digitalWrite(4, LOW);
    digitalWrite(3, LOW);}
}
 
Odpowiedź
#2
Poupraszczaj sobie, bo po paru linijkach się gubisz. Jak coś ma się wykonywać po sobie to lepiej korzystać z jednej zmiennej trzymającej informację o czasie, tu możesz mieć tak, że wiele zadziała równocześnie, bo minął im czas od poprzedniego zdarzenia i zaczną sobie wzajemnie wchodzić na głowę. Do samego wyboru trybu pracy napisz sobie funkcję: void ustawkrok(uint8_t krok); podajesz jako argument krok liczbę 1 -16, w środku funkcji używasz argumentu do wybrania w switch case jednego z 4 warunków - 2,4,8,16 i ostatni domyślny jak argument inny to ewentualnie pełny krok i ustawiasz w danym wariancie wszystkie piny. No i jeszcze musisz pamiętać, jaki tryb był poprzednio by tylko dodać jakiś pin? Jak nie rozumiesz idei funkcji to polecam kurs: https://www.youtube.com/watch?v=HHplT1A4...o&index=10 oczywiście od początku, w Arduino przyda się również druga część obiektowa. Proste instrukcje wykonają się szybciej niż funkcja wywołana w funkcji wywołana w funkcji itd. Ale musisz wybrać kompromis między tym co wytrzyma procesor, a tym co Twoja głowa.
Jak sobie pilnujesz czasu w programie to wszystkie zależne od siebie wątki trzymaj w jednej zmiennej, tu mogą to być po prostu upływające sekundy - w pierwszej robisz jedno, a drugiej kolejne, itd. Jak chcesz migać ledami asynchronicznie jedną co 33ms, druga co 1356ms to lepiej im mierzyć ms osobno i wtedy nie ma nic złego w tym, że czasem zamigają nawet w tej samej ms. U Ciebie to będzie bez sensu, jak sobie włączysz pełny krok i od razu 1/16kroku. Warunek if(sekundy%5==0) spełni się tylko wtedy gdy liczba sekund będzie podzielna przez 5 - jakbyś chciał robić coś co 5s, zmienną sterującą możesz modyfikować czasem i niezależnie przyciskiem/potencjometrem/danymi odebranymi i tu jest zaleta millis, że stanie się to od razu, jak masz 8 różnych trybów to wystarczy że zmienna sterująca zmienia się od 1-8, robisz taki warunek w kolejnej konstrukcji switch case. Chcesz coś co 3s if(sekundy%3==0) i możesz przestawić swoje kroki {(krok*=2); if (krok>16) krok=1;}.
Nawet jak coś robisz zupełnie asynchronicznie to nie wywołuj za często funkcji millis(), operuje na liczbach 32bity i trochę trwa jej wywołanie. Ja robię to raz i napędzam mniejsze zmienne, potem już ich używam. Można sobie ustalić najmniejszą rozdzielczość zdarzeń i tylko dla nich wywoływać millis(), a w oparciu o tą zmienną nakręcać swoje inne, małe, 8-bitowe,  wtedy również porównania trwają krócej. Do większości wystarcza mi 10ms, czas może się co prawda rozjechać jak pętla zgubi mi co jakiś czas ms, ale nie używam tego do zegarka. Istotne jest też by wiedzieć, że jak zmieniasz jakąś zmienną to stało się to właśnie teraz - flaga nowej sekundy, 100ms, minuty, godziny, tak by program nie wykonywał się miliony razy bo coś ustawiłeś na drugą godzinę. No i jako zmiennych do czasu używaj tylko tych bez znaku, tak by przekręcanie liczników nie zepsuło porównań (klątwa 50dni millis()). Kompilator lubi sobie uprościć i przypisać wyniki do int zamiast pozostawać w uint32_t (czy tam ulong), a wtedy się wszystko zatrzyma.

Kod:
uint32_t czasTeraz,czasPoprzedni,tik=10;
uint8_t n10,sekundy,minuty,godziny,dni;
bool fn10,fsekundy,fminuty,fgodziny,fdni;

void setup() {
 // put your setup code here, to run once:
Serial.begin(115200);
pinMode(LED_BUILTIN,OUTPUT);

}

void loop() {
 // put your main code here, to run repeatedly:
czas();


if(fsekundy&&sekundy%15==0)
{Serial.print(godziny);
Serial.print(":");
Serial.print(minuty);
Serial.println();

}

if(fsekundy) digitalWrite(LED_BUILTIN,! digitalRead(LED_BUILTIN));//gdy nowa sekunda wybila zmien stan led
}


void czas()
{
 czasTeraz=millis();
fn10=fsekundy=fminuty=fgodziny=fdni=0;
if((uint32_t)(czasTeraz-czasPoprzedni)>=tik)
{
 czasPoprzedni=czasTeraz;
 fn10=1;
 n10++;
 if(n10>=100)
 {
   n10=0;
   sekundy++;
   fsekundy=1;
    if (sekundy>=60)
   {
     sekundy=0;
     minuty++;
     fminuty=1;
     if (minuty>=60)
     {
       minuty=0;
       godziny++;
       fgodziny=1;
       if (godziny>=24)
       {
         godziny=0;
         fdni=1;
         dni++;
   
       }
     }
   }
 }
}
}

teraz możesz sobie trzymać poprzednie zdarzenie w liczbie s i użyć tej samej konstrukcji z poprzednie_sekundy, aktualne_sekundy/minuty/godziny/dni.
 
Odpowiedź
#3
Wielkie dzięki za odpowiedź. Jestem początkujący w programowaniu, ale mam nadzieję że dzięki Twoim wskazówką uda mi się ten układ zaprogramować Smile
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości