[SOLVED]Kind of while loop for enable system

I will try and explain this the best I can.

I have a working program where I use an hall effect type joystick which basically has an potentiometer which just give 0-5V(speed) output and a 2 switches which control backwards and forwards and send the data out over an NRF24L01. I've added a kind of fail safe on power up so if the joystick is active it does not do anything.

Now I want to add another button so when you press it you have 5 seconds to active the forward or backwards motion, But while the joystick is active the loop does not time out if not used in 5 seconds.

Which would be the best approach for this ?

This is the code where I would like to place somesort of while loop to send out the data whithin the 5 seconds but still keep sending it out while the switches are on but end the while loop once switch is deactivated.

  //############ drvie backwards/lift down  function######################
  if (REV_DN_DAT_DAT == LOW) {
    data.DRV_BCK  = 4;
    lcd.setCursor(0, 1);
    lcd.print("BACKWARD");
  }
  else {
    data.DRV_BCK  = 0;
    lcd.setCursor(0, 1);
    lcd.print("        ");
  }
  //############ Steer left function######################
  if (sl_dat  == LOW) {
    data.Steer_left = 5;

  }
  else {
    data.Steer_left  = 0;

  }
  //############ steer right function######################
  if (sr_dat == LOW) {
    data.Steer_right = 6;
  }
  else {
    data.Steer_right = 0;
    lcd.setCursor(0, 1);
    lcd.print("        ");
  }

Just need some pointers and advice, Thanks

This is the full code of my program

#include <Wire.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
#define FWD_UP  3 //forward signal from joystick
#define REV_DN 4 //reverse signal from joystick
#define SL_input 5 //steer left input
#define SR_input 6 //sterr right input
#define Lift_input 7 //left select drive default
#define E_stopin 8
#define Error_led A3
boolean FWD_UP_DAT = 0; //set the forward signal to 0
boolean REV_DN_DAT_DAT = 0;//set backwards siganl to 0
boolean sl_dat = 0; //set steer left signal to 0
boolean sr_dat = 0; //set sterr right to 0
boolean lift_dat = 0; //set lift to 0
byte E_stopped = 0;
const uint64_t pipeOut = 0xE8E8F0F0E1LL; //IMPORTANT: The same as in the receiver
float input_voltage = 0.0;
RF24 radio(9, 10); // select  CSN  pin
// 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 = 250;
// The sizeof this struct should not exceed 32 bytes
// This gives us up to 32 8 bits channals
struct MyData {
  byte E_stop; //throttle signal
  int throttle; //throttle signal
  byte Steer_left;//sterr left
  byte Steer_right; //Steer right signal
  byte DRV_FWD; //drive forwards
  byte DRV_BCK; //drive backwards
  byte Lift; //left signal
};

MyData data;

void resetData()
{
  //This are the start values of each channal
  // Throttle is 0 in order to stop the motors
  data.E_stop = 0;
  data.throttle = 0;
  data.Steer_left = 0; //Steer left signal
  data.Steer_right = 0;
  data.DRV_FWD = 0;
  data.DRV_BCK = 0;
  data.Lift = 0;
}

void setup()
{
  Serial.begin(115200);
  lcd.begin(16, 2);
  pinMode(Error_led, OUTPUT);
  digitalWrite(Error_led, LOW);
  pinMode(E_stopin, INPUT_PULLUP);
  pinMode(FWD_UP, INPUT_PULLUP);
  pinMode( REV_DN, INPUT_PULLUP);
  pinMode(SL_input, INPUT_PULLUP);
  pinMode(SR_input, INPUT_PULLUP);
  pinMode(Lift_input, INPUT_PULLUP);
  //########################################################################################################################################
  // Detect if any of the buttons are active on power up,Failsafe and do nothing until the fault is rectifed                               #
  //########################################################################################################################################
  while ((digitalRead(FWD_UP) == LOW) || (digitalRead( REV_DN) == LOW) || (digitalRead(SR_input) == LOW) || (digitalRead(SL_input) == LOW)) {
    Error();
  }
  radio.begin();
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.openWritingPipe(pipeOut);
  resetData();
  lcd.clear();
  digitalWrite(Error_led, LOW);
}


void loop()
{
  E_stopped  = digitalRead(E_stopin); //Steer left signal
  sl_dat  = digitalRead(SL_input); //Steer left signal
  sr_dat  = digitalRead(SR_input); //Steer right signal
  FWD_UP_DAT     = digitalRead(FWD_UP); //Drive forward signal
  REV_DN_DAT_DAT    = digitalRead( REV_DN); //Drive Reverse signal
  lift_dat = digitalRead(Lift_input); //Select lift drive default
  //############ E-Stop function######################
  if ( E_stopped  == LOW) {
    data.E_stop = 1;
  }
  else {
    data.E_stop = 0;
  }
  //############ lift/drive function######################
  if (lift_dat  == LOW) {
    data.Lift = 2;
    lcd.setCursor(5, 0);
    lcd.print("LIFT MODE");
  }
  else {
    data.Lift  = 0;
    lcd.setCursor(5, 0);
    lcd.print("DRIVE MODE ");
  }

  //############ drvie forwards/lift up function######################
  if (FWD_UP_DAT == LOW) {
    data.DRV_FWD = 3;
    lcd.setCursor(0, 1);
    lcd.print("FORWARD");
  }
  else {
    data.DRV_FWD = 0;
    lcd.setCursor(0, 1);
    lcd.print("        ");
  }
  //############ drvie backwards/lift down  function######################
  if (REV_DN_DAT_DAT == LOW) {
    data.DRV_BCK  = 4;
    lcd.setCursor(0, 1);
    lcd.print("BACKWARD");
  }
  else {
    data.DRV_BCK  = 0;
    lcd.setCursor(0, 1);
    lcd.print("        ");
  }
  //############ Steer left function######################
  if (sl_dat  == LOW) {
    data.Steer_left = 5;

  }
  else {
    data.Steer_left  = 0;

  }
  //############ steer right function######################
  if (sr_dat == LOW) {
    data.Steer_right = 6;
  }
  else {
    data.Steer_right = 0;
    lcd.setCursor(0, 1);
    lcd.print("        ");
  }
  //############ Display data on the LCD debugging ###########
  lcd.setCursor(0, 0);
  lcd.print(data.throttle);
  lcd.print("  ");
  data.throttle = mapJoystickValues( analogRead(A0), 0, 507, 1023, true );
  input_voltage = (data.throttle * 5.0) / 1024.0;
  lcd.setCursor(8, 1);
  lcd.print(input_voltage);
  lcd.print(" V  ");
  //############ Send data out to RX module ##################
  radio.write(&data, sizeof(MyData));
}

/// Returns a corrected value for a joystick position that takes into account
// the values of the outer extents and the middle of the joystick range.
int mapJoystickValues(int val, int lower, int middle, int upper, bool reverse)
{
  val = constrain(val, lower, upper);
  if ( val < middle )
    val = map(val, lower, middle, 0, 1023);
  else
    val = map(val, middle, upper, 1023, 0);
  return ( reverse ? 1023 - val : val );
}
void Error() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    digitalWrite(Error_led, !digitalRead(Error_led));
  }
}

Steveiboy:
I will try and explain this the best I can.

I have a working program where I use an hall effect type joystick which basically has an potentiometer which just give 0-5V(speed) output and a 2 switches which control backwards and forwards and send the data out over an NRF24L01. I've added a kind of fail safe on power up so if the joystick is active it does not do anything.

Now I want to add another button so when you press it you have 5 seconds to active the forward or backwards motion, But while the joystick is active the loop does not time out if not used in 5 seconds.

Which would be the best approach for this ?

I think the first thing to do (for your own benefit as well as for us) is to write down in English (not code) the sequence of events you want to happen with one event or decision point on each line.

I suspect if you do that carefully you will see how to write the program. But, if you still need help post your list of events.

...R

Thanks Robin2,
My list of events are also another kind of failsafe just in case the joystick is knocked accidentally and to prevent movement if the enable button is not pressed.

  1. No Enable button pressed :-data.Steer_left, data.Steer_right, data.DRV_FWD, data.DRV_BCK set to zero and send out all zero's.

  2. I press the button and then I move the joystick forward and send the data format :-data.Steer_left = 0, data.Steer_right =0, data.DRV_FWD = 3, data.DRV_BCK =0.

  3. While joystick moved forward keep sending data.

3A. If no joystick movement is detected within 5 seconds go back to 1.

4 After 5 seconds and joystick moved back to neuteral postion go back to 1.

Hope this makes sense and I have understood your question correctly, I may be over thinking which is putting the blocker on me trying to do what I'd like (can't see the wood through the trees kind of ting :-).

Steveiboy:

  1. No Enable button pressed :-data.Steer_left, data.Steer_right, data.DRV_FWD, data.DRV_BCK set to zero and send out all zero's.

The way I am thinking there must be at least 6 lines of stuff there, and I would not be surprised to see 12 lines

Probably the same for your other items.

Computers are very stupid, You must use extraordinary detail to get a program correct.

I had assumed it would take you 2 or 3 hours (or more) to make the list - not 20 minutes.

...R

I can't seem to grasp while loops, I've tried to get this code working but no joy.

Not sure where I'm going wrong which will be simple to others.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

#define FWD_UP  3 //forward signal from joystick
#define REV_DN 4 //reverse signal from joystick
#define Error_led A3 //Error LED on power up
#define Enable_button 5
int ledState = LOW;
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long timer_previousMillis = 0;        // will store last time LED was updated
// constants won't change:
const long interval = 250;
unsigned long Timer = 5000;
unsigned long Timer_currentMillis = 0;
unsigned long currentMillis = 0;
boolean failsafe = false;
boolean FWD_UP_DAT = 0; //set the forward signal to 0
boolean REV_DN_DAT_DAT = 0;//set backwards siganl to 0
boolean En_butt = 0;
int Test_state;

void setup() {
  lcd.begin(16, 2);
  lcd.clear();
  pinMode(Error_led, OUTPUT);
  //  digitalWrite(Error_led, LOW);
  pinMode(FWD_UP, INPUT_PULLUP);
  pinMode( REV_DN, INPUT_PULLUP);
  pinMode( Enable_button, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.print("TEST POWER UP");
  digitalWrite(Error_led, LOW);
  //Detect if any buttons are pressed on start up fail saafe if so jump to error loop
  while ((digitalRead(FWD_UP) == LOW) || (digitalRead(REV_DN) == LOW)) {
    Error();
  }
}

void loop() {
  FWD_UP_DAT     = digitalRead(FWD_UP); //Drive forward signal
  REV_DN_DAT_DAT    = digitalRead( REV_DN); //Drive Reverse signal
  En_butt   = digitalRead( Enable_button); //Drive Reverse signal

  if (Enable_button == LOW) {
    Timer_currentMillis = millis();
    if (Timer_currentMillis - timer_previousMillis >= Timer) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
      failsafe = true;
      digitalWrite(Error_led, HIGH);
    }
  }

  while (failsafe)
  {
    //############ drvie forwards/lift up function######################
    if (FWD_UP_DAT == LOW) {
      Test_state = 5;
      lcd.setCursor(0, 1);
      lcd.print("FORWARD");
      failsafe = false;

    }
    else {
      Test_state = 1;
      failsafe = false;
      lcd.setCursor(0, 1);
      lcd.print("        ");
      digitalWrite(Error_led, LOW);
    }
    //############ drvie backwards/lift down  function######################
    if (REV_DN_DAT_DAT == LOW) {
      Test_state = 4;
      failsafe = true;
      lcd.setCursor(0, 1);
      lcd.print("BACKWARD");
    }
    else {
      Test_state  = 6;
      digitalWrite(Error_led, LOW);
      failsafe = true;
      lcd.setCursor(0, 2);
      lcd.print("           ");
    }
  }

  lcd.setCursor(0, 2);
  lcd.print(Test_state);
}

void Error() {

  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 (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(Error_led, ledState);
  }

}

Steveiboy:
I can't seem to grasp while loops, I've tried to get this code working but no joy.

In general. don't use WHILE because it blocks the Arduino until it finishes. Use IF and allow loop() to do the iteration.

But I remain of the opinion that a clear and detailed statement of the requirement is the first priority. Jumping into code before you have the requirement set down is usually a complete waste of time. When there is a clear statement of the requirement the code almost writes itself.

...R

Definition of the problem is 95% of its solution.

Robin2:
In general. don't use WHILE because it blocks the Arduino until it finishes. Use IF and allow loop() to do the iteration.

But I remain of the opinion that a clear and detailed statement of the requirement is the first priority. Jumping into code before you have the requirement set down is usually a complete waste of time. When there is a clear statement of the requirement the code almost writes itself.

...R

Ok thanks I will look at by trying another way and not use while loop.

The program it's self seems to work really well been doing lots of testing, But just need to add some extra protection against false movement of the joystick.

Your code was doomed by this bit:

  En_butt   = digitalRead( Enable_button); //Drive Reverse signal

  if (Enable_button == LOW) {

Since you are comparing a pin number to LOW.

Here is my suggestion:

  • create a flag variable that will be set when the enable button is pressed
  • when not enabled and the enable button is hit set the flag and start a timeout timer
  • if joystick is active reset the timer
  • if joystick is not active and enable is set check for timeout

For example:

unsigned long Timer = 5000;
unsigned long Timer_currentMillis = 0;


#define Enable_button 5
#define FWD_UP  3 //forward signal from joystick
#define REV_DN 4 //reverse signal from joystick
boolean FWD_UP_DAT = 0; //set the forward signal to 0
boolean REV_DN_DAT_DAT = 0;//set backwards siganl to 0

bool enabled = false;

void setup() {


}

void loop() {

  FWD_UP_DAT     = digitalRead(FWD_UP); //Drive forward signal
  REV_DN_DAT_DAT    = digitalRead( REV_DN); //Drive Reverse signal

  // if joystick active
  if ( (FWD_UP_DAT == LOW) || (REV_DN_DAT_DAT == LOW) )
  {

    // reset timer
    Timer_currentMillis = millis();

  } else if ( enabled ) {   // joystick not active, enable set - check timeout

    // if timer is up clear enabled flag
    enabled =  (millis() - Timer_currentMillis) >= Timer;

  } // else if

  // if not enabled and enable button is pressed
  if ( !enabled && (digitalRead( Enable_button) == LOW) )
  {
    // set flag
    enabled = true;

    // set timer
    Timer_currentMillis = millis();

  } // if


  if ( enabled )
  {

    // send joysick info

  } // if


}

Thanks blues eyes that has give me the idea how to do it and very well explained.

I've studied your code and can follow it, There msut be a little glitch as I've added the pins in set up to suit added an LED to show what's going on.

It works as described so when I move the joystick the LED remains on, If I just press the enable button it does not count for 5 seconds as I would thought it would the LED just goes straight out on once enable button released.

Which I'm looking into to get to understand the ocde better and hopefully get to the bottom of

Here's my code

unsigned long Timer = 5000;
unsigned long Timer_currentMillis = 0;


#define Enable_button 5
#define FWD_UP  3 //forward signal from joystick
#define REV_DN 4 //reverse signal from joystick
boolean FWD_UP_DAT = 0; //set the forward signal to 0
boolean REV_DN_DAT_DAT = 0;//set backwards siganl to 0
#define Error_led A3
bool enabled = false;

void setup() {
  pinMode(Error_led, OUTPUT);
  digitalWrite(Error_led, LOW);
  pinMode(FWD_UP, INPUT_PULLUP);
  pinMode( REV_DN, INPUT_PULLUP);
  pinMode(Enable_button, INPUT_PULLUP);
}

void loop() {

  FWD_UP_DAT     = digitalRead(FWD_UP); //Drive forward signal
  REV_DN_DAT_DAT    = digitalRead( REV_DN); //Drive Reverse signal

  // if joystick active
  if ( (FWD_UP_DAT == LOW) || (REV_DN_DAT_DAT == LOW) )
  {
    // reset timer
    Timer_currentMillis = millis();

  } else if ( enabled ) {   // joystick not active, enable set - check timeout

    // if timer is up clear enabled flag
    enabled =  (millis() - Timer_currentMillis) >= Timer;

  } // else if

  // if not enabled and enable button is pressed
  if ( !enabled && (digitalRead( Enable_button) == LOW) )
  {
    // set flag
    enabled = true;

    // set timer
    Timer_currentMillis = millis();

  } // if


  if ( enabled )
  {
    //send data out from joystick
    digitalWrite(Error_led, HIGH);

  }
  else {
    //stop sending data out and turn off timer
    digitalWrite(Error_led, LOW);
  }


}

Once again thanks for the guidance and your time
Steve

Sorry, the enabled flag should only be set to false if the timer is up. Change is on line #39 of the code in #9.

unsigned long Timer = 5000;
unsigned long Timer_currentMillis = 0;


#define Enable_button 5
#define FWD_UP  3 //forward signal from joystick
#define REV_DN 4 //reverse signal from joystick
boolean FWD_UP_DAT = 0; //set the forward signal to 0
boolean REV_DN_DAT_DAT = 0;//set backwards siganl to 0
#define Error_led 13
bool enabled = false;

void setup() {
  pinMode(Error_led, OUTPUT);
  digitalWrite(Error_led, LOW);
  pinMode(FWD_UP, INPUT_PULLUP);
  pinMode( REV_DN, INPUT_PULLUP);
  pinMode(Enable_button, INPUT_PULLUP);

}

void loop() {

  FWD_UP_DAT     = digitalRead(FWD_UP); //Drive forward signal
  REV_DN_DAT_DAT    = digitalRead( REV_DN); //Drive Reverse signal

  // if joystick active
  if ( (FWD_UP_DAT == LOW) || (REV_DN_DAT_DAT == LOW) )
  {
    // reset timer
    Timer_currentMillis = millis();

  } else if ( enabled ) {   // joystick not active, enable set - check timeout

    // if timer is up clear enabled flag
    if ( (millis() - Timer_currentMillis)  >= Timer) enabled = false;;

  } // else if

  // if not enabled and enable button is pressed
  if ( !enabled && (digitalRead( Enable_button) == LOW) )
  {
    // set flag
    enabled = true;

    // set timer
    Timer_currentMillis = millis();

  } // if


  if ( enabled )
  {
    //send data out from joystick
    digitalWrite(Error_led, HIGH);

  }
  else {
    //stop sending data out and turn off timer
    digitalWrite(Error_led, LOW);
  }


}

Blue eyes Thanks very much for your help, I did study both sets of code and seen what you added/changed

I did spot the false bit in front off ( (FWD_UP_DAT == LOW) || (REV_DN_DAT_DAT == LOW) ) which I removed as it timed out after 5 seconds.

I have learnt so much from your code and the way you have done it

Regards
Steve