• 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
Problem z pracą silnika krokowego
#1
Witam
Mam prośbę. Czy mógłby ktoś zerknąć na poniższy kod i powiedzieć mi, dlaczego to nie chce działać poprawnie?
Po wgraniu kodu silnika wszystko działa jak należy, problem zaczyna się po dodaniu kodu wskaźnika.
Kręcąc potencjometrem wskaźnik działa lecz silnik obraca się z prędkością jakieś 2 kroki na minute.
Kod:
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0);
int xmax = 128;
int ymax = 62;
int xcenter = xmax / 2;
int ycenter = ymax / 2 + 10;
int arc = ymax / 2;
int angle = 0;
char* label[] = {"LOAD", "COOLANT", "INTAKE", "VOLT"};
int labelXpos[] = {53, 45, 49, 53};
#define potmeterPin A1
int p, w, m, a = 10;
u8g_uint_t xx = 0;

// Definiuje numery pinów sterownika
const int stepPin = 3 ;
const int dirPin = 4 ;

int customDelay, customDelayMapped; // Definiuje zmienne

void gauge(uint8_t angle) {
 // Narysuj granice wskaznika
 u8g.drawCircle(xcenter, ycenter, arc + 6, U8G_DRAW_UPPER_RIGHT);
 u8g.drawCircle(xcenter, ycenter, arc + 4, U8G_DRAW_UPPER_RIGHT);
 u8g.drawCircle(xcenter, ycenter, arc + 6, U8G_DRAW_UPPER_LEFT);
 u8g.drawCircle(xcenter, ycenter, arc + 4, U8G_DRAW_UPPER_LEFT);

 // Narysuj wskaznik igly, prosta linie na dole posrodku
 float x1 = sin(2 * angle * 2 * 3.14 / 360);
 float y1 = cos(2 * angle * 2 * 3.14 / 360);
 u8g.drawLine(xcenter, ycenter, xcenter + arc * x1, ycenter - arc * y1);
 u8g.drawDisc(xcenter, ycenter, 5, U8G_DRAW_UPPER_LEFT);
 u8g.drawDisc(xcenter, ycenter, 5, U8G_DRAW_UPPER_RIGHT);
 u8g.setFont(u8g_font_chikita);

 // Pokaz etykiety skali
 u8g.drawStr( 20, 42, "0");
 u8g.drawStr( 25, 18, "25");
 u8g.drawStr( 60, 14, "50");
 u8g.drawStr( 95, 18, "75");
 u8g.drawStr( 105, 42, "100");

 // Pokaz etykiete wskaznika
 u8g.setPrintPos(labelXpos[0], 32);
 u8g.print(label[0]);

 // Pokaz wartosc cyfrowa i wyrownaj jej pozycje
 u8g.setFont(u8g_font_profont22);
 u8g.setPrintPos(54, 60);
 if (w < 10) {
   u8g.print("0");
 }
 if (w > 99) {
   u8g.setPrintPos(47, 60);
 }
 u8g.print(w);
}
void setup(void) {
 // Ustawia dwa piny jako Wyjścia
 pinMode ( stepPin, OUTPUT ) ;
 pinMode ( dirPin, OUTPUT ) ;

 digitalWrite ( dirPin, HIGH ) ; // Umożliwia ruch silnika w określonym kierunku

 u8g.setFont(u8g_font_chikita);
 u8g.setColorIndex(1);
 // Przypisz domyslna wartosc koloru
 if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
   u8g.setColorIndex(255);
 }
 else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
   u8g.setColorIndex(3);
 }
 else if ( u8g.getMode() == U8G_MODE_BW ) {
   u8g.setColorIndex(1);
 }
 else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
   u8g.setHiColorByRGB(255, 255, 255);
 }
}
void loop(void) {
 customDelayMapped = speedUp ( ) ; // Pobiera niestandardowe wartości opóźnień z niestandardowej funkcji speedUp
 // Tworzy pule z niestandardowym opóźnieniem, w zależności od Potencjometru, od którego zależy prędkość silnika
 digitalWrite ( stepPin, HIGH ) ;
 delayMicroseconds ( customDelayMapped ) ;
 digitalWrite ( stepPin, LOW ) ;
 delayMicroseconds ( customDelayMapped ) ;

 p = analogRead(A0);
 w = map(p, 0, 1023, 0, 100);
 m = map(p, 0, 1023, 0, 90);
 // Pokaz igle i pokretlo
 xx = m;
 if (xx < 45) {
   xx = xx + 135;
 }
 else {
   xx = xx - 45;
 }
 // petla obrazu
 {
   u8g.firstPage();
   do {
     gauge(xx);
   }
   while ( u8g.nextPage() );
 }
}
// Funkcja odczytu Potencjometru
int speedUp ( ) {
 int customDelay = analogRead ( A0 ) ; // Odczytuje potencjometr
 int newCustom = map ( customDelay, 0 , 1023 , 300 , 4000 ) ; // Zwiększa odczyty wartości potencjometru od 0 do 1023 do żądanych wartości opóźnienia (od 300 do 4000)
 return newCustom;
}
 
Odpowiedź
#2
Witam.
Powodem jest programista. Nie napiszesz żadnego istotnego programu mając w palecie zarządzania czasem tylko delay(). Musisz pogrzebać najpierw w temacie millis() i micros(), potem przerwań. Do tego ustal, jak często mają się dziać rzeczy istotne (np. sterowanie silnikiem) i mniej istotne, np. odczyt analoga, wyświetlanie na ekranie. Poznając nowe funkcje będziesz mógł o tym decydować, ile czasu dajesz na poszczególne zadania. Załóżmy, że pusta pętla powinna się wykonać z pełną prędkością zegara, czyli 16mln razy na sekundę. Na prawdę musisz tak często znać położenie potencjometru? Oczywiście to trwa, dlatego już sam tylko ten odczyt spowolni pętlę do 15 tysięcy. A potem dodajesz jeszcze wysyłanie na ekran, w każdej pętli. Zwalniasz ją znowu tysiąc razy? No i mamy już tylko 15. A teraz dodajesz wisienkę - delay w pętli, w us, więc pewnie już bez znaczenia - taki kamyczek na wieko trumny. Przykład znajdziesz w Arduino, blinkwithoutdelay i wiele pod lupką na forum.
 
Odpowiedź
#3
Witam
Nie mam pojęcia o programowaniu.
Po prostu potrzebuję na gwałt uruchomić pompę perystaltyczną w której padła elektronika. Szukając sterownika do niej trafiłem na stronę z programem na arduino do sterowania silnikiem krokowym.
https://howtomechatronics.com/tutorials/...d-arduino/
A że w szufladzie leżała płytka arduino uno, kupiona kiedyś z myślą o nauce, poskładałem do kupy i hula.
Szukając opisu wyświetlacza oled SSD1306, przypadkiem wpadł mi w oko filmik ze strony:
https://steemit.com/utopian-io/@pakganer...er-arduino
Okazało się, że jest tam też kod. No to postanowiłem to połączyć (ale będzie bajer), no ale niestety, nie jest to takie proste jak mi się wydawało.
 
Odpowiedź
#4
No to zrób sobie tak, że raz na 100 lub 200 ms odczytaj analog, ewentualnie wyciągnij średnią co sekundę i pokaż na ekranie, a resztę czasu zostaw silnikowi, coś jak:

Kod:
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0);
int xmax = 128;
int ymax = 62;
int xcenter = xmax / 2;
int ycenter = ymax / 2 + 10;
int arc = ymax / 2;
int angle = 0;
char* label[] = {"LOAD", "COOLANT", "INTAKE", "VOLT"};
int labelXpos[] = {53, 45, 49, 53};
#define potmeterPin A1
int p, w, m, a = 10;
u8g_uint_t xx = 0;
uint32_t teraz,kiedys;
uint8_t ms100, sekundy;

// Definiuje numery pinów sterownika
const int stepPin = 3 ;
const int dirPin = 4 ;

int customDelay, customDelayMapped; // Definiuje zmienne

void gauge(uint8_t angle) {
// Narysuj granice wskaznika
u8g.drawCircle(xcenter, ycenter, arc + 6, U8G_DRAW_UPPER_RIGHT);
u8g.drawCircle(xcenter, ycenter, arc + 4, U8G_DRAW_UPPER_RIGHT);
u8g.drawCircle(xcenter, ycenter, arc + 6, U8G_DRAW_UPPER_LEFT);
u8g.drawCircle(xcenter, ycenter, arc + 4, U8G_DRAW_UPPER_LEFT);

// Narysuj wskaznik igly, prosta linie na dole posrodku
float x1 = sin(2 * angle * 2 * 3.14 / 360);
float y1 = cos(2 * angle * 2 * 3.14 / 360);
u8g.drawLine(xcenter, ycenter, xcenter + arc * x1, ycenter - arc * y1);
u8g.drawDisc(xcenter, ycenter, 5, U8G_DRAW_UPPER_LEFT);
u8g.drawDisc(xcenter, ycenter, 5, U8G_DRAW_UPPER_RIGHT);
u8g.setFont(u8g_font_chikita);

// Pokaz etykiety skali
u8g.drawStr( 20, 42, "0");
u8g.drawStr( 25, 18, "25");
u8g.drawStr( 60, 14, "50");
u8g.drawStr( 95, 18, "75");
u8g.drawStr( 105, 42, "100");

// Pokaz etykiete wskaznika
u8g.setPrintPos(labelXpos[0], 32);
u8g.print(label[0]);

// Pokaz wartosc cyfrowa i wyrownaj jej pozycje
u8g.setFont(u8g_font_profont22);
u8g.setPrintPos(54, 60);
if (w < 10) {
  u8g.print("0");
}
if (w > 99) {
  u8g.setPrintPos(47, 60);
}
u8g.print(w);
}
void setup(void) {
// Ustawia dwa piny jako Wyjścia
pinMode ( stepPin, OUTPUT ) ;
pinMode ( dirPin, OUTPUT ) ;

digitalWrite ( dirPin, HIGH ) ; // Umożliwia ruch silnika w określonym kierunku

u8g.setFont(u8g_font_chikita);
u8g.setColorIndex(1);
// Przypisz domyslna wartosc koloru
if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
  u8g.setColorIndex(255);
}
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
  u8g.setColorIndex(3);
}
else if ( u8g.getMode() == U8G_MODE_BW ) {
  u8g.setColorIndex(1);
}
else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
  u8g.setHiColorByRGB(255, 255, 255);
}
}
void loop(void) {
teraz=millis();

customDelayMapped = speedUp ( ) ; // Pobiera niestandardowe wartości opóźnień z niestandardowej funkcji speedUp
// Tworzy pule z niestandardowym opóźnieniem, w zależności od Potencjometru, od którego zależy prędkość silnika
digitalWrite ( stepPin, HIGH ) ;
delayMicroseconds ( customDelayMapped ) ;
digitalWrite ( stepPin, LOW ) ;
delayMicroseconds ( customDelayMapped ) ;

if(teraz - kiedys>100UL) //minelo 100ms
{
kiedys=teraz;
ms100++;
if (ms100>=10) ms100=0;
}

if (ms100%2==0) //gdy reszta z dzielenia jest 0, co 200ms
{
p = analogRead(A0);
w = map(p, 0, 1023, 0, 100);
m = map(p, 0, 1023, 0, 90);
// Pokaz igle i pokretlo
xx = m;
if (xx < 45) {
  xx = xx + 135;
}
else {
  xx = xx - 45;
}
}
// petla obrazu
if (ms100==0) //gdy minela sekunda
{
  u8g.firstPage();
  do {
    gauge(xx);
  }
  while ( u8g.nextPage() );
}
}
// Funkcja odczytu Potencjometru
int speedUp ( ) {
int customDelay = analogRead ( A0 ) ; // Odczytuje potencjometr
int newCustom = map ( customDelay, 0 , 1023 , 300 , 4000 ) ; // Zwiększa odczyty wartości potencjometru od 0 do 1023 do żądanych wartości opóźnienia (od 300 do 4000)
return newCustom;
}


Obliczenia trygonometryczne na Arduino są możliwe, ale raz że to zajmuje flash, dwa czas procka. Na przykładach wszystko fajnie wygląda, ale jak już masz połączyć kilka w jeden to trzeba je poukładać, żeby się nie gryzły i wzajemnie nie zakłócały. Są też biblioteki do tego, z tym że trzeba je poznać co najmniej tak dobrze jak przykłady z millis i micros().
A w między czasie sobie uzupełnij wiedzę: https://forbot.pl/blog/kurs-arduino-srod...owac-id936 . Takich kursów jest mnóstwo.
 
Odpowiedź
#5
Dziękuję bardzo za pomoc.
Wszystko hula jak ta lala, może z małym ale (silnik pracuje z przerwami), ale myślę że z tym sobie poradzę.
Co do uzupełniania wiedzy, to o ile można uzupełnić coś czego nie ma, to na pewno będę zgłębiał temat.
Dla mnie w tej chwili było najważniejsze uruchomić pompę, a teraz będę mógł spokojnie zabrać się za naukę.
Jeszcze raz dziękuję.
 
Odpowiedź
#6
Przerwy zapewne robi ten moment z wyświetlaczem, zakomentuj i sobie potwierdź. Jak się wgryziesz i ramu starczy to zainstaluj bibliotekę od Adafruit, buforuje cały ekran i wysłanie trwa 20ms. Tutaj jest tyle poleceń wypisujących na ekran, że nawet nie chce mi się szacować.
Możesz sobie sprawdzić ile trwa coś tam w analogiczny sposób do millis():
Kod:
start=micros();
costam();
stop=micros();
iletrwalo=stop-start;
Serial.println(iletrwalo);
Zmienne mają być tak jak w millis() typu  unsigned long lub uint32_t.
Generalnie wypisanie fragmentu ekranu jest szybsze, ale trzeba widzieć jak jest podzielony i jak odświeżyć wybrany fragment. Ten akurat ma 8 wierszy, można też odświeżyć wybrany zakres po osi X w danym wierszu, ale przy takim zegarze jak w cyrku to sorry. Odświeżanie całego ekranu takimi fragmentami na pewno nie jest szybsze. Jak zależy Ci na szybkości to zamień sobie na pasek postępu na górze, w drugim wierszu stała skala, na kolejnym tylko wartości.
Obejrzyj sobie gifa: http://forum.arduinopolska.pl/watek-ardu...light=oled , jest też cały kod. Sprawdź też czy masz ustawiony I2C na 100kHz, może pracować na 400 znacznie szybciej. Ale to zabawa po zapoznaniu się z elementarzem. 
Powodzenia
 
Odpowiedź
#7
Sterowanie silnikiem MUSI być zrobione w przerwaniach. Prawdopodobnie wystarczy to co udostępnia biblioteka timer. Można też użyć PWM. Używając PWM AVR może sterować nawet silnikami BLDC. Przykład sterowania silnikiem, którego użyłeś jest przykładem jak NIE NALEŻY pisać programów.
- uC: ARM Angel , AVR, Z8, PIC, 8051 / CPU: MC680x0, MC683xx, Z-80, 6502
- CPLD, FPGA, GAL
- GSM, ISDN, ETH, USB, RS232C/485/422
- C, ASM, CUPL, PHP

http://er-mik.prv.pl/projekty_avt.php * http://er-mik.prv.pl/ * http://kolejki.prv.pl/

KA-NUCLEO-F411CE Idea , ESP32, Mega2560, UNO PLUS
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości