ich habe einen Arduino Nano, der einen 28BYJ-48 Schrittmotor antreiben soll. Der Schrittmotor soll eine Sanduhr, die am Schrittmotor angebracht ist, zunächst auf die 0-Grad-Position ausrichten (Schritt 1). Dann nach 238 Sekunden eine 180-Grad-Drehung im Uhrzeigersinn machen, die 2 Sekunden dauert. Nach weiteren 238 Sekunden wieder eine 180-Grad-Drehung, die 2 Sekunden dauert. Und so immer weiter. Das Gehäuse und die verbaute Hardware ist fertig und der CODE steuert den Motor auch an, macht aber (noch nicht) das, was ich will :-(. Bilder zum Gehäuse habe ich eingefügt.
Der momentane Code:
#include <AccelStepper.h>
const byte Fullstep = 4;
const byte Halfstep = 8;
const short fullRevolution = 2038;
const float SteppDegree = 11.4; // Half/Full 11.32 / 5.66
const int ButtonPin = 7; //definert Pin 7 als Schaltereingang
// Pins IN1-IN3-IN2-IN4
AccelStepper stepper1(Halfstep, 11, 9, 10, 8); // definiert halb oder Vollstepschrittweite und ordnet den PINS IN1.. die Anschlüsse d.. am Arduino zu
void setup() {
stepper1.setMaxSpeed(2000); // set the maximum speed
stepper1.setSpeed(500); // set initial speed
stepper1.setAcceleration(1000); // set acceleration
stepper1.setCurrentPosition(0); // set position
// pinMode(ButtonPin, INPUT_PULLUP); //
Serial.begin(9600); //definert die Datenübertragung
}
void loop() { // äusserer Loop der: 1. Die den move loop aufruft und 2. die Stillstandszeit festlegt
int pressed = digitalRead(ButtonPin);
Serial.println(pressed);
delay(5000); // Pausenzeit in ms
//if(pressed==LOW){ //
move(); // ruft den loop "move" zum drehen auf
// }
}
void move(){
float degree = 180; // im Uhrzeigersinn
float moveRev = degree * SteppDegree; //hier wird die schrittzahl definiert
stepper1.setCurrentPosition(0); // vor jeder neuen Bewegung wird die aktuelle Stepperposition auf 0 gesetzt, andernfalls läuft der Steppzähler ins Nirwana
stepper1.move(moveRev); // - für Uhrzeigersinn
boolean isRunning = true; // definiert eine Boolean Variable (true, false,...) wenn der Stepper läuft
stepper1.enableOutputs(); // nach den Anzahl der definierten Schritte (moverev) wird der Stepper stromlos geschaltet. andernfalls bleibt eine Spule bestromt und verbatraucht unnöftig Energie
long pos = 0;
while(isRunning){ // Ausgabe der Stepperposition auf dem Serial printer alle 10 steps
long current_pos = stepper1.currentPosition();
if (current_pos - pos > 10) { // Verhinderzu häufige Ausgaben
pos = current_pos;
Serial.println(pos); // Schickt die pos ( das ist in diesem Fall die aktuelle Stepperposition) zu den Monitoren
}
isRunning = stepper1.run();
}
stepper1.disableOutputs(); // Stellt nach der Bewegung den Strom am Steppermotor ab
}
Das wird nichts, da die Position relativ ist und Du keinen definierten Start bzw. Endpunkt hast.
Du brauchst dazu z.B. einen Endschalter, den Du anfahren kannst um eine definierte Position zu erreichen.
#include <AccelStepper.h>
const byte Fullstep = 4;
const byte Halfstep = 8;
const uint16_t fullRevolution = 2038;
const uint16_t halfRevolution = fullRevolution / 2;
// const float SteppDegree = 11.4; // Half/Full 11.32 / 5.66
const uint8_t ButtonPin = 7; //definert Pin 7 als Schaltereingang
// Pins IN1-IN3-IN2-IN4
AccelStepper stepper1(Halfstep, 11, 9, 10, 8); // definiert halb oder Vollstepschrittweite und ordnet den PINS IN1.. die Anschlüsse d.. am Arduino zu
const uint32_t oneSecond = 1000UL;
const uint32_t fourMinute = oneSecond * 240UL;
uint32_t checkTime;
uint32_t myMillis;
void setup()
{
Serial.begin(9600); //definert die Datenübertragung
Serial.println(F("Start..."));
stepper1.setMaxSpeed(2000); // set the maximum speed
stepper1.setSpeed(500); // set initial speed
stepper1.setAcceleration(1000); // set acceleration
stepper1.setCurrentPosition(0); // set position
pinMode(ButtonPin, INPUT_PULLUP); //
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
myMillis = millis(); // lokale Zeit
if (checkButton()) // Taste gedrückt?
{ manualStep(); } // erklärt sich selbst :-)
automatikStep();
heartbeat(500);
}
bool checkButton()
{
bool isPressed = false;
static bool lastPressed = !isPressed;
if (!digitalRead(ButtonPin))
{ isPressed = true; }
if (isPressed != lastPressed)
{
Serial.println(isPressed);
lastPressed = isPressed;
}
return isPressed;
}
void manualStep()
{
bool fertig = false; // Merker Schleifenstatus
bool pressed = false; // Merker Tastendruck
const uint8_t oneStep = 1;
checkTime = millis(); // Setzt Starttime
stepper1.enableOutputs(); // Stepper aktivieren
stepper1.setCurrentPosition(0); // Startposition festlegen
while (fertig == false)
{
if (checkButton() == true) // Taste gedrückt
{
pressed = true;
stepper1.move(oneStep); // drehen
while (stepper1.run()) // Hier kann irgendwas rein....
{
debugPosition(500); // Ausgabe der Position
};
stepper1.setCurrentPosition(0);
}
else // Taste nicht gedrückt
{
if (pressed == true) // war gedrückt
{
checkTime = millis(); // Zeit merken
pressed = false; // Merker löschen -> Startzeit nur einmal setzen ;)
}
if (millis() - checkTime > 10000) // Zeit abgelaufen (und Taste losgelassen)
{ fertig = true; } // Ende Schleife setzen
}
}
stepper1.disableOutputs(); // Stepper abschalten
}
void automatikStep()
{
if (myMillis - checkTime >= fourMinute) // Pausenzeit abgelaufen
{
checkTime = myMillis; // Zeit merken
stepper1.enableOutputs(); // Stepper aktivieren
stepper1.setCurrentPosition(0); // Startposition setzen
stepper1.move(halfRevolution); // Drehbewegung starten
}
if (stepper1.run()) // Stepper läuft?
{ debugPosition(50); } // Position ausgeben (Taktzeit)
else if (myMillis - checkTime > oneSecond * 2) // Stepper stoppt und Laufzeit um?
{ stepper1.disableOutputs(); } // Stepper deaktivieren
}
void debugPosition(const uint32_t tikTime)
{
static uint32_t lastPrint = 0;
if (myMillis - lastPrint > tikTime)
{
Serial.print(F("Aktuelle Position: "));
Serial.println(stepper1.currentPosition());
Serial.flush();
lastPrint = myMillis;
}
}
void heartbeat(const uint32_t tik)
{
static uint32_t lastTik = 0;
if (millis() - lastTik > tik)
{
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
lastTik += tik;
}
}
Die Idee dahinter:
Du kannst jederzeit mit der Taste den Antrieb weiter stellen und damit in eine definierte Position bringen.
Lässt Du die Taste los, fängt Dein 4 Minutenzyklus (wieder) an.
/*
Forum:https://forum.arduino.cc/t/arduino-nano-code/1382277
Wokwi: https://wokwi.com/projects/431411551161475073
Simple State Machine
- MOVETOZERO: Move the stepper to zero position using the buttons
- WAITING: Wait for a given time in this position
- TURNING: Turn the stepper to position 180 degree or position 0 degree
- go on with WAITING if the respective target position has been reached
Buttons: Turn Left (yellow),
turn Right (white),
stop turning (black) or
accept position as Zero with Start (green)
Pressing Left or Right several times increases the turn rate
Pressing Stop resets the turn rate to minTurnRate again
Pressing Start sets the turn rate to maxTurnRate
Pressing Stop while in WAITING or TURNING state stops the stepper and changes state to MOVETOZERO again
ec2021
2025/05/19
*/
#include <MobaTools.h>
class buttonType {
private:
byte pin;
byte state = HIGH;
byte lastState = LOW;
unsigned long lastChange = 0;
public:
void init(byte aPin) {
pin = aPin;
pinMode(pin, INPUT_PULLUP);
};
boolean pressed() {
byte actState = digitalRead(pin);
if (actState != lastState) {
lastState = actState;
lastChange = millis();
}
if (state != actState && millis() - lastChange > 50) {
state = actState;
return !state;
}
return false;
};
};
constexpr byte btLeftPin {7};
constexpr byte btStopPin {6};
constexpr byte btRightPin {5};
constexpr byte btStartPin {4};
constexpr unsigned long totalSequenceTime {5000}; // 240 seconds => 240000;
constexpr long stepsPer360 {200};
constexpr int maxTurnSpeed {148};
constexpr int minTurnSpeed { 9};
MoToStepper myStepper(stepsPer360, FULLSTEP);
enum SandUhrStates {MOVETOZERO, WAITING, TURNING};
SandUhrStates state = MOVETOZERO;
long targetAngle = 0;
unsigned long startToWait = 0;
unsigned long startOfTurn = 0;
unsigned long lastTurnTime = 0;
unsigned long waitTimeCorrection = 0;
int actSpeed = 10;
buttonType btLeft, btRight, btStop, btStart;
void setup() {
myStepper.attach( 11, 9, 10, 8);
setSpeed(minTurnSpeed);
Serial.begin(115200);
btLeft.init(btLeftPin);
btRight.init(btRightPin);
btStop.init(btStopPin);
btStart.init(btStartPin);
Serial.println("Move to Zero");
state = MOVETOZERO;
}
void loop() {
sandUhr();
checkForButtons();
}
void sandUhr() {
switch (state) {
case MOVETOZERO:
if (btLeft.pressed()) {
myStepper.rotate(-1);
setSpeed(actSpeed + 1);
}
if (btRight.pressed()) {
myStepper.rotate(1);
setSpeed(actSpeed + 1);
}
if (btStop.pressed()) {
myStepper.stop();
setSpeed(minTurnSpeed);
}
if (btStart.pressed()) {
myStepper.stop();
myStepper.setZero();
setSpeed(maxTurnSpeed);
startToWait = millis();
lastTurnTime = 0;
state = WAITING;
targetAngle = 0;
Serial.println("Waiting ... ");
}
break;
case WAITING:
if (millis() - startToWait >= totalSequenceTime - lastTurnTime) {
targetAngle = (targetAngle == 0) ? 180 : 0;
myStepper.write(targetAngle);
startOfTurn = millis();
state = TURNING;
Serial.println("Turning");
}
break;
case TURNING:
if (myStepper.read() == targetAngle) {
startToWait = millis();
lastTurnTime = startToWait - startOfTurn;
state = WAITING;
Serial.print("Turn required ");
Serial.print(lastTurnTime);
Serial.println(" [ms]");
Serial.print("Waiting for ");
Serial.print(totalSequenceTime - lastTurnTime);
Serial.println(" [ms]");
}
break;
}
}
void checkForButtons() {
if (state != MOVETOZERO) {
if (btStop.pressed()) {
myStepper.stop();
setSpeed(minTurnSpeed);
Serial.println("Move to Zero");
state = MOVETOZERO;
}
}
}
void setSpeed(int speed) {
actSpeed = speed;
myStepper.setSpeed(actSpeed);
}
Die Parameter müssten noch für Deinen Stepper angepasst werden. Außerdem verwendet der Code vier Taster zum Einstellen der "Null-Position" nach dem Start des Sketches:
Gelb = Linkslauf
Weiß = Rechtslauf
Schwarz = Stopp
Green = Start der Motorsequenz
Mit Stopp kann die Motorsequenz jederzeit unterbrochen und das Justieren per Knopfdruck gestartet werden. Geschickter wäre natürlich ein Sensor (z.B. ein Mikroschalter, ein Magnetkontakt oder eine Lichtschranke), welche die Nullposition signalisiert. Geht aber auch so.
Mit jeder Betätigung der Links/Rechtslauf-Tasten erhöht sich die Drehzahl ein wenig. Die Stopp-Taste setzt den Wert auf minTurnRate zurück.
Geht sicher alles noch schöner und besser, aber vielleicht gibt Dir das ein paar Hilfestellungen für die Umsetzung.