turntable ordentlich - Wokwi ESP32, STM32, Arduino Simulator
in echt dreht sich der motor nicht
Die üblichen Probleme sind: (1) unzureichende Stromversorgung, (2) unsachgemäße Verkabelung. Zeigen Sie eine Zeichnung Ihrer Anschlüsse und der Stromquelle.
habe es genauso gemacht wie in der anleitung und wegen der stromversorgung die volt sind genug wegen der ampere muss ich gucken aber als ich mehr ampere hatte wurde die motor steuerung dauernd gebruzelt
Haben Sie den Drehschalter zweimal gedrückt ("set", "run")?
Nein, das hast du nicht. Haben Sie das aktuelle Limit des A4988 festgelegt?
Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden.
Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.
mfg ein Moderator.
danke euch beiden
Hi @amelmar ,
bei dem von Dir verlinkten Sketch sind im Library Manager keine Libraries installiert ...
Das kann man natürlich nachpflegen, es wäre aber schön, wenn der Sketch gleich ohne Nacharbeit läuft.
Vielleicht hast Du nach dem Kopieren nur vergessen, die Seite nochmals zu speichern?
Hier eine Kopie, bei der die Bibliotheken eingebunden sind und im Kopftext Links auf die Forum- und die Wokwi-Seite vorhanden sind:
https://wokwi.com/projects/418715177026680833
Da nicht jeder den "Ausflug" auf die externe Seite machen möchte, sollte man den Code auch hier in Code-Tags posten ...
Wokwi-Sketch
/*
Forum:https://forum.arduino.cc/t/steppermotor-dreht-sich-nicht/1337240
Wokwi: https://wokwi.com/projects/418715177026680833
*/
#include <U8g2lib.h>
#include <RotaryEncoder.h>
#include <Button_SL.hpp>
using ulong = unsigned long int;
using uint = unsigned int;
//
// Gobal constants
//
constexpr byte PIN_IN1 {2};
constexpr byte PIN_IN2 {3};
constexpr byte PIN_BTN {4};
constexpr byte PIN_STEPPER {5};
constexpr byte VALUE_MIN {1}; // Counter minimum value
constexpr byte VALUE_MAX {4}; // Counter maximum value
constexpr byte DIGITS {1};
constexpr byte BUFFERLENGTH {DIGITS + 1};
constexpr uint COMPARTMENTS {8}; // The table should make a 360° turn in eight steps.
// constexpr ulong TIMEUNIT_MS {1000UL * 60 * 60}; // One hour in milliseconds
constexpr ulong TIMEUNIT_MS {1000UL * 60}; // Minutes for demonstration purposes
constexpr byte STEPS_PER_REVOLUTION {200}; // Number of steps for a 360° rotation
constexpr byte STEPS_PER_TIMEPERIOD {200 / COMPARTMENTS}; // Step segments
constexpr byte DISPLAY_MAX_X {128};
constexpr byte DISPLAY_MAX_Y {64};
// Font u8g2_font_logisoso42_tn // 24 Width 51 Hight
constexpr byte FONT_WIDTH {24};
constexpr byte FONT_HIGHT {51};
constexpr const char *STATUS_STRING[4] {"set", "running", "\0", "\0"}; // Note enum class status
constexpr byte STATUS_X {5}; // Statusstring coordinates
constexpr byte STATUS_Y {5};
constexpr byte TRGL_X {10}; // TRGL = Triangle coordinates
constexpr byte TRGL_Y {20};
constexpr byte TRGL_STEP_X {20};
constexpr byte TRGL_STEP_Y {15};
constexpr byte COUNTER_X {(DISPLAY_MAX_X - FONT_WIDTH * (BUFFERLENGTH - 1)) / 2}; // Column = X Coordinate
constexpr byte COUNTER_Y {(DISPLAY_MAX_Y + FONT_HIGHT) / 2}; // Row = Y coordinate
constexpr byte PIN_PWR {13};
//
// Data definitions
//
class Interval {
public:
bool operator()(const ulong duration) {
if (false == isStarted) {
return start(false);
}
return (millis() - timeStamp >= duration) ? start(true) : false;
}
void stop() {
isStarted = false;
}
private:
bool start(bool state = false) {
isStarted = !state; // Set the value to true on the first call
timeStamp = millis();
return state;
}
private:
bool isStarted {false}; // Flag = true if the first Operator() call has been made.
ulong timeStamp {0};
};
enum class Status : byte { set, running, start, calc };
//
// Extend the RotaryEncoder class with
// 1. a lower and upper limit for a counter
// 2. a variable step count
//
template <typename T> class RotaryEncoderExt : public RotaryEncoder {
public:
RotaryEncoderExt(uint8_t pin1, uint8_t pin2, T valMin, T valMax, LatchMode mode = LatchMode::FOUR0)
: RotaryEncoder {pin1, pin2, mode}, valMin {valMin}, valMax {valMax} {}
template <typename V> bool query(V &value);
void setStep(int value) {
step = value;
}
private:
const T valMin; // value minimum
const T valMax; // value maximum
int step {1};
};
template <typename T> template <typename V> bool RotaryEncoderExt<T>::query(V &value) {
uint8_t flag {true};
tick();
switch (getDirection()) {
case RotaryEncoder::Direction::NOROTATION: flag = false; break;
case RotaryEncoder::Direction::CLOCKWISE: value = value < valMax ? value + step : valMin; break;
case RotaryEncoder::Direction::COUNTERCLOCKWISE: value = value > valMin ? value - step : valMax; break;
}
return flag;
}
struct StepperData {
const byte pin; // Pin to which the stepper driver is connected
const uint stepsPerRev; // Number of steps for a 360° rotation
};
struct TurnTableData {
const StepperData stepper;
const byte compartments; // Number of table compartments
const ulong timeUnit; //
byte timeCounter; // Counter for a time unit (eg. counter * time)
ulong timePeriod; // Time between each table rotation
byte rotationCount; // Number of rotations performed
Status runningStatus; // Status e.g set time (hours) or running (drive stepper)
Interval wait; // Object for controlling the waiting cycles
};
//
// Global objects / variables
//
using DisplayType = U8G2_SSD1306_128X64_NONAME_2_HW_I2C;
DisplayType u8g2(U8G2_R0);
using namespace Btn;
ButtonSL button {PIN_BTN};
using Encoder = RotaryEncoderExt<decltype(VALUE_MIN)>;
Encoder encoder {PIN_IN1, PIN_IN2, VALUE_MIN, VALUE_MAX, RotaryEncoder::LatchMode::FOUR3};
//
// Function(s).
//
//////////////////////////////////////////////////////////////////////////////
/// @brief Display Data on the OLED
///
/// @param disp Display object
/// @param value Value to be displayed
/// @param status set or running
//////////////////////////////////////////////////////////////////////////////
void displayData(DisplayType &disp, byte value, Status status) {
char charBuffer[BUFFERLENGTH];
snprintf(charBuffer, BUFFERLENGTH, "%d", value);
disp.firstPage();
do {
disp.setFont(u8g2_font_6x10_tr);
if (status != Status::running) {
disp.drawStr(STATUS_X, STATUS_Y, STATUS_STRING[static_cast<byte>(Status::set)]);
disp.drawDisc(TRGL_X + TRGL_STEP_X / 2, TRGL_Y + TRGL_STEP_Y, TRGL_STEP_X / 2);
} else {
disp.drawStr(STATUS_X, STATUS_Y, STATUS_STRING[static_cast<byte>(Status::running)]);
disp.drawTriangle(TRGL_X, TRGL_Y, TRGL_X + TRGL_STEP_X, TRGL_Y + TRGL_STEP_Y, TRGL_X, TRGL_Y + TRGL_STEP_Y * 2);
}
disp.setFont(u8g2_font_logisoso42_tn); // 24 Width 51 Hight
disp.drawStr(COUNTER_X - 10, COUNTER_Y, charBuffer);
disp.setFont(u8g2_font_logisoso22_tr); // 27 Width 33 Hight
disp.drawStr(COUNTER_X + 20, COUNTER_Y, "hrs.");
} while (u8g2.nextPage());
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Rotate the stepper
///
/// @param pin Pin to which the motor is connected
/// @param steps Number of steps
//////////////////////////////////////////////////////////////////////////////
void spinMotor(byte pin, uint steps) {
for (byte x = 0; x < steps; ++x) {
digitalWrite(pin, HIGH);
delay(20);
digitalWrite(pin, LOW);
delay(20);
}
}
//////////////////////////////////////////////////////////////////////////////
/// @brief State machine
///
/// @param data Turntable data
/// @param disp Display object
/// @param enc Encoder object
/// @param btn Button for changing the status
//////////////////////////////////////////////////////////////////////////////
void fsm(TurnTableData &data, DisplayType &disp, Encoder &enc, ButtonSL &btn) {
switch (data.runningStatus) {
case Status::start:
data.runningStatus = Status::set;
displayData(disp, data.timeCounter, data.runningStatus);
break;
case Status::set:
if (enc.query(data.timeCounter)) {
displayData(disp, data.timeCounter, data.runningStatus);
}
break;
case Status::calc:
data.runningStatus = Status::running;
data.timePeriod = data.timeCounter * (data.timeUnit / data.compartments);
displayData(disp, data.timeCounter, data.runningStatus); // Display running status
break;
case Status::running:
if (data.wait(data.timePeriod)) {
spinMotor(data.stepper.pin, data.stepper.stepsPerRev / data.compartments);
++data.rotationCount;
}
// if periodcount = COMPARTMENTS stop running mode (rotation ends)
if (data.rotationCount == data.compartments) {
data.runningStatus = Status::set;
data.rotationCount = 0;
displayData(disp, data.timeCounter, data.runningStatus);
}
break;
default: break;
}
// Press button to change status between set and run
if (btn.tick() != ButtonState::notPressed) {
data.runningStatus = (data.runningStatus == Status::set) ? Status::calc : Status::set;
data.wait.stop(); // Reset timer
displayData(disp, data.timeCounter, data.runningStatus);
}
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Initialization part of the main program
///
//////////////////////////////////////////////////////////////////////////////
void setup(void) {
// Serial.begin(115200);
u8g2.begin();
pinMode(PIN_STEPPER, OUTPUT);
pinMode(PIN_PWR, OUTPUT);
digitalWrite(PIN_PWR, HIGH);
button.begin();
button.releaseOn();
button.setDebounceTime_ms(100);
}
//////////////////////////////////////////////////////////////////////////////
/// @brief main program
///
//////////////////////////////////////////////////////////////////////////////
void loop() {
// Stepper Pin, Steps per Rev, Compartment, Time Unit, start value, timeperiod , rotation count, status
static TurnTableData ttData {
{PIN_STEPPER, STEPS_PER_REVOLUTION},
COMPARTMENTS, TIMEUNIT_MS, VALUE_MIN, 0, 0, Status::start
};
fsm(ttData, u8g2, encoder, button);
}
In der Simulation bei Wokwi wird die externe Versorgung augenscheinlich nicht verwendet (der grün markierte Anschluss im Bild in der rechten, unteren Ecke des Treibers) und ist hier in Deinem Beispiel auch nicht angeschlossen!

In der Wokwi-Skizze ist Vcc mit dem Dir-Pin verbunden! Das bringt natürlich so gar nichts für die Spannungsversorgung! Je nach gewünschter Drehrichtung ist DIR auf logisch LOW oder HIGH zu setzen.
Auszug aus der Polulu-Dokumentation:
(Quelle: https://www.tme.eu/Document/25459777e672c305e474897eef284f74/POLOLU-2128.pdf)
Du solltest den Stepper erstmal mit einem einfachen Sketch zum Laufen bringen, dann wird's wahrscheinlich klappen!
Viel Erfolg!
ec2021
Also hast du jetzt noch einen Stepper-Treiber der nicht "gebrutzelt" ist?
Es gibt noch etwas weiteres zu beachten.
Schrittmotor Spannungsspitzen
Grundprinzip des Schrittmotors:
Spulen ständig ein/ausschalten nach einem bestimmten Muster.
Bei jedem Umschalten dreht er einen Schritt oder einen Mikroschritt weiter.
Bei einer Drehzahl von 1000 U/Min bedeutet das die Spannungen an den Spulen werden
ca 6000 mal pro Sekunde umgeschaltet.
Schrittmotoren haben Spulen.
Spulen haben eine Induktivität. Die Induktivität hat die Eigenschaft
bei Einschalten der Spannung den Strom erst einmal langsam ansteigen zu lassen.
Bei einem Schrittmotor möchte man jedoch sobald wie möglich den eingestellten Strom haben.
Damit durch die Spulen schon direkt nach dem Einschalten der eingestellte Strom fließt benutzt man möglichst hohe Spannungen.
Hohe Spannung = schneller Stromanstieg.
Bei hohen Spannungen würde aber die Spule durchbrennen wenn man den Strom zu lange anlegt.
Deshalb gibt es diesen Strom-Mess-Widerstand R-sense.
Damit wird der Strom gemesssen und die Spannung dann mit gaaanz hoher Frequenz ein/ausgeschaltet so dass sich im Mittel die passende Stromstärke einstellt.
Das ist das Stromtreiber-Prinzip. Hohe Spannung plus Strom begrenzen durch rechtzeitig abschalten.
Damit erreicht man mehr Drehmoment am Schrittmotor
gaaanz wichtig !
Die Kabel zu den Motorspulen nur bei abgeschalteter Stromversorgung anschließen / abklemmen.
Ebenfalls wegen der Induktivität entsteht beim Kontakt unterbrechen eine hohe Spannungsspitze. Diese Spannungsspitze würde den Schrittmotortreiber zerstören .
Auch beim Anschließen. Es ist sehr wahrscheinlich dass man beim Anschließen eben doch den Kontakt schließt und noch einmal für eine hunderstel Sekunde unterbricht und schon ZACK
Schrittmotortreiber kaputt.
Deshalb Motorkabel des Schrittmotors immer bei abgeschalteter Spannungsversorgung anschließen ( abklemmen
und
Für absolut wackelfreien Kontakt sorgen.
Wackelkontakt ZACK Schrittmotortreiber kaputt.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.


