text:
State machine waiting for input state isn't getting input states for unknown reason
I have a state machine program used to monitor sensors and activate relays that has been used and adapted on multiple machines and it typically performs exactly as needed. I am attempting to adapt the program to include an additional relay and two sensors and I can't figure out why the program won't update the states for two of the sensors added. All other sensors update and the program runs as intended until the program enters the state to check that the sensors have been interrupted. The final machine will use photo interrupters but I have bread boarded the circuit with both the sensors as well as using switches to attempt to debug the system.
Everything else works flawlessly on the breadboard and the program runs great save for the part where the program is waiting for the state of the sensors to read "BOTH_RSENSORS_LOW" on line 304 of the program. I have the serial monitor running to check the status of "RsensorState" that is updated every time line 302 runs. Within the main loop, "RsensorState" should be getting updated on line 174 which is supposed to be updated on line 437 where it should be returning the state based on the sensor inputs. The serial monitor shows no change to the state while changing the input on the pins attached to it. I have tested other pins as well in case they are shorted somehow to HIGH. I have the exact same sensors working fine to return the state of sensors 1 and 2. I have gone over the code and don't know what is missing. Every other block works great and as wanted. Perhaps I have a small syntax error that I am simply not seeing. I have attempted to lay out the program in as easy a format as I can and build the steps of the logic in blocks that are easy for me to navigate.
Board: Arduino DUE
Software: Arduino IDE 1.8.5
Includes the libraries Bounce2.h and LiquidCrystal.h
The device is designed to use a system of two buttons that need to be pressed within a specified time of each other. If at any point they are released they should turn off the relays and wait til both of them are released completely before being able to proceed again. The program is set up in 10 states to perform the functions of the machine.
CLEAR_SENSORS Turns off relay2 attached to a physical stop designed to align the part so the finished part can be slid through the machine and then checks to see if sensors 1 and 2 are not blocked meaning the part has been removed so the stop can then be be put back in place. Sensors 1 and two are on either side of the stop so that the stop will not be activated and hit the part as it is getting pushed through.
CHECK_SENSORS Turns back on relays and waits until a part is put back in and the first sensor can see that a part is in place. When it sees a part it moves to the next state.
WAIT_FOR_BOTH_LOW Checks the two safety buttons to be sure they are both released and the operator has not tried to short one out or has stuck something in the switch to hold it on. This is returned to any time the switches fail the timeout parameters.
WAIT_FOR_BUTTON Waits for a button to be pressed and goes into the next step.
ONE_PUSHED_WAIT_FOR_OTHER_BUTTON looks for the other button to be pressed within the specified time frame. If it is not then the program goes back to waiting for both to be released.
FINAL_CHECK checks to make sure the part has not been removed. If it has it goes back to waiting for the part to be put back in place and for all buttons to be released.
LOWER_RAILS checks to make sure the buttons are still being held and if so lowers an aligning and holding railing attached to Relay3
CHECK_RAIL_SENSORS checks 2 sensors to be sure they are both blocked and the railing is fully down. They are to act as limit sensors. This is the step the program gets stuck on.
SAFETY_WINDOW is a small time frame the machine waits until it turns on the relays and then after that time frame turns on relay1
RELAY_ON turns off the main relay1 and the holding relay3 if the buttons are released and turns them off after the time frame for the relays to run has expired. It then goes to the beginning where it waits for the part to be removed.
When I bypass the CHECK_RAIL_SENSORS step the whole things works flawlessly. I am stumped why that particular part isn't working. From what I can tell it has to do with the RsensorState not getting updated as expected like the other sensors are. sensorState updates and functions exactly as expected so I am not sure why RsensorState does not. Am I making a syntax error I am not aware of? I have gone through it a hundred times and maybe I am just not seeing it. All the components have been tested and function as expected. Here is the code:
// This sketch reads inputs from two buttons and a sensor to turns on 2 relays
// RelayPin2 is engaged until the end of the first relay's cycle
// It requires that both buttons be pressed within a certain time of each other and held
// A relay pin is then turned on for a specified period of time
// RelayPin3 turns on and is verified by Sensors 3 and 4
// RelayPin2 is turned off after the first relay pin has completed it's cycle
// When the sensor is clear, RelayPin2 is turned on again
// Both buttons must then be released again for another cycle to begin
// A state machine is used, only to make it more clear what is going on.
// Used with an Arduino DUE on Arduino 1.8.5 IDE
// Original sketch found on https://arduino.stackexchange.com/questions/45584/state-machine-logic-problem-with-added-states-monitoring-safety-switches/
// Uses the Bounce2 library: https://github.com/thomasfredericks/Bounce2
//
// When a button is pressed, the input turns HIGH.
//
// Normally only one 'enum' is used for the state, that controls the code.
// This sketch has also a 'enum' for the buttons, which is called the input state.
// define the different states for this sketch.
// An 'enum' is like a number of #define with increasing numbers.

// include the library code:
#include <Bounce2.h>
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

// Logical states of the main state machine
enum
{
  CLEAR_SENSORS,
  CHECK_SENSORS,
  WAIT_FOR_BOTH_LOW,
  WAIT_FOR_BUTTON,
  ONE_PUSHED_WAIT_FOR_OTHER_BUTTON,
  FINAL_CHECK,
  LOWER_RAILS,
  CHECK_RAIL_SENSORS,
  SAFETY_WINDOW,
  RELAY_ON,
} state;       // an 'enum' is its own type.

// define the different input states.
enum
{
  BOTH_BUTTONS_LOW,      // no buttons are pressed.
  BOTH_BUTTONS_HIGH,     // both buttons are pressed.
  ONE_BUTTON_HIGH,       // probably one of the buttons is pressed.
};

// Define the different sensor states

enum
{
  BOTH_SENSORS_HIGH, // Both Sensors are not blocked
  BOTH_SENSORS_LOW, // Both Sensors are blocked
  SENSOR1_HIGH_SENSOR2_LOW,  // Sensor 1 is not blocked but Sensor 2 is
  SENSOR2_HIGH_SENSOR1_LOW,   // Sensor 2 is not blocked but Sensor 1 is
};

// Define the different rail sensor states

enum
{
  BOTH_RSENSORS_HIGH, // Both sensors are not blocked
  BOTH_RSENSORS_LOW,  // Both rail sensors are blocked
  SENSOR3_HIGH_SENSOR4_LOW,  // Sensor 3 is not blocked Sensor 4 is
  SENSOR4_HIGH_SENSOR3_LOW,  // Sensor 4 is not blocked Sensor 3 is
};

const int ButtonPin1 = 2;
const int ButtonPin2 = 3;
const int Sensor1Pin = 6;
const int Sensor2Pin = 24;
const int Sensor3Pin = 30;
const int Sensor4Pin = 31;
const int RelayPin = 5;
const int RelayPin2 = 13;
const int RelayPin3 = 34;
const int IndicatorPin = 4;
const int IndicatorPin2 = 25;
const int IndicatorPin3 = 26;
const int IndicatorPin4 = 27;
const int IndicatorPin5 = 35;

// The 'previousMillis' is exclusively for the state machine portion only.
// It is used for different software timers in different states.
// That is okay, because within the state machine the states are seperated from each other.
// Funtions outside the state machine would require a separate timer.
unsigned long previousMillis;

const unsigned long RelayOnTime = 1750;    // Length of time for relay
const unsigned long TimeFrameForSecondButton = 300; // Length of time to allow two pushes
const unsigned long PushSafetyWindow = 300; // Safety Delay after push to be sure part is in place

// Counters for the number of failed relay triggers and successful cycles.
// They can probably be normal integers as well.
unsigned long failed = 0;
unsigned long success = 0;

// Instantiate Bounce objects
Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
Bounce debouncer3 = Bounce();
Bounce debouncer4 = Bounce();
Bounce debouncer5 = Bounce();
Bounce debouncer6 = Bounce();

void setup()
{
  lcd.begin(16, 2);
  lcd.print("On");
  Serial.begin(9600);
  Serial.println("Unit Online");

// Set up first button
  pinMode(ButtonPin1, INPUT);
  debouncer1.attach(ButtonPin1);
  debouncer1.interval(15); //Debounce time

// Set up second button
  pinMode(ButtonPin2, INPUT);
  debouncer2.attach(ButtonPin2);
  debouncer2.interval(15); //Debounce time

// Set up Sensor1
  pinMode (Sensor1Pin, INPUT);
  debouncer3.attach(Sensor1Pin);
  debouncer3.interval(5); //Debounce time

// Set up Sensor2
  pinMode (Sensor2Pin, INPUT);
  debouncer4.attach(Sensor2Pin);
  debouncer4.interval(5); //Debounce time

  // Set up Sensor3
  pinMode (Sensor3Pin, INPUT);
  debouncer5.attach(Sensor3Pin);
  debouncer5.interval(5); //Debounce time

// Set up Sensor4
  pinMode (Sensor4Pin, INPUT);
  debouncer6.attach(Sensor4Pin);
  debouncer6.interval(5); //Debounce time

  pinMode(RelayPin, OUTPUT);      // OUTPUT to Relay
  pinMode(RelayPin2, OUTPUT);     // OUTPUT to Second Relay
  pinMode(RelayPin3, OUTPUT);     // OUTPUT to Third Relay
  pinMode(IndicatorPin, OUTPUT);  // OUTPUT to Indicator LED
  pinMode(IndicatorPin2, OUTPUT); // OUTPUT to Second Indicator LED
  pinMode(IndicatorPin3, OUTPUT); // OUTPUT to Third Indicator LED
  pinMode(IndicatorPin4, OUTPUT); // OUTPUT to Fourth Indicator LED
  pinMode(IndicatorPin5, OUTPUT); // OUTPUT to Fifth Indicator LED

  Serial.println("Going to CLEAR_SENSORS state");

// Set initial state of the machine
  state = CLEAR_SENSORS;
}

void loop()
{

  unsigned long currentMillis = millis();

// Update the Bounce instances
  debouncer1.update();
  debouncer2.update();
  debouncer3.update();
  debouncer4.update();

  int inputState = getInputState();
  int sensorState = getSensorState();
  int RsensorState = getRSensorState();

// Process the data in a state machine.
// The output part is also in the state machine.
  switch(state)
  {
    case CLEAR_SENSORS:
       // Turn off relay2 and wait til everything is clear
        lcd.setCursor(0,0);
        lcd.print("Clear Machine");
        digitalWrite(RelayPin2, LOW);     // Turn OFF Relay 2
        digitalWrite(IndicatorPin2, LOW); // Turn OFF IndicatorPin 2
        digitalWrite(IndicatorPin4, HIGH); // Turn ON IndicatorPin 4
      if(sensorState == BOTH_SENSORS_HIGH)
      {
        // Prepare to go to the next state
        Serial.println("Machine Clear Going to CHECK_SENSORS state");
        state = CHECK_SENSORS;
      }
      break;
    case CHECK_SENSORS:
      // Turn on Relay 2 and then verify the sensor is engaged before proceeding
        lcd.setCursor(0,0);
        lcd.print("Load Barricade");
        digitalWrite(RelayPin2, HIGH);  // Turn on Relay 2
        digitalWrite(IndicatorPin2, HIGH); // Turn ON IndicatorPin 2
        digitalWrite(IndicatorPin3, HIGH); // Turn ON IndicatorPin 3
        digitalWrite(IndicatorPin4, LOW); // Turn OFF IndicatorPin 4
      if(sensorState == SENSOR2_HIGH_SENSOR1_LOW)
      {
        // Prepare to go to the next state
        Serial.println("Machine Clear Going to WAIT_FOR_BOTH_LOW state");
        state = WAIT_FOR_BOTH_LOW;
      }
      break;
    case WAIT_FOR_BOTH_LOW:
      // Both buttons must be released to be able to continue.
        lcd.setCursor(0,0);
        lcd.print("Wait For Release");
        digitalWrite(IndicatorPin3, LOW); // Turn OFF IndicatorPin 3
      if(inputState == BOTH_BUTTONS_LOW)
      {
        // Prepare to go to the next state.
        Serial.println("Going to WAIT_FOR_BUTTON state");
        state = WAIT_FOR_BUTTON;
      }
      break;
    case WAIT_FOR_BUTTON:
// This is the state when everything is idle and no buttons are pressed.
// Normally both buttons are released.
// Waiting for the first button to be pressed.
// Both buttons could be pressed at the same time !
        lcd.setCursor(0,0);
        lcd.print("Engage Buttons   ");
      if(inputState == ONE_BUTTON_HIGH || inputState == BOTH_BUTTONS_HIGH)
      {
// At least one button is pressed.
// Prepare to go to the next state.
// Start a timer, because there is a timeout.
        Serial.println("Going to ONE_PUSHED_WAIT_FOR_OTHER_BUTTON state");
        previousMillis = currentMillis;
        state = ONE_PUSHED_WAIT_FOR_OTHER_BUTTON;
       }
      break;
    case ONE_PUSHED_WAIT_FOR_OTHER_BUTTON:
        lcd.setCursor(0,0);
        lcd.print("Wait for Other");
      if(inputState == BOTH_BUTTONS_LOW)
      {
// The button was released. That's not what we want.
// Return to the state to wait for both off.
        Serial.println("Going to WAIT_FOR_BOTH_LOW state");
        state = WAIT_FOR_BOTH_LOW;
      }
      else if(currentMillis - previousMillis >= TimeFrameForSecondButton)
      {
// The timeout has ended.
// The second button was not pushed after the first button
// within the timeout. That's too bad.
        Serial.println("Too Long Going to WAIT_FOR_BOTH_LOW state");
        state = WAIT_FOR_BOTH_LOW;
      }
      else if(inputState == BOTH_BUTTONS_HIGH)
      {
// The timeout has not ended and is still running.
// And now both buttons are pressed.
// We can continue.
// Start the timer for the SAFETY_WINDOW state.
        Serial.println("Going to FINAL_CHECK state");
        previousMillis = currentMillis;
        state = FINAL_CHECK;
      }
      break;
    case FINAL_CHECK:
      if(sensorState != SENSOR2_HIGH_SENSOR1_LOW)
      // Check to make sure the barricade hasn't been removed
      {
        // Prepare to go to the next state
        Serial.println("Machine Clear Going to CHECK_SENSORS state");
        state = CHECK_SENSORS;
      }
      else if(sensorState == SENSOR2_HIGH_SENSOR1_LOW)
      {
        Serial.println("Going to LOWER_RAILS state");
        state = LOWER_RAILS;
      }
      break;
    case LOWER_RAILS:
        lcd.setCursor(0,0);
        lcd.print("Lowering Rails  ");
      if(inputState != BOTH_BUTTONS_HIGH)
      // Check to be sure safety buttons are held and if not wait for another try
      {
        Serial.println("Going to WAIT_FOR_BOTH_LOW state from LOWER_RAILS");
        state = WAIT_FOR_BOTH_LOW;
      }
      else
      // If buttons 1 and 2 are still held proceed to turn on Relay 3 and onto the sensor check
      {
        digitalWrite(RelayPin3, HIGH);  // Turn ON RelayPin3
        digitalWrite(IndicatorPin5, HIGH); // Turn ON IndicatorPin5
        Serial.println("Going to CHECK_RAIL_SENSORS state");
        state = CHECK_RAIL_SENSORS;
      }
      break;
    case CHECK_RAIL_SENSORS:
       lcd.setCursor(0,0);
       lcd.print("Checking Rails  ");
       Serial.println(RsensorState);
       // Wait until the sensors are blocked to move into the next state
      if(RsensorState == BOTH_RSENSORS_LOW)
      {
        Serial.println("Going to SAFETY_WINDOW state");
        state = SAFETY_WINDOW;
      }
      break;
    case SAFETY_WINDOW:
        lcd.setCursor(0,0);
        lcd.print("Wait a second");
      if(inputState != BOTH_BUTTONS_HIGH)
      {
// During the safety time window, a button was released.
// Return to idle.
        Serial.println("Going to WAIT_FOR_BOTH_LOW state");
        digitalWrite(RelayPin, LOW);  // Turn OFF RelayPin
        digitalWrite(IndicatorPin, LOW); // Turn OFF IndicatorPin
        digitalWrite(RelayPin3, LOW);  // Turn OFF RelayPin3
        digitalWrite(IndicatorPin5, LOW); // Turn OFF IndicatorPin5
        state = WAIT_FOR_BOTH_LOW;
      }
      else if(currentMillis - previousMillis >= PushSafetyWindow)
      {
// The buttons are still pressed.
// The time window has reached the end.
// Prepare to go to the next state.
        Serial.println("Going to RELAY_ON state");
        previousMillis = currentMillis;
        digitalWrite(RelayPin, HIGH);  // Turn ON RelayPin
        digitalWrite(IndicatorPin, HIGH); // Turn ON IndicatorPin
        state = RELAY_ON;
      }
      break;
    case RELAY_ON:
        lcd.setCursor(0,0);
        lcd.print("Relay Engaged   ");
      if(inputState != BOTH_BUTTONS_HIGH)
      {
// One of the buttons was released.
// Stop the relay and return to idle.
// Although the relay was triggered, it was not succesful.
        failed++;
        Serial.print("Failed=");
        Serial.println(failed);
        Serial.println("Going to WAIT_FOR_BOTH_LOW state");
        digitalWrite( RelayPin, LOW);  // Turn Off RelayPin
        digitalWrite(IndicatorPin, LOW); // Turn Off IndicatorPin
        digitalWrite(RelayPin3, LOW);  // Turn OFF RelayPin3
        digitalWrite(IndicatorPin5, LOW); // Turn OFF IndicatorPin5
        state = WAIT_FOR_BOTH_LOW;
      }
      else if(currentMillis - previousMillis >= RelayOnTime)
      {
        // Everyting was okay.
        // The buttons are still pressed.
        // It was complete and succesful.
        // It is time to turn off the relay and return to idle.
        success++;
        Serial.print("Success=");
        Serial.println(success);
        Serial.println("Going to CLEAR_SENSORS state");
        lcd.setCursor(0,1);
        lcd.print("Cycles ");
        lcd.print(success);
        digitalWrite(RelayPin, LOW);  // Turn Off RelayPin
        digitalWrite(IndicatorPin, LOW); // Turn Off IndicatorPin
        digitalWrite(RelayPin3, LOW);  // Turn OFF RelayPin3
        digitalWrite(IndicatorPin5, LOW); // Turn OFF IndicatorPin5
        state = CLEAR_SENSORS;
      }
      break;
    default:
        Serial.println("Error, unknown state");
      break;
    }
}

// This function returns the input state.
// There is no StateChangeDetection, because a state machine is used.
  int getInputState()
{
  int returnInputState;

// Read the debounce state and create an input state according to the 'enum' values.
  int value1 = debouncer1.read();
  int value2 = debouncer2.read();

    if(value1 == LOW && value2 == LOW)
    {
      returnInputState = BOTH_BUTTONS_LOW;
    }
    else if(value1 == HIGH && value2 == HIGH)
    {
      returnInputState = BOTH_BUTTONS_HIGH;
    }
    else
    {
    // Not both on, not both off, so it must be something else.
    returnInputState = ONE_BUTTON_HIGH;
    }

  return(returnInputState);
}

 // This function is to return the state of sensors 1 and 2
  int getSensorState()
{
  int returnSensorState;

// Read the sensor states and create an input state
  int value3 = debouncer3.read();
  int value4 = debouncer4.read();

    if(value3 == HIGH && value4 == HIGH)
    {
      returnSensorState = BOTH_SENSORS_HIGH;
    }
    else if(value3 == HIGH && value4 == LOW)
    {
      returnSensorState = SENSOR1_HIGH_SENSOR2_LOW;
    }
    else if(value4 == HIGH && value3 == LOW)
    {
      returnSensorState = SENSOR2_HIGH_SENSOR1_LOW;
    }
    else
    {
      returnSensorState = BOTH_SENSORS_LOW;
    }
  return(returnSensorState);
}

 // This function is to return the state of Sensors 3 and 4
  int getRSensorState()
{
  int returnRSensorState;

// Read the sensor states and create an input state
  int value5 = debouncer5.read();
  int value6 = debouncer6.read();

  if(value5 == LOW && value6 == LOW)
    {
      returnRSensorState = BOTH_RSENSORS_LOW;
    }
    else if(value5 == HIGH && value6 == LOW)
    {
      returnRSensorState = SENSOR3_HIGH_SENSOR4_LOW;
    }
    else if(value6 == HIGH && value5 == LOW)
    {
      returnRSensorState = SENSOR4_HIGH_SENSOR3_LOW;
    }
    else
    {
      returnRSensorState = BOTH_RSENSORS_HIGH;
    }
  return(returnRSensorState);
}

The part giving me trouble is this state:
case CHECK_RAIL_SENSORS:
   lcd.setCursor(0,0);
   lcd.print("Checking Rails  ");
   Serial.println(RsensorState);
   // Wait until the sensors are blocked to move into the next state
  if(RsensorState == BOTH_RSENSORS_LOW)
  {
    Serial.println("Going to SAFETY_WINDOW state");
    state = SAFETY_WINDOW;
  }
  break;

It may be something to do with how the sensor state is acquired. I am using Bounce2 to debounce the inputs.
 // This function is to return the state of Sensors 3 and 4
  int getRSensorState()
{

  int returnRSensorState;

// Read the sensor states and create an input state
  int value5 = debouncer5.read();
  int value6 = debouncer6.read();

  if(value5 == LOW && value6 == LOW)
    {
      returnRSensorState = BOTH_RSENSORS_LOW;
    }
    else if(value5 == HIGH && value6 == LOW)
    {
      returnRSensorState = SENSOR3_HIGH_SENSOR4_LOW;
    }
    else if(value6 == HIGH && value5 == LOW)
    {
      returnRSensorState = SENSOR4_HIGH_SENSOR3_LOW;
    }
    else
    {
      returnRSensorState = BOTH_RSENSORS_HIGH;
    }
  return(returnRSensorState);
}

Any input is greatly appreciated! Please let me know if more clarification is necessary.
Edit 07/12/18
IF you use this code don't forget to update this section for it to work! The complete, corrected code is too large to post:
// Update the Bounce instances
  debouncer1.update();
  debouncer2.update();
  debouncer3.update();
  debouncer4.update();
  debouncer5.update();
  debouncer6.update();

Your debouncer update section:
// Update the Bounce instances
  debouncer1.update();
  debouncer2.update();
  debouncer3.update();
  debouncer4.update();

is missing debouncer5.update(); and debouncer6.update();. It is required to call update() once per loop() to ensure the object is up to date.

Oh man I can't believe I missed that! Thank you I was going cross eyed trying to figure out what I missed! It works great now!


text:
Problem with Dual Safety Switches Initiating Timed Relay
I have been working on an Arduino project that has me kind of stumped. What it needs to achieve is that two momentary safety switches need to be pushed and held within a specified time frame as defined by "PushTimeWindow" then continue to be held as a relay is engaged for the period of time as defined by "RelayOnTime" and at any point if either or both of the momentary switches are released the relay needs to turn off immediately. The number of successful pressed is then displayed on an LCD screen. I have most of that portion of the code working OK so far. It seems to do what I want it to do even if the code could be much more efficient.
I need to figure out a way to ensure the buttons are released first before another successful two hand press can be registered and another cycle initiated and they can't simply be held as the cycles continue. I have been trying to figure out how to place "state change" logic into the code but can't figure out where or how to include it properly. I created a variable called "LastButtonSafeChecked" and one called "ButtonSafeChecked" to act as a comparison but I can't get it to work properly. Where can I include that logic and is a state change the correct way to go about it in this case?
Any suggestions on improving the code and implementing the missing logic are greatly appreciated as I think it is outside the scope of my coding knowledge. I included a lot of serial print lines in order to try and debug what events were happening. Here is the code:
/*
Designed to detect two button presses within specific time gap
Then turn on a relay for a specified time
Then turn it off and look for another press
  */
// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

// this constant won't change:
 const int  ButtonPin1 = 2;   // the pin that pushbutton 1 is attached to
 const int  ButtonPin2 = 3;   // the pin that pushbutton 2 is attached to
 const int  RelayPin = 5;     // the pin that the Relay is attached to

// Variables will change:
int ButtonPushCounter = 0;    // counter for the number of button presses
int ButtonState1 = 0;         // current state of the button1
int ButtonState2 = 0;         // current state of button2
int LastRelayState = 0;     // previous state of relay
int ButtonSafeOn1 = 0;        // button1 time check passed
int ButtonSafeOn2 = 0;        // button2 time check passed
int ButtonSafeChecked = 0;     // Button Check passed flag
int LastButtonSafeChecked = 0;  // Last State of button check
int RelayOn = 0;            // toggles relay on off state
unsigned long RelayMillis = 0;  //on time check for relay
unsigned long Button1Millis = 0;  //on time check for Button1
unsigned long Button2Millis = 0;  //on time check for Button2
const long RelayOnTime = 1000; //Length of time for relay
const long PushTimeWindow = 1000; //Length of time to allow two pushes

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Press Count");
   // initialize the button pins as a inputs:
   pinMode(ButtonPin1, INPUT);
   pinMode(ButtonPin2, INPUT);
   // initialize the Relay Pin as an output:
   pinMode(RelayPin, OUTPUT);
   // initialize serial communication:
   digitalWrite(RelayPin, LOW);
   Serial.begin(9600);
}

void loop() {
unsigned long currentMillis = millis();
   // read the pushbutton input pins:
   ButtonState1 = digitalRead(ButtonPin1);
   ButtonState2 = digitalRead(ButtonPin2);
//check if Button1 is HIGH
    if (ButtonState1 == HIGH) {
        Button1Millis = currentMillis;
        Serial.println("Button1");
     }
//check if Button2 is HIGH
    if (ButtonState2 == HIGH) {
        Button2Millis = currentMillis;
        Serial.println("Button2");
      }
//let program know Button1 is within window
   if (ButtonState1 == HIGH) {
      if (currentMillis - Button1Millis < PushTimeWindow){
        ButtonSafeOn1 = 1;
    } else {
        ButtonSafeOn1 = 0;
    }
   }
//let program know Button2 is within window
   if (ButtonState2 == HIGH) {
      if (currentMillis - Button2Millis < PushTimeWindow){
        ButtonSafeOn2 = 1;
    } else {
        ButtonSafeOn1 = 0;
    }
   }
//Double Check both buttons are still pushed
   if (ButtonState1 == HIGH && ButtonState2 == HIGH) {
//Check to see if both button safetys add up and Change RelayOn to 1
    if (ButtonSafeOn1 + ButtonSafeOn2 == 2){
      ButtonSafeChecked = 1;
      RelayOn = 1;
      Serial.println("Relay On");
      } else {RelayOn = 0;
      ButtonSafeChecked = 0;
     }
    }
//Turn off relay if too much time elapsed
    if (currentMillis - RelayMillis < RelayOnTime) {
      RelayOn = 0;
      ButtonSafeChecked = 0;
    }
//Turn on relay pin if RelayOn is 1
  if (RelayOn == 1) {
       digitalWrite(RelayPin, HIGH);
       Serial.println("Relay Pin should go High");
    } else {digitalWrite(RelayPin, LOW);
    }
//update the RelayMillis if it is still on
  if (RelayOn == 1){
      RelayMillis = currentMillis;
    }
//increment counter to diplay press count
    if (LastRelayState != RelayOn){
      ButtonPushCounter++;
      Serial.println("State of Relay");
      Serial.print(RelayOn);
      Serial.println("  ");
      Serial.println("State of Last Relay State");
      Serial.print(LastRelayState);
    }
     // Delay a little bit to avoid bouncing
     delay(75);
     // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print((ButtonPushCounter/2));
  //Save Current Relay State for Next Loop
   LastRelayState = RelayOn;
  //Save Current Button Safety check for comparison for state change
   LastButtonSafeChecked =  ButtonSafeChecked;
}

update 10/13/17
Here is the current code that includes the Bounce2 library as suggested by user Jot as well as the state machine he created to handle the task. Could I have implemented Bounce2 better?
// A state machine is used, only to make it more clear what is going on.
//
// When a button is pressed, the input turns HIGH.
//
// Normally only one 'enum' is used for the state, that controls the code.
// This sketch has also a 'enum' for the buttons, which is called the input state.

// define the different states for this sketch.
// An 'enum' is like a number of #define with increasing numbers.
// include the library code:
#include <Bounce2.h>
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

enum
{
  WAIT_FOR_BOTH_OFF,
  WAIT_FOR_BOTH_ON,
  SAFETY_WINDOW,
  RELAY_ON,
} state;       // an 'enum' is automatically an integer.

// define the different input states.
enum
{
  BOTH_OFF,        // no buttons are pressed.
  BOTH_ON,         // both buttons are pressed.
  SOMETHING_ELSE,  // probably one of the buttons is pressed.
};

const int ButtonPin1 = 2;
const int ButtonPin2 = 3;
const int RelayPin = 5;

// The previousMillis is used twice for two different things.
// That is okay in this state machine.
unsigned long previousMillis;

const unsigned long RelayOnTime = 1750;    // Length of time for relay
const unsigned long PushTimeWindow = 300; // Length of time to allow two pushes

// Counters for the number of failed relay triggers and successful cycles.
// They can probably be normal integers as well.
unsigned long failed = 0;
unsigned long success = 0;

Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();

void setup()
{
  lcd.begin(16, 2);
  lcd.print("Press Count");
  Serial.begin(9600);
  Serial.println("Unit Online");

// Set up first button
  pinMode(ButtonPin1, INPUT);
  debouncer1.attach(ButtonPin1);
  debouncer1.interval(5); //Debounce time

// Set up second button
  pinMode(ButtonPin2, INPUT);
  debouncer2.attach(ButtonPin2);
  debouncer2.interval(5); //Debounce time

  pinMode(RelayPin, OUTPUT);  // OUTPUT to Relay

  Serial.println("Going to WAIT_FOR_BOTH_OFF state");
  state = WAIT_FOR_BOTH_OFF;
}

void loop()
{

  unsigned long currentMillis = millis();

// Update the bounce instances
  debouncer1.update();
  debouncer2.update();

  int inputState = getInputState();

  // Process the data in a state machine.
  // The output part is also in the state machine.
  switch(state)
  {
    case WAIT_FOR_BOTH_OFF:
      // Both buttons must be released to be able to continue.
      if(inputState == BOTH_OFF)
      {
        // Prepare to go to the next state.
        Serial.println("Going to WAIT_FOR_BOTH_ON state");
        state = WAIT_FOR_BOTH_ON;
      }
      break;
    case WAIT_FOR_BOTH_ON:
      // This is the state when everything is idle and no buttons are pressed.
      // Normally both buttons are released,
      // but when both are pressed, then go to the next state.
      if(inputState == BOTH_ON)
      {
        // Prepare to go to the next state.
        Serial.println("Going to SAFETY_WINDOW state");
        previousMillis = currentMillis;
        state = SAFETY_WINDOW;
      }
      break;
    case SAFETY_WINDOW:
      if(inputState != BOTH_ON)
      {
        // During the safety time window, a button was released.
        // Return to idle.
        Serial.println("Going to WAIT_FOR_BOTH_OFF state");
        state = WAIT_FOR_BOTH_OFF;
      }
      else if(currentMillis - previousMillis <= PushTimeWindow)
      {
        // The buttons are still pressed.
        // The time window has reached the end.
        // Prepare to go to the next state.
        Serial.println("Going to RELAY_ON state");
        previousMillis = currentMillis;
        digitalWrite(RelayPin, HIGH);  // Turn ON RelayPin
        state = RELAY_ON;
      }
      break;
    case RELAY_ON:
      if(inputState != BOTH_ON)
      {
        // One of the buttons was released.
        // Stop the relay and return to idle.
        // Although the relay was triggered, it was not succesful.
        failed++;
        Serial.print("Failed=");
        Serial.println(failed);
        Serial.println("Going to WAIT_FOR_BOTH_OFF state");
        digitalWrite( RelayPin, LOW);  // Turn Off RelayPin
        state = WAIT_FOR_BOTH_OFF;
      }
      else if(currentMillis - previousMillis >= RelayOnTime)
      {
        // Everyting was okay.
        // The buttons are still pressed.
        // It was complete and succesful.
        // It is time to turn off the relay and return to idle.
        success++;
        Serial.print("Success=");
        Serial.println(success);
        Serial.println("Going to WAIT_FOR_BOTH_OFF state");
        lcd.setCursor(0,1);
        lcd.print(success);
        digitalWrite(RelayPin, LOW);  // Turn Off RelayPin
        state = WAIT_FOR_BOTH_OFF;
      }
      break;
    default:
      Serial.println("Error, unknown state");
      break;
  }
}

// This function returns the input state.
// There is no StateChangeDetection, because a state machine is used.
int getInputState()
{
  int returnInputState;

  // Read the debounce state and create a input state according to the 'enum' values.
  int value1 = debouncer1.read();
  int value2 = debouncer2.read();

  if(value1 == LOW && value2 == LOW)
  {
    returnInputState = BOTH_OFF;
  }
  else if(value1 == HIGH && value2 == HIGH)
  {
    returnInputState = BOTH_ON;
  }
  else
  {
    // Not both on, not both off, so it must be something else.
    returnInputState = SOMETHING_ELSE;
  }

  return(returnInputState);

}

Sorry about the formatting, I went back to edit it but it was already changed to the correct formatting. Thanks.,

Another issue the code has upon further testing is that an operator could hold one button down and then hit the other and it allows the relay to turn on. That behavior won't work either as the device is to increase the effectiveness of a safety system on some equipment and it is supposed to prevent any operator from being able to "trick" a safety system into letting it allow a user to use only one hand or to be able to force the system to cycle without hands. Thanks again for looking.

Are both buttons equally important ? And you only have to know if both are pressed or both are released or something in between ? Then there is no need for two variables to store the millis value. For the state, either use a single variable that can be multiple states or two variables. Have you programmed a state machine before ? A state machine with StateChangeDetection for the buttons would make the sketch a lot larger but also easier to read and easier to add things to it and to change things. Without the state machine, I would create a single StateChangeDetection for both buttons together.

Hello Jot, I have used a state change in a previous device but I can't figure out how to add it in. Both buttons are equally important as they are safety switches designed to keep both of an operators hands occupied and out of the way as the relay is on. Whenever one or both switches is released the relay needs to turn off as quick as possible. The air solenoid attached to the relay automatically switches in reverse and initiates a brake system to stop the device.

A state change does seem Ideal as the whole system needs to wait after a relay cycle is complete until both buttons are released and then depressed again in order to start a  new relay cycle.

A good way to make a sketch easier is to split it into three parts. The input part, the processing part and the output part. What about making an input function that returns a value from a enum { BOTH_OFF, BOTH_ON, SOMETHING_ELSE }. Then you can isolate the input from the rest. The processing part can be a state machine. The more I think about it, the more I think in the direction of a state machine.

Hello, I haven't used an enum before I will look up the function now and see how to use it. I think you are right about splitting up the sketch, I have been trying to lay it out in a "Bubble Diagram" to get my head around it. I am thinking that a state machine need to wrap around the outside of the whole sketch and the inputs and running of the relay needs to reside within that state machine. Thanks for the guidance, it's appreciated!

The Arduino has a loop function, that runs over and over again.
The Arduino has a millis function for the time.
Those two combine beautifully with a state machine.
Once I made a function that returns the input value as BOTH_OFF, BOTH_ON, or SOMETHINE_ELSE, then the state machine automatically unfolds itself.
I hope you see how clean the code is. Every state has its own code. You don't have to think for hours how to make a spaghetti of if-statements. Although the sketch is now larger, there is no unnecessary code.
If you want to change something, you only have to find the state that you want to change. Adding a new state is also easy.
I have added some explanation in the sketch.
// A state machine is used, only to make it more clear what is going on.
//
// When a button is pressed, the input turns HIGH.
// Are there an external pulldown resistors ?
//
// Normally only one 'enum' is used for the state, that controls the code.
// This sketch has also a 'enum' for the buttons, which is called the input state.

// define the different states for this sketch.
// An 'enum' is like a number of #define with increasing numbers.
enum
{
  WAIT_FOR_BOTH_OFF,
  WAIT_FOR_BOTH_ON,
  SAFETY_WINDOW,
  RELAY_ON,
} state;       // an 'enum' is automatically an integer <- it is not an integer

// define the different input states.
enum
{
  BOTH_OFF,        // no buttons are pressed.
  BOTH_ON,         // both buttons are pressed.
  SOMETHING_ELSE,  // probably one of the buttons is pressed.
};

const int ButtonPin1 = 2;
const int ButtonPin2 = 3;

// The previousMillis is used twice for two different things.
// That is okay in this state machine.
unsigned long previousMillis;

const unsigned long RelayOnTime = 1000;    // Length of time for relay
const unsigned long PushTimeWindow = 1000; // Length of time to allow two pushes

// Counters for the number of failed relay triggers and successful cycles.
// They can probably be normal integers as well.
unsigned long failed = 0;
unsigned long success = 0;

void setup()
{
  Serial.begin(9600);
  Serial.println("Hello");

  pinMode(ButtonPin1, INPUT);
  pinMode(ButtonPin2, INPUT);

  pinMode(LED_BUILTIN, OUTPUT);  // LED_BUILTIN for testing

  Serial.println("Going to WAIT_FOR_BOTH_OFF state");
  state = WAIT_FOR_BOTH_OFF;
}

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

  // Collect all input data.
  int inputState = getInputState();

  // Process the data in a state machine.
  // The output part is also in the state machine.
  switch(state)
  {
    case WAIT_FOR_BOTH_OFF:
      // Both buttons must be released to be able to continue.
      if(inputState == BOTH_OFF)
      {
        // Prepare to go to the next state.
        Serial.println("Going to WAIT_FOR_BOTH_ON state");
        state = WAIT_FOR_BOTH_ON;
      }
      break;
    case WAIT_FOR_BOTH_ON:
      // This is the state when everything is idle and no buttons are pressed.
      // Normally both buttons are released,
      // but when both are pressed, then go to the next state.
      if(inputState == BOTH_ON)
      {
        // Prepare to go to the next state.
        Serial.println("Going to SAFETY_WINDOW state");
        previousMillis = currentMillis;
        state = SAFETY_WINDOW;
      }
      break;
    case SAFETY_WINDOW:
      if(inputState != BOTH_ON)
      {
        // During the safety time window, a button was released.
        // Return to idle.
        Serial.println("Going to WAIT_FOR_BOTH_OFF state");
        state = WAIT_FOR_BOTH_OFF;
      }
      else if(currentMillis - previousMillis >= PushTimeWindow)
      {
        // The buttons are still pressed.
        // The time window has reached the end.
        // Prepare to go to the next state.
        Serial.println("Going to RELAY_ON state");
        previousMillis = currentMillis;
        digitalWrite(LED_BUILTIN, HIGH);  // LED_BUILTIN for testing
        state = RELAY_ON;
      }
      break;
    case RELAY_ON:
      if(inputState != BOTH_ON)
      {
        // One of the buttons was released.
        // Stop the relay and return to idle.
        // Although the relay was triggered, it was not succesful.
        failed++;
        Serial.print("Failed=");
        Serial.println(failed);
        Serial.println("Going to WAIT_FOR_BOTH_OFF state");
        digitalWrite( LED_BUILTIN, LOW);  // LED_BUILTIN for testing
        state = WAIT_FOR_BOTH_OFF;
      }
      else if(currentMillis - previousMillis >= RelayOnTime)
      {
        // Everyting was okay.
        // The buttons are still pressed.
        // It was complete and succesful.
        // It is time to turn off the relay and return to idle.
        success++;
        Serial.print("Success=");
        Serial.println(success);
        Serial.println("Going to WAIT_FOR_BOTH_OFF state");
        digitalWrite(LED_BUILTIN, LOW);  // LED_BUILTIN for testing
        state = WAIT_FOR_BOTH_OFF;
      }
      break;
    default:
      Serial.println("Error, unknown state");
      break;
  }
}

// This function returns the input state.
// There is no StateChangeDetection, because a state machine is used.
int getInputState()
{
  int returnInputState;

  // Read the buttons and create a input state according to the 'enum' values.
  int ButtonState1 = digitalRead(ButtonPin1);
  int ButtonState2 = digitalRead(ButtonPin2);

  if(ButtonState1 == LOW && ButtonState2 == LOW)
  {
    returnInputState = BOTH_OFF;
  }
  else if(ButtonState1 == HIGH && ButtonState2 == HIGH)
  {
    returnInputState = BOTH_ON;
  }
  else
  {
    // Not both on, not both off, so it must be something else.
    returnInputState = SOMETHING_ELSE;
  }

  return(returnInputState);
}

A few extra notes about a state machine or "finite state machine" or "FSM":
In the SAFETY_WINDOW state, I use "if .. else if .." instead of two seperate "if" statements. When the state is changed due to the buttons, then I don't want to check the timeout anymore.
In the SAFETY_WINDOW state, the relay is turned on, because there I prepare for the next state. If you think that is confusing, you can add a state in between, for example called INITIATE_RELAY_ON, and turn the relay on in that state and then continue to the next state.
That is also nice about a state machine. You can add or remove states and move code around for you convenience.
In the SAFETY_WINDOW state I check the buttons first and then the timeout. I could also check the timeout first. It does not matter.
This is typical for a state machine. When delay is replaced by millis and the Arduino loop and the state machine are executed many times per second, then it does not matter which condition is checked first.
A sketch can have many state machines. Sometimes a library contains a state machine. Such libraries often have a 'update' function, that is supposed to be called every time the Arduino loop runs.
Correction nov 4, 2017
Oops, an 'enum' is not automatically an integer. An 'enum' is its own type. Its type is more like the type of a union or struct.

That works brilliantly! Thank you for leaving the breadcrumbs in there to work out how it functions. I was running in circles trying to set up 4 different state changes timed with the millis function. I have been researching setting up finite state machines but I think I have been way over thinking it. I ended up thinking I needed 12 "What" states to keep track of instead of 7 like you used. I am now down the rabbit hole learning how these things are set up and know I think I will use similar logic here on out. Thanks again!

I can see how everything is switched around and executed in the "switch...case" function. I think I was definitely missing that type of envelope that groups it together properly. I am definitely more versed in long strings of "IF" statements that are trying to switch up and toggle too many variables.

Thanks. I have added "A few extra notes" paragraph at the end of my answer. I hope that makes the explanation complete.

Thank you for the additional information, it's really helpful.

Hello, I built the system and made the circuit board but ran into an unforeseen issue. The OSHA approved industrial switches are big and seem to bounce like crazy and in turn toggle off the logic of the program to turn off the relay and wait for the state to go low then high again. To debounce them would it would be a matter of adding an enum and a state to define each switch as debounced or not within a const unsigned long period and count millis again to toggle between the two states of within or outside of the bounce window? Does that sound on the correct track?

I suppose some smoothing capacitors on the input of the switches may do the trick of absorbing the spikes too... the solenoids and relays seem to have a nasty habit of throwing a lot of back spikes to the system which needed smoothing as well.

I would reading the inputs with digitalRead replace by Bounce2 ( https://github.com/thomasfredericks/Bounce2 ). The "debouncer.update" is called in the loop function many times until the input is stable during the specified period (called interval). There is also a mathematical much more advanced way for heavy debouncing: https://github.com/PaulMurrayCbr/DebounceInput

A RC filter at the input is always good for some extra protection. Not just a capacitor. When using only a capacitor, the current spike through the wires increases. What value is the pullup/pulldown resistor for the switch ? 220 ohm to 2k2 would be better than 10k.

Hello, I will check out bounce2 and and the other link you sent and see how it goes thank you. I have 10k pull down resistors on the switches now. I added (2) .1uf capacitors to each switch in parallel because I didn't have .2uf caps. It did smooth the bouncing out somewhat but I think that some software debouncing would really improve the system as it is still affected some by the bounce.

I use 10k for a button that is on the same pcb board. Use lower values. Can you measure with a storage scope how long the buttons bounce ? The "debouncer.update" goes directly in the Arduino loop, not behind an if-statement or so.

I have used the bounce2 library and it seems to be working as expected. I am building another system that I can test it on before I add the smoothing caps to the switches to see. The scope we have here is not working correctly so unfortunately I will have to do a bit of guessing on the debounce time. One thing that I hadn't noticed before is that the program does everything as expected except it seems to not honor the SAFETY_WINDOW. A button can be held down and even if the window has passed it still turns on the relay.

Is this behavior perhaps because the case WAIT_FOR_BOTH_ON constantly updates each cycle so the time window can't expire when the code previousMillis = currentMillis is called in that case? I will post the current state of the code in the question to show where it's at.

I tested the program before adding Bounce2 as well and the behavior of not honoring the safety window is still present.

Only 5ms ? That is for a little tiny micro switch. Use 50ms, or even up to 200ms. Can you get a number for how long the buttons are bouncing ? If you don't have a scope, perhaps a measuring sketch ? Did you replace the 10k resistor with 1k ? You really must lower that 10k. I do not understand your question, but you use the debouncerX.update and the debouncerX.read correctly. Perhaps the wires collect a lot of noise, or the wire to the button is floating. Try to measure and test more.

Now I understand your question. When a state is changed, old variables of the previous state don't have to be cleared, they are just no longer used. So when the state is changed I use the same previousMillis for the new state. I see no problem, but you can split it into two variables. What about a minimal time that both buttons must be off. There is definitely something going on with the buttons and the signal from the buttons. Is the signal perhaps LOW when the buttons are pressed ?

Hello, I will up the ms on the debounce time for sure and try to get a sketch going on to test the bounces. The pull downs have been reduced to 1k. I will try to split the time variables into two and see if I can get that to work to get the safety window working. The caps across the inputs have smoothed a lot of the bounce and the system functions as planned for the most part. I figure double insurance never hurts and I am excited to understand bounce2 and use it in the future. The only thing left is to fix the safety window. I will update when I get more information.

Perhaps my explanation of the original function was off because the notes in the sketch function exactly as they say. The buttons should have a small window within both need to be pressed. If they aren't pressed within that window they need to be released and pushed again to go back to WAIT_FOR_BOTH_OFF state. It is a window to ensure they are pushed within a specified time of each other, not a window to delay the relay turning on.

I think that may constitute a a new question as it is a different function than originally how it sounded it was stated. I will open up a new question to pose that logic.

Is there a reason that the state machine would ignore the input state of "SOMETHING_ELSE"? it seems to not ever enter that state despite one button being pushed and both high and both low not being true so it should return that state correct? I opened an additional question that is linked to this one with the new code since it was a new function to the original question.

From what I understood, this is what you're trying to do:

Turn a relay on as long as both buttons are pushed for 'pushWindowTime' milliseconds;
Keep the relay on for 'relayOnTime' milliseconds, or until at least one of the buttons are pushed.

I believe the difficulty you're facing is mostly because time is a parameter in your program, and in order to achieve that you're using 'millis()', which returns the number of milliseconds elapsed since the program starts. But rather than working with that, it may be easier in this case to use a delay associated to a loop, which is what I did.
int ButtonPin1 = 0;
int ButtonPin2 = 0;
int RelayPin = 0;

int ButtonState1 = 0;
int ButtonState2 = 0;

bool highState = false;

int pushTimeWindow = 10000;
int relayOnTime = 10000;

void setup() {
  //IOs definition
  pinMode(ButtonPin1, INPUT);
  pinMode(ButtonPin2, INPUT);
  pinMode(RelayPin, OUTPUT);

  digitalWrite(RelayPin, LOW);
}

void loop() {

  //Loop for reading each button's state in a given period of time 'pushTimeWindow'.
  for(int i = 0; i < pushTimeWindow; i++) {

    //Reads each button's state at every iteraction
    ButtonState1 = digitalRead(ButtonPin1);
    ButtonState2 = digitalRead(ButtonPin2);

    //Flags a boolean if both buttons are pushed.
    if((ButtonState1 == HIGH)&&(ButtonState2 == HIGH))
      highState = true;

    //If a button is released, breaks the loop.
    else {
      highState = false;
      break;
    }
    //Delays the loop one second.
    delay(1000);
  }

  if(highState) {

    //Loop to activate the relay as long as both buttons are pushed, during the time limit 'relayOnTime'.
    for(int i = 0; i < relayOnTime; i++) {

      ButtonState1 = digitalRead(ButtonPin1);
      ButtonState2 = digitalRead(ButtonPin2);

      //Activates the relay if both buttons are pushed.
      if((ButtonState1 == HIGH)&&(ButtonState2 == HIGH))
        digitalWrite(RelayPin, HIGH);

      //Shuts down the relay if a button is released and breaks the loop.
      else {
        digitalWrite(RelayPin, LOW);
        break;
      }

  //Delays the loop one second.
  delay(1000);
}

  }

  //Makes sure that every time loop() starts again, the relay is shut down.
  highState = false;

}

Hope this answers your question. Let us know what you find.

Hello, Thank you for taking a look at the code. The logic you stated is mostly what I am trying to do. I am trying to turn the relay on when both buttons are pushed within a time window. Both buttons need to stay pushed through the relay cycle. If either or both are released they relay must go off. After a relay cycle the system needs to wait until both buttons are released until it can initiate another relay cycle. My main concern with delays is if the system doesn't look for a button release the relay will not turn off.

Oh, I see. Now that you mentioned, there is an error in my code. The second loop also needs a digitalRead in order to constantly update each button's value. I'll edit the answer. Also, I'm assuming you would work with times like 5 or 10 seconds for both loops, so that's why the delay is 1 second long. If you want to work with shorter time periods, you could always make the delays smaller. Let me know if it works for you.

Here is the code:

your code and the code pieces posted so far suffer from two problems: 1) too specific to the application; and 2) too complicated.
here is a different approach to consider:
1) write a piece of code that reads the state of a button, with or without debouncing;
2) write a piece of code that detects no press, single press, double press, and long press (or even more if you want), using 1) above.
3) write a piece of code that detects the same but for two buttons, using 2) above.
...
you can consider the use of enum to make the code more robust.
with this approach, your code can be reused for future projects, and will be easier to maintain / understand as it is very intuitive and modular.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
How do I turn on or off an array of LEDs based on the value of a variable?
I've created a function whereby an int ('cleanCount') automatically goes up or down (0-1000) based on the situation. The value changes every few milliseconds.
Based on the value, I would like to turn on or off LEDs. Let's say for every increment of '100' another LED goes on. So if the value is 359 there are 3 leds on, if It would been 899 there would've been 8 LEDs on.
I could simply write
if (cleanCount <= 100) { // turn on NO LEDs
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    ...
}

...

else if (cleanCount <= 500) { // turn on 4 LEDs
    ...
    digitalwrite(led3, HIGH);
    digitalwrite(led4, HIGH);
    digitalwrite(led5, LOW);
    digitalwrite(led6, LOW);
    ...
}

but that would be a big pile of code which could be way more efficient. Perhaps.. my code isn't even correct.
So how could this be more efficient or perhaps actually working?

The whole code, here below.
int cleanCount = 1000;
int softpotPin = A0; //analog pin 0

void setup () {
    Serial.begin(9600);
    digitalWrite(softpotPin, HIGH); //enable pullup resistor
}

void loop() {
    int softpotReading = analogRead(softpotPin);
    if (softpotReading < 980) { // IF AANGERAAKT
        digitalWrite(werktIeLED, HIGH);
        ++cleanCount;
        Serial.println(cleanCount);
        delay(16); // 5x zo snel als leeglopen
    }
    else if (softpotReading > 980) { // IF NIET AANGERAAKT
        digitalWrite(werktIeLED, LOW);
        --cleanCount;
        Serial.println(cleanCount);
        delay(64); // 1000 / 60 seconden
    }
    else {      // Als er een fout optreed..
        Serial.println("Fout!");
        digitalWrite(werktIeLED, HIGH);
        delay(250);
        digitalWrite(werktIeLED, LOW);
        delay(250);
    }

}

If you want the a bar graph effect, the arduino ide has a ino under examples>Display>barGraph maps analog values to ten LEDs

@RSM but how would I combine that example with my scope: 1 LED per 100 of my variable. That- and multiple LED's should be lid.

The code uses the map() function and will lite an LED per 100, it also keeps LEDs on below the current lit

Here is a suggestion with the led pins in an array that you loop over.
I suggest making the array global, so put it outside any functions (usually at the top):
byte led_pins[] = {pin1, pin2, pin3, pin4, pin5, pin6, pin7, pin8};

Then put this in your loop (assumes that you have a int called cleanCount that is in scope:
const int increment = 100;

for (int i = 0; i < sizeof(led_pins) / sizeof(led_pins[0]); i++) {
  boolean onOrOff = cleanCount > (i+1) * increment;
  digitalWrite(led_pins[i], onOrOff);
}

I'm pretty new to Arduino and coding for it. But uh, do I paste all of that in 'void loop' or a part above 'void setup' and a part in 'void loop' or..? Seems great and character-optimised formatted.

I updated the answer

cleanCount is stated at the top, above the setup, but has the value changing functionality in the loop. I'll post the whole code in a sec.

You can use the barGraph example from the Arduino code examples. This gives a bar-type graph and not point. I will give rough explination why it will work and the need not to re-invent the wheel.
    int sensorReading = analogRead(analogPin);
  // map the result to a range from 0 to the number of LEDs:
  int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);

  // loop over the LED array:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed < ledLevel) {
      digitalWrite(ledPins[thisLed], HIGH);
    }
    // turn off all pins higher than the ledLevel:
    else {
      digitalWrite(ledPins[thisLed], LOW);
    }
  }

int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);
This will give you the point in the array, 0-10, for 0-1000, if you replace 1023 with 1000
Simplified map() function:
int point = sensorReading*10/1000 this gives you a range of 0-10, the int keeps it from having decimal points.
As you can see from the for loop it turns on all the LEDs that are in the array to the end and then turns off those not needed.

Instead of repeating several calls to digitalwrite you should consider changing the pins directly as described here.
This now depends on which port your LEDs are connected to. Assuming port D you would use DDRD to define the pins as output (usually in setup()) and PORTD to set their values (in loop), e.g.
DDRD = B11111110; // define pins 1..7 as outputs, pin 0 as input

and
PORTD = B11110000; // switch on first 4 LEDs

Now all you need to do is to write a function to map your number range to suitable bit strings.
The function could look like this:
int convert(int n) {

  int res = 0;   // start with all pins off (zero)
  while (n > 100) {
    res <<= 1;   // shift pattern 1 bit (i.e. pin) to the left
    res |= 1;    // "switch on" lowest pin
    n -= 100;    // defines step size (1 LED for every  100)
  }
  return res;

}

It takes your value and returns an int that you can assign to the port. I.e. for 0..100 it returns 0, for 101..200 it returns 1, for 201..300 it returns 3 = B11, for 301..400 it returns 7 = B111 and so on. (Note that it does not do any sanity checks on the input / output but that's certainly easy for you to add if needed.)
(In response to comment: Note that the bit pattern I use as example for DDRD above is an example: It sets bit / pin 0 as input. If you use convert you would, of course, set the lowest bit of DDRD to 1 to make it an output.)

502 error on the link.. But I can use 'port manipulation arduino' as a search term. Looking at the information. Seems great!

Link works for me? I'll add a function also.

Yeah, the link is working now for me too. Although perhaps this -> http://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/ explains it better. Or atleast, more easy. Awaiting the function. Thanks!

I really have to read that 4 times thoroughly, as I'm a real beginner and I didn't understand it the first time, hehe. But thanks!

added some hopefully helpful comments...

Problem is that there is always one led lid, even in n<100. Secondly, the DDRD example, has pin D0 as an input, while convert will just write to bit 0. Thirdly, the PORTD example actually lights up the last four leds. Direct port manipulation is not very beginner friendly, and isn't really necessary, unless performance becomes an issue.

Firstly, I am not hired to write code to specs but trying to give hints on how to solve a problem. Adjusting the code so that it lights no led if n < 100 is something I think Sander is well capable of. Secondly, I chose this bit pattern for DDRD to make clear what it means if a bit is 0. But I will add a comment to make sure that this is not missed. Thirdly, that depends on how you define first and last, right?

@Gerben It is not a problem if the first LED is always lid. Actually, that's great because the first one is red, which suggests 'BAD'. No leds visualize less than a red lid one. Perhaps you can add that, Fuenfundachtzig.  Besides that; every suggestion is appreciated. Perhaps port manipulation is nog beginner friendly, perhaps. But I'm asking for efficient code, instead of writing every LED in an IF statement, which would be awefully bad. That might result in more mediate code, instead of beginner one. Still: Thanks!

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Is is possible to hook up an SD card and a GSM/GSRM module?
Is it possible to hook up a GSM/GSRM module AND an SD card at the same time to an Arduino Uno, or any Arduino?
I want to build a cellphone to read off the buttons that are being dialed into it for a poor guy who has no hope of using a regular cellphone, and I figure I need to include wav files for the buttons (and any other functions) on an external source.
I'm a good programmer, so if I can hobble the parts together I can make them talk to each other.  But, I'm not so sure the different schemes for this all use the same pins, so I was wondering if someone would be so kind as to enlighten me..

SD uses SPI and the GSM uses the Serial connection with AT commands

So this shouldn't be an issue?  Those pins aren't shared?

No the pins aren't, Serial is 0, 1, but the software serial is used because those are the programming pins on an arduino and SPI are 11, 12, 13

Yes.

But let me try to talk you through it.
Step 1 - Analysis/Requirements:
Get your requirements right, what should your system do, what functionality.
So, GSM functionalities and SD card savings (in short).
One of the requirements would be that's it on an Arduino (atmega 328P).
Any other hardware requirements?
Step 2 - Design:
Check the possibilities with the Arduino, 1 hardware serial and multiple software serial connections. One hardware SPI/I2C I believe.
SD cards often use SPI connection and GSM units most likely use serial.
So this works great. Check some tutorials on SPI and (arduino) serial.
Step 3 - Wiring up
Wire everything up, as defined in the datasheet of the devices. Cross the Rx and Tx lines. Put MISO to MISO and MOSI to MOSI accordingly.
Be sure everything has enough power (GSM modules typically draw a lot of current when sending/connecting). Usually, if you find out that two devices are attached to the same pin, there might be something wrong (unless you can declare how they're seperated or why this is the case).
Step 4 - Implement
Well, you stated you're good at programming, so I'll leave this open for you.
But mind that it's only one of the three steps, so you should look at some tutorials, it'll learn a lot faster than asking everything. Try to get a bit comfortable with your thoughts, base them on things you have learned.

So this shouldn't be an issue? Those pins aren't shared? - user1833028

Things like this can be found in the device's datasheet and if you follow some tutorials you'll see that they're different and why.
Also, what helps for me often, is to try to seperate this 'big' project into two smaller projects.
Try to get the GSM working and after that you go for the SD card reader.


text:
Problem with some sensors but not with servos
I use a lot Arduino Uno, but in this case, I have some BQ ZUM BT-328 boards, which are based on Arduino BT. The problem with some of BQ ZUM BT-328 boards is that the ultrasonic sensor (HC-SR04) is not working in any pin. However, apparantely, the boards work and the 2 servos (SM-S4306R) work fine too. When I change the ultrasonic sensor to other pins and with other wires, it is not working yet. However, I use that sensor in another different BQ ZUM BT-328 board and it is working fine, and if I add the same setup (2 SM-S4306R) and same code, it continues working fine. Then, the problem is just in some boards, not in everyone.
The ultrasonic example is:
long distance;
long responseTime;

int pinTrig = 9;
int pinEcho = 8;

void setup(){
  Serial.begin(9600);
  pinMode(pinTrig, OUTPUT);
  pinMode(pinEcho, INPUT);
}

void loop(){
  digitalWrite(pinTrig, LOW);
  delayMicroseconds(5);

  digitalWrite(pinTrig, HIGH);
  delayMicroseconds(10);
  responseTime = pulseIn(pinEcho, HIGH);
  Serial.println("Tiempo "+ String(responseTime)+" microsegundos");

  distance = int(0.01716*responseTime);

  Serial.println("Distancia "+ String(distance)+"cm");
  delay(500);
}

Then, I suppose that those BQ ZUM BT-328 boards have some problem and maybe they are starting to fail. I say this, because the same problem works in some boards and in others fails. In those board in which it fails I checked the correct connection of pins (GND, VCC, digitals), change the pin and the wires without result. However, the servos continue to work fine and I can upload the code to the board. My questions are:
Am I correct and they are failing?
Why they are just failing with that sensor and not the SM-S4306R? I mean, maybe some specific component of the board is failing?

the questions are not answerable because your description lacks detail

Which more details do you need? I can add more or test more the board. Just tell me.

include information about the board, the sensors, the connection diagram and minimal program that shows the failure

I have added a reference to the datasheet of the board, the sensor, and the motor. I have explain better the mistakes, and added the code example.

Looks like in your sample code you did not complete the 10us pulse.
  digitalWrite(pinTrig, LOW);
  delayMicroseconds(5);

  digitalWrite(pinTrig, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrig, LOW); // you missed this

See example.

Thank you so much for your answer. I tried in all boards adding that line, but the result is the same. The boards which was failing continue failing.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Error message - Need help
I found this Haptic Headband project on YouTube (link below) and I am trying to verify the code that was given in the instructions with the Arduino IDE. However, I keep getting the message below and am not too sure what I need to do to fix it. I'd appreciate any help I could get to solve this issue.
I have also attached a pdf of the instructions with the code to use for the headband.
PDF: https://cdn-learn.adafruit.com/downloads/pdf/haptic-headband.pdf?timestamp=1602887165
https://www.youtube.com/watch?v=xD7bfBx5D9M&ab_channel=AdafruitIndustries

libraries\Adafruit_DRV2605_Library\Adafruit_DRV2605.cpp.o (symbol from plugin): In function `Adafruit_DRV2605::Adafruit_DRV2605()':
(.text+0x0): multiple definition of `Adafruit_DRV2605::setRealtimeValue(unsigned char)'
sketch\Adafruit_DRV2605.cpp.o (symbol from plugin):(.text+0x0): first defined here
libraries\Adafruit_DRV2605_Library\Adafruit_DRV2605.cpp.o (symbol from plugin): In function `Adafruit_DRV2605::Adafruit_DRV2605()':
(.text+0x0): multiple definition of `Adafruit_DRV2605::useERM()'
sketch\Adafruit_DRV2605.cpp.o (symbol from plugin):(.text+0x0): first defined here
libraries\Adafruit_DRV2605_Library\Adafruit_DRV2605.cpp.o (symbol from plugin): In function `Adafruit_DRV2605::Adafruit_DRV2605()':
(.text+0x0): multiple definition of `Adafruit_DRV2605::useLRA()'
sketch\Adafruit_DRV2605.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino Uno.

you asked for help with nonexistent code

It would help if you could put the code inside the question. Did you install the DRV2605 library correctly?

“Multiple definition” means that you have something defined more than
once. According to the error message, some methods are defined both in
libraries\Adafruit_DRV2605_Library and in your sketch folder.
It looks to me like you are trying to use two copies of the
Adafruit_DRV2605 library. One of them is properly installed as a
library, and the other is within your sketch folder. You don't need two
copies. If the library is properly installed, there is no point in
copying its source files to your sketch folder. Get rid of that extra
copy and try recompiling.

Thank you for your help! I got it!

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Changing the servo motor operating direction using arduino
I want to turn the servo motor 90 degrees with the first double high inputs, then I want to turn the motor 180 degrees with double high inputs, but the motor turns 180 degrees with one high input.
thank you for all help
#include <Servo.h>
Servo myservo;
const int  buttonPin = 8;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to
int Newbuttoncounter;
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  myservo.attach(9);
  myservo.write(90);
  delay(1000);
  pinMode(buttonPin, INPUT);

  pinMode(ledPin, OUTPUT);

  Serial.begin(9600);
}

void loop() {
  myservo.write(90);
  buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState) {

    if (buttonState == HIGH) {

      buttonPushCounter++;
      delay(500); // darbeleri alması için nefesleme.bu olmasa her darbede yüksek olur
    }
    if (buttonPushCounter % 2 == 0) {
      myservo.write(0);   //sağa döner
      delay(500);
      myservo.write(90);
      delay(500);
      Serial.println("WHITE");
      Newbuttoncounter = buttonPushCounter;

    }

    else if (Newbuttoncounter % 2 == 0) {

        myservo.write(180); //sola döner
        delay(500);
        myservo.write(90);
        delay(500);

      }

      else {

        lastButtonState = buttonState;
      }
    }
  }

Please [edit] your question to add the code there, not in an answer. The code markup is three backticks, not [code] here. Look at the help in the editor in case of doubt.

What's a "double" high input?

double high input detection of the sensor


text:
ESP32 webserver with a loaded page fails to update data in elements after sending an Json file, the Json data is printed instead of the loaded page
I've an ESP32 with a web server, in the page where I show the sensor readings and the state of the system, right now the readings are showing themselves well, the problem comes when I want to show the state of the system.
Right now I'm testing the behavior only with the /encender page, The state of the system is sent in a Json file to only update the elements that contains the system state but instead of update those html elements, the page dessapears and the web explorer shows me an error of empty response.
here follows my actual code related to my problem:
Code related to the /encender page (an  element) in backend.cpp:
server.on("/encender", HTTP_GET,[](AsyncWebServerRequest *request){
    digitalWrite(ledPinSistemaApagado,LOW);
    digitalWrite(ledPinSistemaEncendido,HIGH);
    if(ultimaPaginaCargada == "/encender");
    {
      Serial.println("No se envía la página /encender, solo se actualizará el estado del sistema.");
      request->send(200);
      return;
    }
    ultimaPaginaCargada = "/encender";
    cuentaAcceso = true;
    request->send(SPIFFS,"/index.html", String(), false, Procesador);
  });

the code in backend.cpp related to the update of the state of the function is like follows
server.on("/data-estado", HTTP_GET, [](AsyncWebServerRequest *request){
    if(!request->authenticate(usuarioHTTP, claveHTTP) && !cuentaAcceso) {
        return request->requestAuthentication("Ingreso al Sistema");
    };
    Serial.println("Enviando la data de estado.");
    sistemaEstado["estado-sistema"] = ledEstado;
    sistemaEstado["modo-sistema"] = modoSistema;
    String json = "";
    serializeJsonPretty(sistemaEstado, json);
    Serial.println(json);
    ultimaPaginaCargada = "/data-estado";
    cuentaAcceso = true;
    request->send(200, "application/json", json);
    json = String();
    Serial.println("Enviada la data de estado.");
});

right now the above piece of code, if the variable ùltimaPaginaCargada is "/encender", it means that the page /encender was previously loaded, so it only sends "200" to the web explorer, on the contrary the "/encender" wasn't previously loaded and that page is sent.
Following is the code on my app.js:
function Actualiza_Estado() {
    console.log("Entrando a Actualiza_Estado().");
    var xxhr = new XMLHttpRequest();
    if(this.readyState == 4 && this.status == 200)
    {
        console.log("Analizando los componentes reibidos en Actualiza_Estado()");
        var estadoWeb = JSON.parse(this.responseText);
        console.log(estadoWeb);
        var estadoEnc = document.getElementById("estado-sistema");
        estadoEnc.innerHTML = "
Estado Sistema: " + "" + `${estadoWeb.estado-sistema}` + "";
        var modoEnc = document.getElementById("modo-sistema");
        modoEnc.innerHTML = "
Modo Sistema: " + "" + `${modoEnc.modo-sistema}` + "";
        console.log("Enviados los componentes a actualizar a la pantalla");
    }
    else
    {
        console.log("Contenido no cargado en Actualiza_Estado()");

    }
    xxhr.open("HTTP_GET", "/data-estado", true);
    xxhr.send();
    console.log("Solicitada la actualización del estado del sistema");
};

// Funciones para mostrar el nivel del tanque en la página de visualización.

function Lee_Nivel_Tanque() {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if(this.readyState == 4 && this.status == 200)
        {
            var volTanqueWeb = JSON.parse(this.responseText);
            console.log(volTanqueWeb);
            var volActualWeb = document.getElementById("mask01");
            volActualWeb.innerHTML = volTanqueWeb.colAgua.toFixed(2);
        }
        else
        {
            console.log("Contenido no cargado en Lee_Nivel_Tanque()");
        }
    };
    xhr.open("HTTP_GET", "/data-tanque", true);
    xhr.send();
    console.log("Solicitada actualización del tanque.");
};

// Funciones para enviar la hora y la fecha a la ventana

function Fecha_Hora() {
    let hoyFecha = new Date();
    let hoyHora = hoyFecha.toLocaleTimeString();
    let dia = hoyFecha.getDate();
    let mes = hoyFecha.getMonth() + 1;
    let anio = hoyFecha.getFullYear();
    let diaSemana = hoyFecha.getDay();
    dia = ('0' + dia).slice(-2);
    mes = ('0' + mes).slice(-2);
    let semana = ['DOMINGO', 'LUNES', 'MARTES', 'MIÉRCOLES', 'JUEVES', 'VIERNES', 'SÁBADO'];
    let muestraSemana = semana[diaSemana];
    let fechaCompleta = `${muestraSemana}-${dia}-${mes}-${anio}`;
    document.getElementById("la-fecha").innerHTML = fechaCompleta;
    document.getElementById("la-hora").innerHTML = hoyHora;
    console.log(fechaCompleta + '->' + hoyHora);
};

window.onload = function() {
    let intervaloVolumen;
    let intervaloFecha;
    intervaloFecha = setInterval(Fecha_Hora, 1000);
    if((window.location.pathname === "/index") ||
        (window.location.pathname === "/apagar") ||
        (window.location.pathname === "/encender") ||
        (window.location.pathname === "/auto") ||
        (window.location.pathname === "/manual"))
    {
        //Actualiza_Estado();
        intervaloVolumen = setInterval(Lee_Nivel_Tanque, 20000);
    }
    else
    {
        clearInterval(intervaloVolumen);
        intervaloVolumen = null;
    }
}

var datoEstado = document.getElementsByClassName("boton-control");
datoEstado.addEventListener("click", function(event) {
    event.preventDefault();
    Actualiza_Estado();
});

above the functions that I think matters are Àctualiza_Estado() and the var datoEstado, datoEstado is bassically a listener that when I make click at any of the buttons made with  elements it calls Àctualiza_Estado() to request the Json file with the state of the system.
On the window.onload() function if any of the buttons or the proncipal page are loaded then it defines an interval to update the parameter to read from the sensor and every 20 seconds it requests a Json file whith that data (this works excelent).
is that in the function server.on() related to /encender page, I make the program to send a 200 response to the request to make the ESP32 code to send only the Json file by calling the Actualiza_Estado() function with requests /data-estado but like I said the web explorer seems to have an empty response.
I've made a variation in the function server.on() related to /encender page in backend.cpp to force the sending of the Json file directly from there like follows
server.on("/encender", HTTP_GET,[](AsyncWebServerRequest *request){
    digitalWrite(ledPinSistemaApagado,LOW);
    digitalWrite(ledPinSistemaEncendido,HIGH);
    if(ultimaPaginaCargada == "/encender");
    {
    Serial.println("Enviando la data de estado.");
    sistemaEstado["estado-sistema"] = ledEstado;
    sistemaEstado["modo-sistema"] = modoSistema;
    String json = "";
    serializeJsonPretty(sistemaEstado, json);
    Serial.println(json);
    ultimaPaginaCargada = "/data-estado";
    cuentaAcceso = true;
    request->send(200, "application/json", json);
    json = String();
    }
    ultimaPaginaCargada = "/encender";
    cuentaAcceso = true;
    request->send(SPIFFS,"/index.html", String(), false, Procesador);
});

in the above case the web explorer receives the Json file and displays de data but in an empty black page and shows the formatted Json file.
I don't know whats happening because the method of Json file works very well when using it for the sensor reading with Lee_Nivel_Tanque().
What can I do to solve the problem?

estadoWeb.estado-sistema needs to be estadoWeb["estado-sistema"]

The issue you're experiencing is likely due to the handling of the request->send(200); in the /encender endpoint. Have you already solved the problem?

@tepalia yes, I could solve the problem based on all your advices

I didn't go through all the question. Just looking at the code there are
quite a few issues that deserve to be addressed.
In the back-end for /encender, you have
    if(ultimaPaginaCargada == "/encender");
    {
    // ...

Notice the semicolon right after the condition. In C++, a bare semicolon
is an empty statement (a no-op). Here, this empty statement is the body
of the if statement. The braced block that follows is executed
unconditionally. This is most likely not what you mean.
        request->send(200);

Do not send an empty 200 response. If you want to tell the client “your
request has been processed successfully, but I have nothing to send to
you”, you should send a 204 No Content response.
    ultimaPaginaCargada = "/encender";

A Web API is supposed to be stateless. If you need to remember the last
page loaded, your whole protocol is most likely flawed.
On the JavaScript function Actualiza_Estado():
    var xxhr = new XMLHttpRequest();
    if (this.readyState == 4 && this.status == 200) {

The second line does not belong here: it should be within a
onreadystatechange handler. See how Lee_Nivel_Tanque() is written.

Edit: A few more remarks.
if(ultimaPaginaCargada == "/encender");

I previously wrote “If you need to remember the last page loaded, your
whole protocol is most likely flawed.” You may have misunderstood this
point. The problem is not that the server remembers which page was
loaded last. The problem is that its behavior depends on this
information. The server response should not depend on what page was
loaded last.
request->send(SPIFFS, "/index.html", String(), false, Procesador);

This looks fishy. I am not sure I fully understand your approach but,
from the little you show, it looks to me like you are building a
Web-based user interface for some device in the form of a
single-page application. In this approach, you have:

A single URL (typically the root: /) that delivers the user
interface in the form of a static HTML document, possibly with
embedded JavaScript.
Zero or more URLs that deliver static assets required by that
document: JavaScript, images, fonts…
One or more endpoints that let you interact with the device by either
retrieving JSON-formatted dynamic data (GET endpoints) or changing
the device's state (POST endpoints).

In this approach, the only instance where you may serve an HTML document
is in response to a GET / request. A dynamic data endpoint should
never deliver index.html.
xxhr.open("HTTP_GET", "/data-estado", true);

The HTTP method should be written "GET", not "HTTP_GET".

Hi @Edgar Bonet, thanks for the corrections, I didn't note that I  left that semicolon there, and thank you for the advice about the stateless api, I'll make some modifications and I'll let you know

and I must note that for Actualiza_Estado() I don't want an time interval, in addition, I know you are reffering to the the remembering of the last loaded page in my backend.cpp, at that time I didn't need to remember the pages, I just wanted to store the last loaded page. Following, the Actualiza_Estado() function is meant to show in the web page the state of the hardware part of my project, if is ON or OFF, etc.

and thank you for the 204 response advice


text:
18b20 dallastemperature
I can't compare for the condition Error "sensors not int type" translate to int type does not work. Please tell me the solution to this problem
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define ONE_WIRE_BUS 2
#define Rele 5

OneWire oneWire(ONE_WIRE_BUS);
LiquidCrystal_I2C lcd(0x27,16,2);
DallasTemperature sensors(&oneWire);

int tmp;
int PotenciometrPin = A0;
int val;

void setup(void)
{
 pinMode(Rele, OUTPUT);
 digitalWrite(Rele, HIGH);

 lcd.init();
 lcd.backlight();
}

void loop(void)
{
 lcd.setCursor(0, 0);
 sensors.requestTemperatures();
 val = analogRead(PotenciometrPin);
 lcd.print("Ustonovit`: ");
 val = map(val, 0, 1023, 0, 100);
 lcd.print(val);
 int(sensor);
 // if(val = sensors){ <-- THIS PROBLEM
 //digitalWrite(Rele, LOW);
 // }
 lcd.setCursor(0, 1);
 lcd.print("Fakt: ");
 lcd.print(sensors.getTempCByIndex(0));
 delay(1000);
}

What is this supposed to do? sensors is an object, you cannot compare it to a value. What are you trying to compare it to? Besides, it should be ==, not = for a comparison. And the line above the if is also useless.

Just look at the examples provided with that library (and look carefully at both the actual use and the setup parts).


text:
Raspberry pi pico (Arduino core) not initialising SPI correctly for NRF24l01
I'm working on a project where i have a Raspberry pi Pico connected to a NRF24l01+ to send some data.
However i'm not recieving any data on the reciever and i think that its because the SPI bus is not getting initialised propperly.
I have tested this code to try and troubleshoot the error
/*
  If your serial output has these values same then Your nrf24l01 module is in working condition :

  EN_AA          = 0x3f
  EN_RXADDR      = 0x02
  RF_CH          = 0x4c
  RF_SETUP       = 0x03
  CONFIG         = 0x0f

  This code is under public domain

  Last updated on 21/08/28
  https://dhirajkushwaha.com/elekkrypt
 */

#include <SPI.h>
#include <RF24.h>
#include <printf.h>

RF24 radio(12, 5);

byte addresses[][6] = {"1Node", "2Node"};

void setup() {
  Serial.begin(9600);
  delay(5000);
  SPI.begin();
  Serial.println("start");
  radio.begin();
  radio.setPALevel(RF24_PA_LOW);

  radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1, addresses[1]);
  radio.startListening();
  printf_begin();

  radio.printDetails();

}

void loop() {
//  empty

}

And i'm recieving this as output
start
SPI Speedz  = 10 Mhz
STATUS      = 0x00 RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=0 TX_FULL=0
RX_ADDR_P0-1    = 0x0000000000 0x0000000000
RX_ADDR_P2-5    = 0x00 0x00 0x00 0x00
TX_ADDR     = 0x0000000000
RX_PW_P0-6  = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA       = 0x00
EN_RXADDR   = 0x00
RF_CH       = 0x00
RF_SETUP    = 0x00
CONFIG      = 0x00
DYNPD/FEATURE   = 0x00 0x00
Data Rate   = 1 MBPS
Model       = nRF24L01+
CRC Length  = Disabled
PA Power    = PA_MIN
ARC     = 0

which doesnt look good...
I have checked the pins with my oscilloscope and appart from some activity on the CSN line i'm not seeing any data over the other pins at all. This is leading me to believe that the pico is not initialising the SPI bus in the correct way.
These are my connections:
VCC (nRF24L01) => 3.3V output (Raspberry Pi Pico).
GND (nRF24L01) => GND (Raspberry Pi Pico).
SCK (nRF24L01) => GP6 (Raspberry Pi Pico).
MOSI (nRF24L01) => GP7 (Raspberry Pi Pico).
MISO (nRF24L01) => GP4 (Raspberry Pi Pico).
IRQ (nRF24L01) => not connected
CE (nRF24L01) => GP12 (Raspberry Pi Pico).
CSN (nRF24L01) => GP5 (Raspberry Pi Pico

If anyone could help me out with this that would be greatly appreciated i need this thing to work really badly.

always format printout messages as code

If you are using the Arduino-Pico framework, the default SPI0 is not at the pins that you were expecting at, see the SPI0 pin assignments settings for the framework for generic Pico board, which is consists to the pin diagram of default SPI0.

@hcheung Hi, I am currently running into the same problem. I am using a diffrent core (platform io), but couldn't find any pins definition when exploring the files. Do you know if this also happens with other libraries ? Thanks

@BruceWawe, there are basically two popular Arduino Cores, ArduinoCore-mbed from Arduino C.C. and Arduino Pico core from Earle Philhower. Unfortunately PlatformIO only supports ArduinoCore-mbed. ArduinoCore-mbed pin definitions and supported boards can be find here.

@hcheung Many thanks ! I couldn't find the right GitHub !


text:
How to set the sampling frequency in Arduino without using a delay
I am reading an ECG signal using a single lead heart rate monitor. What I know is that when I use delay(15) it means that I am getting 66.67 readings in a second which corresponds to the sampling frequency. I want to set the sampling frequency to 250. This can be done by introducing delay(4).
What I really need is to set the sampling frequency to 250 Hz without introducing a delay in the code because I am acquiring ECG data in real time. Also, I am sending the data to python for processing and the delay will affect the sampling frequency in the time domain analysis.
any detailed solution or code ??
PS. I am using Arduino UNO
Code:
#define SERIAL_BUFFER_SIZE 8192
#include <SoftwareSerial.h>
unsigned long Time;
void setup() {

  // initialize the serial communication:

  pinMode(10, INPUT); // Setup for leads off detection LO +
  pinMode(11, INPUT); // Setup for leads off detection LO -
  Serial.println("CLEARDATA"); //clears up

  Serial.println("RESETTIMER"); //resets timer to 0

  Serial.begin(115200);

}

void loop() {
  if((digitalRead(10) == 1)||(digitalRead(11) == 1)){
   Serial.println('!');
  //  continue;
  }
  else{
   /*
     // send the value of analog input 0:
     int idata = analogRead(A0);
  //  float data = (idata*3.3)/1023;
      Serial.println(idata);
*/
  int sensorValue = analogRead(A0);
  float voltage = sensorValue * (3.3/1023.0);
  Serial.println(voltage);
  }
  //Wait for a bit
    delay(4);
}

You could also use a hardware timer to do this. E.g. use Timer1 to interrupt your code 250 times per second and take ADC measurement there. Also be aware of the ADCs conversion time, which can take about 100 us to execute. (Code see e.g. https://github.com/PaulStoffregen/TimerOne/blob/master/examples/Interrupt/Interrupt.pde)

There are many options, which have varying degrees of accuracy and complexity. The right one for you depends on how much timing accuracy you require. See Getting a fixed sampling rate, which your question is almost a duplicate of.

Use the concept of blink without delay.
Instead of using delay() to set the timeout you use a timestamp and check micros() against that to see whether your interval has passed:
const unsigned long READ_PERIOD = 4000;  // 4000 us: 250 Hz

void loop() {
    static unsigned long lastRead;
    if (micros() - lastRead >= READ_PERIOD) {
        lastRead += READ_PERIOD;
        if (digitalRead(10) == 1 || digitalRead(11) == 1)
            Serial.println('!');
        else
            Serial.println(analogRead(A0) * (3.3/1024));
    }
}

I took the liberty to do a few edits: use micros() instead of millis(), as the latter has 1 ms of jitter; write lastRead += READ_PERIOD instead of lastRead = now to prevent creeping drift; a few simplifications.

Thanks for your answer. I have tried the code, however, it gave sampling frequency 125 Hz. I tried playing with the READ_PERIOD and I found that 2000 gave sampling frequency of 250 Hz. What does this number stand for and what concept or equation is being used ?   Many thanks !!

(1000000 / 4000) == 250  If 2000 works your timing is off.

@dandavis  can you please specify the units of the baud rate and the reading period. it is  (bps / us  = hz) ??    Thanks


text:
data streaming using Bluetooth + RFduino
I am trying to send ECG data using RFduino. I am using two RFduino modules. The transmitter module is using the device code while the receiver is using the host code. I have common baud rate between the two modules which is 250k. I have an issue with the first data that comes to the receiver . Always a question mark is displayed in the beginning as shown in the figure below:

I do not want this question mark to appear at the beginning because it is making issues in the analysis side.
Codes:
device:
/*
This sketch demonstrates how to send structured data from a Device
to a Host in a Gazell network.

Written by (VLorz) Victor Lorenzo.

You are free to use this code.
*/

#include <RFduinoGZLL.h>
#include "myStruct.h"

/* This instance will be sent over GZLL */
static my_struct_t  theStruct;

/* And this variable is for timing */
static long PrevTime;

/* It would be nice to know if the host received the packet */
static bool   Acked;
static int    AckedCount;

void setup()
{
  // Initialize the structure to a known state;
  //theStruct.OneByte = 1;
  //theStruct.OneDWord = 0x02030405;
  theStruct.ECG = 0x0000;
  //theStruct.Count = 0;
  Serial.begin(250000);
  //pinMode(3, INPUT); // Setup for leads off detection LO +
  //pinMode(2, INPUT); // Setup for leads off detection LO -
  Serial.println("CLEARDATA"); //clears up

  Serial.println("RESETTIMER"); //resets timer to 0
  // start the GZLL stack;
  Serial.print( F("GZLL init...") );
  Serial.println( RFduinoGZLL.begin( DEVICE0 ) );

  Serial.println( F("Running") );

  /* Force the first xmit */
  PrevTime = millis() - 1001;
  Acked = false;
}

void loop()
{
  long  Now;

  Now = millis();

  if (4 <= Now - PrevTime) {
    Acked = false;

    // This is simply for making something change;
    theStruct.Count++;
    theStruct.ECG  = analogRead(2);
    // So we send the struct to the host;
    RFduinoGZLL.sendToHost( (char*)&theStruct, sizeof(theStruct) );

    PrevTime = Now;
  }

  if (Acked) {
    Acked = false;
    //Serial.print( "Ack received for Count = " );
    //Serial.println( AckedCount );
    Serial.println(theStruct.ECG );
  }
}

void RFduinoGZLL_onReceive(device_t device, int rssi, char *data, int len)
{
  // What we expect here is the host sending the value in the Count field from
  // the structure we have sent;
  if (len == 1)
    AckedCount = (uint8_t)*data;
  else
    AckedCount = -1;

  Acked = true;
}

The host:
/*
This sketch demonstrates how to send structured data from a Device
to a Host in a Gazell network.

Written by (VLorz) Victor Lorenzo.
You are free to use this code.
*/

#include <RFduinoGZLL.h>
#include "myStruct.h"

/* This instance will be filled with data received over GZLL */
static my_struct_t  theReceivedStruct;

/* It would be nice to know if the host received the packet */
static bool   DataReady;

void setup()
{
  Serial.flush();
  Serial.begin(250000);

  // start the GZLL stack;
 // Serial.print( F("GZLL init...") );
  Serial.println( RFduinoGZLL.begin( HOST ) );
  //Serial.println( F("Running") );

  DataReady = false;
}

void loop()
{
  if (DataReady) {
    //Serial.println( "Data received!!!" );
    //Serial.print( F("OneWord=") );
    Serial.println( theReceivedStruct.ECG, DEC );
    //Serial.print( F("Count=") );
    //Serial.println( theReceivedStruct.Count );
   // Serial.println( "" );
    DataReady = false;
  }
}

void RFduinoGZLL_onReceive(device_t device, int rssi, char *data, int len)
{
  //
  // IMPORTANT!!! This function runs under interrupt context!!!
  //

  if (DataReady) {
    // Do not overwrite our buffer;
    return;
  }

  if (len != sizeof(theReceivedStruct)) {
    // Ignore packets with wrong length!!!
    return;
  }

  // Copy the data to our structure buffer;
  for (char* lpDest = (char*)&theReceivedStruct; len > 0; len--) {
    *lpDest = *data;
    lpDest++;
    data++;
  }

  // ...and signal the application the data is ready
  DataReady = true;

  RFduinoGZLL.sendToDevice( device, theReceivedStruct.Count );
}

Can you include the output with all of the debugging un-commented on the host?

@Craig  what do you mean .?  To remove the comments of serial commands  in the setup() or loop ??

Yes. uncomment the Serial.print and Serial.println lines in both setup() and loop().  That extra output will be useful in debugging the problem.


text:
Custom LED toggling function: one out of three LEDs misbehave
I connected three LEDs to an Arduino Uno and wrote a simple LED class. I toggle all the leds the main loop, but for some reason one led (connected to pin7) always misbehaves, skips one toggle or stays on all the time. Initially all leds are off (in begin() function). What could cause this problem?
main.cpp
#include "led.h"
#include <Arduino.h>

Led leds[] = {
    Led(2),
    Led(3),
    Led(7)
};

void setup()
{
    Serial.begin(9600);
    for (Led& l : leds) l.begin();
}

void loop()
{
    for (Led &l : leds) l.toggle();
    delay(500);
}

Led.h
class Led {
public:
    Led(int pin);
    void begin();
    void toggle();

private:
    const int _pin;
};

Led.cpp
#include "led.h"
#include "Arduino.h"

Led::Led(int pin) : _pin(pin)
{}

void Led::begin()
{
    pinMode(_pin, OUTPUT);
    digitalWrite(_pin, LOW);
}

void Led::toggle()
{
    digitalWrite(_pin, !digitalRead(_pin));
}

Check the wiring; there's no particular reason this would be an issue specifically with that pin unless there's a wiring or electrical issue (which can be internal). Note that digitalRead returns an int, not a bool, and IMO should be coded as such to avoid breaking changes or cross-architecture issues.

Aha okay, the Arduino I'm using has been through alot so I will verify this with a new one soon. It could be faulty. But what exactly do you mean that "it should be coded as such"? Should I explicitly cast it to a bool? Or write it the "long way", checking if digitalRead==0 or ==1?

Re: the latter; it's (incrementally) safer to check against HIGH (or LOW) and use a conditional op. I forget the thread that led me to think this could be a potential issue moving forward--something on the Arduino forums. Sorry--it's probably not a big deal, either.

Got cranky and found it: https://forum.arduino.cc/t/does-digitalread-on-an-output-pin-return-the-last-state-it-was-set-to/437863

It's safer for your class to have an internal record of the LED state instead of relying on digitalRead() to give you the right result.

Okay, I was considering this option as well. Could you point me to some resources or explanations what is the reasoning behind it? What do you mean by "safer"?

It seems to be a hardware fault, as others have suggested:
I connected the LED to another pin(8) and it works perfectly, everytime.
Looks like something got fried internally on that specific pin


text:
Correctly Powering Lilypad Arduino
I am trying to correctly power a Lilypad Arduino that is attached with an HC-05, Lilypad temp sensor, and Amped pulse sensor. So far I have found that powering by plugging the Lilypad into my laptop and using three coin cells in parallel will allow for the Pulse sensor and Temp sensor to function properly. When I attach the HC-05, the readings become extremely incorrect. To remedy this, I attached the HC-05 to a 9v battery.
As I'm sure you can tell, I am novice to say the least. How can I properly power these components without damaging them. Thank you.
Update : I failed to tweak the program to reflect voltage change when disconnected from laptop. Temperature data much better and BPM is correct. Only issue that remains is the question of how to safely power all components through Lilypad. Thanks again.

a standard 9V battery is one of the weakest batteries available ... it is 6 AAAA cells in series, which makes the available current is very low

@KingDuken You are correct, the Lilypad probably isn't designed for this but, in theory, I would expect the only limitation to be power supply.

@jsotola Would it be safe to assume that my issue has to do with current rather than voltage? If so, would you recommend more current into the Arduino or simply powering the components independently from the Arduino? I'm not certain of the limitations of the device.

@SimonMarcoux That makes sense. I only run into issues when I want to use the HC-05 along with the sensors, when powering it separately, I have no issues. Thank you for the insight.