How to get red led to come on with button push

Hello Everyone
I have built a rotary car dumper for my HO scale railroad layout.
I have the sketch below operating almost the way I want it to but.
1- I would like for the red led to come on solid after the first button push.
2- Once the rotary makes it to the dumped position the red led goes to flashing, which is functioning correctly.
3- Then when the second button push is made, I would like for the red led go to solid again while the rotary is moving.
4- Then when the rotary is back to the start positon the red led goes off.
5- Then the green light comes on to signal car is empty and ready for a new one to be pushed in, this part is functioning correctly.

As the code is written now with the first button push the green led goes off, which is correct.
when the rotary makes it to the dumping point the red led starts flashing. which is correct
when the rotary makes it back to the start point the green light back comes on. which is correct.
I have inserted digitalWrites(ledPin1, High); at various points in the sketch but have had no success making it function like I want
it to.
any help would be appreciated Thanks James

// constants won't change. Used here to set a pin number:
const int ledPin1 =  3;// the number of LED1 which is thye red led
const int ledPin2 =  4;// the number of LED2 which is the green led

// Variables will change:
int led1State = LOW;             // ledState used to set LED1

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change:
const long interval = 500;           // interval at which to blink (milliseconds)

/*Example sketch to control a stepper motor with A4988 stepper motor driver and Arduino with the Accelstepper library the original sketch did not use a library. More info: https://www.makerguides.com */

/* I modified the sketch from makerguides to run a nema 17 steppermotor with an A4988 driver and a 28BYJ-48 steppermotor with a ULN2003a driver board to run in a sequence with a button push then return to its start position with the second button push*/

/*-----( Import needed libraries )-----*/
#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

#include <AccelStepper.h>

// Define stepper motor connections :
#define dirPin 5
#define stepPin 6

// Define step constant  use a value of 4 for full step use a value of 8 for halfsteps for the unl2003a driver board
//#define FULLSTEP 4
#define HALFSTEP 8

// Creates an instance for stepper 1
// Pins entered in sequence IN1-IN3-IN2-IN4 for proper step sequence
AccelStepper stepper1(HALFSTEP, 8, 10, 9, 11);

// creates an instance for stepper 0
AccelStepper stepper0(1, stepPin, dirPin);

#define buttonPin 7  // defines the push button pin;

//Define variables
//variable that stores the state of the button:
int buttonReading;
//State of the blinds, low is closed, high is open:
int state = LOW;
int previous = LOW;

/*-----( Declare Constants )-----*/
// LCD geometry
const int LCD_COLS = 20;
const int LCD_ROWS = 4;


/*-----( Declare objects )-----*/
hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip
/*-----( Declare Variables )-----*/
int status;


void setup() {
  Serial .begin(9600);

  // set the digital pin as output:
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  digitalWrite(ledPin2, HIGH);
  lcd.begin(20, 4);        // initialize the lcd for 20 chars 4 lines, turn on backlight

  // ------- Quick 3 blinks of backlight  -------------
  for (int i = 0; i < 3; i++)
  {
    lcd.backlight();
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
  lcd.backlight(); // finish with backlight on

  //-------- Write characters on the display ------------------
  // NOTE: Cursor Position: Lines and Characters start at 0

  lcd.setCursor(0, 0); //Start at character 4 on line 0
  lcd.print("Hi Model RailRoaders");
  delay(500);
  lcd.setCursor(0, 1);
  lcd.print("From The I&J RR");
  delay(500);
  lcd.setCursor(0, 2);
  lcd.print("Rotary Dump Ready");
  lcd.setCursor(0, 3);
  delay(500);
  lcd.print("Push Button to Dump");


  pinMode (buttonPin, INPUT_PULLUP);

  // set the maximum speed, acceleration factor, initial speed and the start position for stepper 1
  stepper1.setMaxSpeed(1000.0);
  stepper1.setAcceleration(50.0);
  stepper1.setCurrentPosition(0);

  // set the maximum speed, acceleration factor, initial speed and the start position for stepper 0
  stepper0.setMaxSpeed(600);
  stepper0.setAcceleration(50.0);
  stepper0.setCurrentPosition(0);
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (led1State == LOW) {
      led1State = HIGH;
    } else {
      led1State = LOW;
    }


  }
  
  buttonReading = digitalRead(buttonPin);

  if (buttonReading == LOW && previous == HIGH) {
    if (state == LOW) {
      state = HIGH;
    }
    else {
      state = LOW;
    }
  }

  previous = buttonReading;

  if (state == HIGH) {
     // set LED1 with the ledState of the variable:
    digitalWrite(ledPin1  , led1State);
    digitalWrite(ledPin2 , LOW);
    while (stepper1.currentPosition() != 2000) // adjust this number for the go to position;
    {
      stepper1.setSpeed(600);
      stepper1.runSpeed();
    }

    // Serial.println("clamping car");

    lcd.setCursor(0, 0); //Start at character 4 on line 0
    lcd.print("Hi Model RailRoaders");
    lcd.setCursor(0, 1);
    lcd.print("From The I&J RR");
    lcd.setCursor(0, 2);
    lcd.print("Rotary Dump Running");
    lcd.setCursor(0, 3); //Start at character 4 on line 0
    lcd.print("Dumping Car           ");
    // delay(2000);

  }

  if (state == HIGH) {
    while (stepper0.currentPosition() != 6000) // adjust this number for the go to position;
    {
      stepper0.setSpeed(600);
      stepper0.runSpeed();
    }
    //Serial.println("rotating car");
   

  }
  if (state == LOW) {
    
    while (stepper0.currentPosition() != 0)
    {
      stepper0.setSpeed(-600);
      stepper0.runSpeed();
    }
    //Serial.println("rotating car back");
  }
  if (state == LOW) {
    while (stepper1.currentPosition() != 0)
    {
      stepper1.setSpeed(-600);
      stepper1.runSpeed();
    }
    //Serial.println("Ready for loaded car");
   
    lcd.setCursor(0, 0); //Start at character 4 on line 0
    lcd.print("Hi Model Railroaders");
    lcd.setCursor(0, 1);
    lcd.print("From The I&J RR");
    lcd.setCursor(0, 2);
    lcd.print("Rotary Dump Ready  ");
    lcd.setCursor(0, 3); //Start at character 4 on line 0
    lcd.print("Push Button To Dump");
    // delay(2000);

    digitalWrite(ledPin1 , LOW);
    digitalWrite(ledPin2 , HIGH);

  }
}

Hello Model RailRoader
The sketch makes a new led1State but this state will be written to the Led pin if the button is pressed only.
p.s. Do you have mounted the LED correctly?

I think that what you're actually need is a finite state machine. You have a few states in your application

  1. Wait for a button push to start the process
  2. Turn to the dump position
  3. Wait for a button push to go back
  4. Turn to initial (home) position
enum ROTATYSTATE
{
    WAIT_START,     // wait for button to be pressed
    MOVE_TO_DUMP,   // move the rotary to dump position
    WAIT_RETURN,    // wait for button to be pressed again
    MOVE_TO_HOME,   // move rotary to home position
};

ROTARYSTATE currentState = WAIT_START;

The above creates a 'type' ROTARYSTATE with 4 possible values and next defines a variable to hold the state.

The basics in loop() can now be

void loop()
{
  switch (currentState)
  {
    case WAIT_START:
      // green led on, red led off
      // ..
      // wait for button to be pressed
      if (button_changed_from_high_to_low)
      {
        // go to next state
        currentstate = MOVE_TO_DUMP;
      }
      break;
    case MOVE_TO_DUMP:
      // red led on, green led off
      // ...
      // move the stepper till dump position is reached
      // ..
      // once completed, go to next state
      if (moveIsComplete)
      {
        // go to next state
        currentState = WAIT_RETURN;
      }
      break;
    case WAIT_RETURN:
      // red led flashing; use a millis() based function for this
      // ..
      // wait for button to be pressed
      if (button_changed_from_high_to_low)
      {
        currentstate = MOVE_TO_HOME;
      }
      break;
    case MOVE_TO_HOME:
      // led to red
      // ...
      // move the stepper
      // ..
      // once completed, go to next state
      if (moveIsComplete)
      {
        currentState = WAIT_START;
      }
      break;
  }
}

This is basically to give you the idea. I'm not familiar with the AccelStepper library and I don't know how the end of a move is detected in your code, hence if (moveIsComplete). It might be while (stepper0.currentPosition() != 6000).
I haven't implemented the state change detection, just a simple place holder if (button_changed_from_high_to_low).

1 Like

consider (simulated your stepper functions)

enum { Off = HIGH, On = LOW };

const byte buttonPin = A1;
const byte redLedPin = 10;
const byte grnLedPin = 11;

const int   FlashPeriod = 500;
const int   Speed       = 600;
const int   Position0   = 0;
const int   Position1   = 6000;

struct Stepper_s {
    int position = 0;
    int speed;

    int  currentPosition (void) { return position; };
    void setSpeed (int spd)     { speed = spd; };
    void runSpeed (void)        { position += speed; delay (500); };
} stepper0;

// -----------------------------------------------------------------------------
byte butState;

int
buttonPress (void)
{
    byte but = digitalRead (buttonPin);
    if (butState != but)  {
        butState = but;

        return (LOW == but);
    }
    return 0;
}

// -----------------------------------------------------------------------------
void
rotate (
    int  position,
    int  speed )
{
#if 0
    delay (3000);
#else
    stepper0.setSpeed (speed);
    while (stepper0.currentPosition () != position)
    {
        stepper0.runSpeed();
    }
#endif
}

// -----------------------------------------------------------------------------
unsigned long msecLst;

enum { Idle, Dump, Dumped, Return };
int state = Idle;

void loop() {
    unsigned long msec = millis ();

    switch (state)  {
    case Idle:
        digitalWrite (redLedPin, Off);
        digitalWrite (grnLedPin, On);

        if (buttonPress ())
            state = Dump;
        break;

    case Dump:
        Serial.println ("Dump");
        digitalWrite (redLedPin, On);
        digitalWrite (grnLedPin, Off);

        rotate (Position1, Speed);
        state = Dumped;
        Serial.println ("Dumped");
        break;

    case Dumped:
        if ( (msec - msecLst) > FlashPeriod)  {
            msecLst = msec;
            digitalWrite (redLedPin, ! digitalRead (redLedPin));
        }

        if (buttonPress ())
            state = Return;
        break;

    case Return:
        Serial.println ("Return");
        digitalWrite (redLedPin, On);
        rotate (Position0, -Speed);

        digitalWrite (redLedPin, Off);
        digitalWrite (grnLedPin, On);

        state = Idle;
        Serial.println ("Idle");
        break;
    }
}

// -----------------------------------------------------------------------------
void setup() {
    Serial.begin (9600);

    digitalWrite (grnLedPin, On);
    pinMode      (grnLedPin, OUTPUT);

    digitalWrite (redLedPin, Off);
    pinMode      (redLedPin, OUTPUT);

    pinMode      (buttonPin, INPUT_PULLUP);
    butState = digitalRead (buttonPin);
}

Thank You guys for the suggestions as you can see from my sketch I have no programming knowledge. I have read the tutorials here and just cant grasp the skills but with your suggestions I will figure out how to get things working the way I want. THANKS AGAIN!!!! James

here's another version that suggests using a common lcd display function.

it's helpful to use sub-functions to avoid redundant code and to make the code easier to read and less confusing

enum { Off = HIGH, On = LOW };

const byte buttonPin = A1;
const byte redLedPin = 10;
const byte grnLedPin = 11;

const int   FlashPeriod = 500;
const int   Speed       = 600;
const int   Position0   = 0;
const int   Position1   = 6000;

struct Stepper_s {
    int position = 0;
    int speed;

    int  currentPosition (void) { return position; };
    void setSpeed (int spd)     { speed = spd; };
    void runSpeed (void)        { position += speed; delay (500); };
} stepper0;

// -----------------------------------------------------------------------------
byte butState;

int
buttonPress (void)
{
    byte but = digitalRead (buttonPin);
    if (butState != but)  {
        butState = but;

        return (LOW == but);
    }
    return 0;
}

// -----------------------------------------------------------------------------
void
display (
    const char *s0,
    const char *s1,
    const char *s2,
    const char *s3 )
{
#if 0
    lcd.setCursor(0, 0);
    lcd.print(s0);
    lcd.setCursor(0, 1);
    lcd.print(s1);
    lcd.setCursor(0, 2);
    lcd.print(s2);
    lcd.setCursor(0, 3);
    lcd.print(s3);
#else
    Serial.println (s0);
    Serial.println (s1);
    Serial.println (s2);
    Serial.println (s3);
    Serial.println ();
#endif

}

// -----------------------------------------------------------------------------
void
rotate (
    int  position,
    int  speed )
{
#if 0
    delay (3000);
#else
    stepper0.setSpeed (speed);
    while (stepper0.currentPosition () != position)
    {
        stepper0.runSpeed();
    }
#endif
}

// -----------------------------------------------------------------------------
unsigned long msecLst;

enum { Start, Idle, Dump, Dumped, Return };
int state = Start;

void loop() {
    unsigned long msec = millis ();

    switch (state)  {
    case Start:
        display (   "Hi Model Railroaders", "From The I&J RR",
                    "Rotary Dump Ready",    "Push Button To Dump");
        state = Idle;
        break;

    case Idle:
        digitalWrite (redLedPin, Off);
        digitalWrite (grnLedPin, On);

        if (buttonPress ())
            state = Dump;
        break;

    case Dump:
        digitalWrite (redLedPin, On);
        digitalWrite (grnLedPin, Off);

        display (   "Hi Model Railroaders", "From The I&J RR",
                    "Rotary Dump Running",  "Dumping Car");

        rotate (Position1, Speed);

        display (   "Hi Model Railroaders", "From The I&J RR",
                    "Dump Complete",        NULL);

        state = Dumped;
        break;

    case Dumped:
        if ( (msec - msecLst) > FlashPeriod)  {
            msecLst = msec;
            digitalWrite (redLedPin, ! digitalRead (redLedPin));
        }

        if (buttonPress ())
            state = Return;
        break;

    case Return:
        digitalWrite (redLedPin, On);

        display (   "Hi Model Railroaders", "From The I&J RR",
                    "Rotary Dump Running",  "Reversing Car");

        rotate (Position0, -Speed);

        digitalWrite (redLedPin, Off);
        digitalWrite (grnLedPin, On);

        state = Start;
        break;
    }
}

// -----------------------------------------------------------------------------
void setup() {
    Serial.begin (9600);

    digitalWrite (grnLedPin, On);
    pinMode      (grnLedPin, OUTPUT);

    digitalWrite (redLedPin, Off);
    pinMode      (redLedPin, OUTPUT);

    pinMode      (buttonPin, INPUT_PULLUP);
    butState = digitalRead (buttonPin);
}