text:
Controlling an MCP41HV31 Digital Potentiometer
I need to control a 10kOhm digital potentiometer in rheostat mode in 256 steps. I found an Arduino tutorial, which works with an MCP41010 (I added a viper resistance according to the datasheet). This works fine - I can send values from 0 to 255 to the CS pin an the resistance between output pin A and B changes from 0 to 10kOhm.
The problem is, that my application requires 16V to go through this resistance, which the MCP41010 can't handle.
I tried to go with a MCP41HVX1 high voltage digital potentiometer (which I soldered on a TSSOP-to-DIP Breakout board) and assumed it would work the same way. Turns out it doesn't... My connections are:
Arduino nano -> MCP41HVX1

10 -> CS
11 -> SDI
13 -> SCK
5V -> VL
GND -> DGND

With the MCP41010 I connect a 115Ohm viper resistor between output pin A and wiper terminal and measure resistance between output pin A and B (pink connectors). I noticed, that the MCP41HVX1 has a different description for the rheostat modus but I can't get that to work either.
This is my circuit that works with the MCP41010

And here is the respective code (which sets the MCP41010 to 255 i.e. 10kOhm)

#include <SPI.h>
byte address = 0x11;
int CS= 10;

void setup()
{
  pinMode (CS, OUTPUT);
  SPI.begin();
}

void loop()
{
  digitalPotWrite(255, CS);

}

int digitalPotWrite(int value, char Port)
{
  digitalWrite(Port, LOW);
  SPI.transfer(address);
  SPI.transfer(value);
  digitalWrite(Port, HIGH);
}

Has anyone ever done this or has a clue what's going on?

I was not allow to post all necessary links in the original post. Here is the tutorial for the MCP41010 and it's datasheet.

Well, for a start your wiring is wrong. Look at the pinout of the HV version. You're not connecting to the pot pins with your pot wires (or not all of them) and you aren't providing the proper V+ and V- voltages.

Pin 14 should go to +16V, pin 10 to GND, and 11-13 are your pot pins.

Sorry, I got it wrong in the graphic, of course the outputs are pin 11 and 13. Connecting pin 14 to +16V didn't change much. Right now I'm not even trying to run 16V through the resistance but measure it with an oscilloscope.

I realize that this thread is old. I am providing an answer for anyone else who may end up here like I did a while back looking to solve this.
I have created an Arduino library on Github (https://github.com/gregsrabian/MCP41HVX1) which allows for control of this family of chips. The README.md within the github project documents all of the APIs and also provides the wiring diagram. There are also example sketches included.
I have created an article on Instructables (https://www.instructables.com/id/MCP41HVX1-Digital-Potentiometer-for-Arduino/) that provides a step by step on how to control this family of chips. There is also an explanation on how to solder the TSSOP chip.

One thing I discovered, after coming back to the internet multiple times for clues, is that that SHDN pin on the MCP41HVX1 has to be tied HIGH.
If not, you can try incrementing, decrementing, or writing values to your heart's content and the thing is not going to budge.
I tied SHDN to the VL level via a 10k resistor and I can write and increment without problems.
I think it should have been flagged in the datasheet though, in the Pinout Description table.


text:
Serial monitor returns "48" when I enter "0"
I am going through an Arduino Learning Book(978-1-59327-448-1) and I've run into the same issue twice now.
When I enter data into the serial monitor, the number that it reads and displays(when asked to print) is way different than what I'm entering.
In diagnosing the problem, I went to https://www.arduino.cc/en/Serial/Read
Copied the code into a new sketch, and tried to run it.
When I Enter 0, I get 48, and a second line saying 10. Enter 1, I get 49 and 10, etc. Here are the results when I enter 0, then 1, then 2, then 3
I received: 48
I received: 10
I received: 49
I received: 10
I received: 50
I received: 10
I received: 51
I received: 10
here is the code I'm using
int incomingByte = 0;   // for incoming serial data

void setup() {
    Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
}

void loop() {

    // send data only when you receive data:
    if (Serial.available() > 0) {
            // read the incoming byte:
            incomingByte = Serial.read();

            // say what you got:
            Serial.print("I received: ");
            Serial.println(incomingByte, DEC);
    }
}

I have the serial monitor set to 9600.
All sketches have worked fine so far, including those that use Serial.print functions, but when I use Serial.read, things seem to get screwed up.
I'm sure I'm missing something stupid, but I've googled around and all the answers are much higher level than just trying to run the code in the Arduino.cc example
Thanks in advance for helping a first timer!
PS: I Tried to get all of the code into the grey box with various line spacing and indenting strategies, but it's not perfect. Does anyone have any tips on that?

You just missed this.

Please explain further. I was wondering if its wanting ASCII input instead of regular numbers, but the code in my book, and that site doesn't make any special provisions for or mention of different input styles.

you are seeing the ascii code of the char you fed it. you can use Serial.print((char)49); to coerce it back into 1

Comments under questions are for clarifying the question, not answering it. Please make an answer if you wish to answer, which has the benefit that you get reputation if it is voted up or accepted.

I Tried to get all of the code into the grey box with various line spacing and indenting strategies, but it's not perfect. - what grey box? In what way isn't it perfect? Do you mean the forum or the Arduino IDE?

ok now i see, its reading as "symbol" on that linked page or "char" elsewhere, and storing the associated ASCII Code. I can trick it into toring anything down to 33 with "!" as the answer, but for the sketch in the book i need it to store values from 0 to 255(Im playing a guessing game with the board). So whats my workaround for that? The book just expects their code to magically work, and the code looks similar to arduino.cc Lastly where does that extra "10" come from? as in "I received: 10" in the serial monitor(original arduino.cc example)

@nick, the grey box on this page. In my original question.... wait nevermind, now it all in the box, it wasnt before i asked the question. but for reference, the code after my line "here is the code im using" and thank you again to all

@Mechanical-ish  About the "the grey box on this page". That was me. I edited your question so the entire sketch fit in to a "Code Sample". You can highlight a sketch and format it using the "Ctrl+K" keyboard short cut, insert 4 blank spaces in front of each line of code, or highlight the sketch then click the "{}" link in the editor.

           Serial.println(incomingByte, DEC);

You told it to print the incoming byte in decimal, so that is what it did. 48 is the decimal equivalent of ASCII '0'.
Change that line to:
Serial.println((char) incomingByte);

That casts the thing you are printing to a character, and then the appropriate version of Serial.println prints it as a character, not a decimal number.

10 is the decimal equivalent of a new line (newline) so that is why you are also seeing 10 printed.

I need to convert the incoming stuff into integers so that it can see if im guessing right or not

Assuming you mean an integer other than 0 to 9 (like, 42 for example) then you need a bit more work. I have a page about that sort of thing:
http://www.gammon.com.au/serial
Example code:
/*
Example of processing incoming serial data without blocking.

Author:   Nick Gammon
Date:     13 November 2011.
Modified: 31 August 2013.

Released for public use.
*/
// how much serial data we expect before a newline
const unsigned int MAX_INPUT = 50;

void setup ()
  {
  Serial.begin (115200);
  } // end of setup

// here to process incoming serial data after a terminator received
void process_data (const char * data)
  {
  // for now just display it
  // (but you could compare it to some value, convert to an integer, etc.)
  Serial.println (data);
  }  // end of process_data

void processIncomingByte (const byte inByte)
  {
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
    {

    case '\n':   // end of text
      input_line [input_pos] = 0;  // terminating null byte

      // terminator reached! process input_line here ...
      process_data (input_line);

      // reset buffer for next time
      input_pos = 0;
      break;

    case '\r':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;

    }  // end of switch

  } // end of processIncomingByte

void loop()
  {
  // if serial data available, process it
  while (Serial.available () > 0)
    processIncomingByte (Serial.read ());

  // do other stuff here like testing digital input (button presses) ...

  }  // end of loop

In this example, the function process_data is called when there is a complete number to be handled.

Ok i changed it as you suggested, and got "I received: 1
I received: " so thats working for printing the number i enter, still confused as to why its printing that extra line. Also, when i go back to the guessing game in the book, i need to convert the incoming stuff into integers so that it can see if im guessing right or not.

The extra line is the linefeed you are echoing back. You will have configured the terminal monitor to send a linefeed after pressing Send.

You can use Serial.parseInt() to read a number sent from Serial Monitor. parseInt waits for all numeric characters of the sent text, so it blocks the execution of your sketch for a very short time until all characters are received. At higher baud rate it will be faster. If your sketch doesn't need to loop as fast as possible, then you can use it. parseInt stops at first character that is not a digit (for example a newline character) and returns the received number as long.
void setup() {
  Serial.begin(115200);
}

void loop() {
  if (Serial.available() > 0) {
    long number = Serial.parseInt();
    Serial.println(number);
  }
}

source: Stack Exchange

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

sort: votes


text:
Writing to sd card with a sampling rate 50ms or less? I have a sketch that writes to sd every 1s but jams at faster sampling rates. Please help?
My code below reads data from an ADC and 3 digital pins via a Mega and prints to an SD Shield (Deek Robot). I want to be able to read the data every 50ms (20ms ideally). I can't get below 250ms.
I've read countless forum posts regarding the same issue and understand that I need to create 2x 512 byte buffer, store data to one while the other is being written to the SD card. A forum post mentioned using the Adafruit GPS library for an example of double-buffering but I can't seem to find it. Another suggests changing the internal buffer from 64bytes to 256bytes in hardwareserial.cpp but I can't even navigate to it on my w***ows laptop.
I've run dataString.Length and the max length is 38 for the 8 columns of data, plus a long (for recording ms) another byte for the "\t" and 3 bytes of headroom = 46bytes in all, round it up to 50bytes/sample at a 50ms sampling rate is 1000bytes/second. Darn it, I forgot to add the separating-commas between the columns = plus another 7 bytes; call it 55 in total = 1100bytes/second. I know it can be done but I can't do it; not at my current knowledge/skill level.
Thank you in advance for your help.

//include relevant libraries
#include <EnableInterrupt.h>
#include <SPI.h>
#include <SD.h>

//globally define pins
#define BUSY 3    //purple*
#define RD 4      //yellow* RD+CS tied together
#define RESET 5   //grey*
#define CONVST 6  //green* CONVSTA+CONVSTB soldered together on the board
#define RANGE 7   //blue*   *not permanent - double check!!!*

#define DB0 22
#define DB1 23
#define DB2 24
#define DB3 25
#define DB4 26
#define DB5 27
#define DB6 28
#define DB7 29
#define DB8 30
#define DB9 31
#define DB10 32
#define DB11 33
#define DB12 34
#define DB13 35
#define DB14 36
#define DB15 37

//byte statusLed       = 13;
byte sensorPin1       = 38;
byte sensorPin2       = 40;
byte sensorPin3       = 42;

int sensorValue[8];
int rawData[16];
//change the size  of these arrays to match the amount of channels being read by the ADC
int adcChannel[5];
int adcData[5];
int channelCount=5;

volatile byte pulseCount1;
volatile byte pulseCount2;
volatile byte pulseCount3;

int pulses[3];

// cs pin for sd-shield *NB 53 for Mega
const int chipSelect = 53;
// SCK 52
// MISO 50
// MOSI 11

unsigned long oldTime;

void setup() {             //set up the hardware

  Serial.begin(9600);
  //sd card.....
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }
  Serial.println("card initialized.");

  enableInterrupt(BUSY, bitBang, FALLING);

  oldTime            = 0;

  pinMode(DB0, INPUT_PULLUP);
  pinMode(DB1, INPUT_PULLUP);
  pinMode(DB2, INPUT_PULLUP);
  pinMode(DB3, INPUT_PULLUP);
  pinMode(DB4, INPUT_PULLUP);
  pinMode(DB5, INPUT_PULLUP);
  pinMode(DB6, INPUT_PULLUP);
  pinMode(DB7, INPUT_PULLUP);
  pinMode(DB8, INPUT_PULLUP);
  pinMode(DB9, INPUT_PULLUP);
  pinMode(DB10, INPUT_PULLUP);
  pinMode(DB11, INPUT_PULLUP);
  pinMode(DB12, INPUT_PULLUP);
  pinMode(DB13, INPUT_PULLUP);
  pinMode(DB14, INPUT_PULLUP);
  pinMode(DB15, INPUT_PULLUP);

  pinMode(RESET, OUTPUT);
  pinMode(CONVST, OUTPUT);
  pinMode(RD, OUTPUT);
  pinMode(RANGE, OUTPUT);
  pinMode(BUSY, INPUT);

  //reset ADC to begin conversion
  digitalWrite(RESET, HIGH);
  delayMicroseconds(10);
  digitalWrite(RESET, LOW);

  digitalWrite(CONVST, LOW);
  digitalWrite(RD, HIGH);
  digitalWrite(RANGE, LOW);
  digitalWrite(BUSY, LOW);

  delayMicroseconds(100);

  // Set up the status LED line as an output
//  pinMode(statusLed, OUTPUT);
//  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  pinMode(sensorPin1, INPUT);
  digitalWrite(sensorPin1, HIGH);

  pinMode(sensorPin2, INPUT_PULLUP);
  digitalWrite(sensorPin2, HIGH);

  pinMode(sensorPin3, INPUT_PULLUP);
  digitalWrite(sensorPin3, HIGH);

  pulseCount1        = 0;
  pulseCount2        = 0;
  pulseCount3        = 0;

  oldTime            = 0;

  // the hall effect sensors are configured to trigger on a FALLING state change
  // (transition from HIGH state to LOW state)
  enableInterrupt(sensorPin1, pulseCounter1, FALLING);
  enableInterrupt(sensorPin2, pulseCounter2, FALLING);
  enableInterrupt(sensorPin3, pulseCounter3, FALLING);

}

void loop() {

  //change this value to preffered sampling rate
  if ((millis() - oldTime) == 50) {

    oldTime = millis();

    //Serial.print(millis());
    //Serial.print("\t");

    //tell ADC to start read (converting analogue input to digital output)
    delayMicroseconds(10);
    digitalWrite(CONVST, LOW);
    delayMicroseconds(10);
    digitalWrite(CONVST, HIGH);
    //when read-conversion is complete ADC sends the BUSY pin low triggering the bitBang ISR

    //print ADC data from array within the bitBang ISR to a string
    String adcString = "";
    for(int thisChannel=0; thisChannel<channelCount; thisChannel++){
      adcString += String(adcData[thisChannel]);
      adcString += ",";
    }

    //disable interrupt to access current pulse count
    disableInterrupt(sensorPin1);
    disableInterrupt(sensorPin2);
    disableInterrupt(sensorPin3);
    //grab current pulse count and store in a variable
    pulses[0] = pulseCount1;
    pulses[1] = pulseCount2;
    pulses[2] = pulseCount3;
    //reset pulse count
    pulseCount1 = 0;
    pulseCount2 = 0;
    pulseCount3 = 0;
    //enable interrupt and start incrementing pulse count again
    enableInterrupt(sensorPin1, pulseCounter1, FALLING);
    enableInterrupt(sensorPin2, pulseCounter2, FALLING);
    enableInterrupt(sensorPin3, pulseCounter3, FALLING);

    String pulseString = "";
    for(int i=0; i<3; i++){
      pulseString += String(pulses[i]);
      if (i<2) {
        pulseString += ",";
      }
    }

   String dataString = String(adcString + pulseString);
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("dataLog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.print(millis());
    dataFile.print(",");
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    //Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening dataLog.txt");
  }

 //Serial.println(dataString);

  }
//start again
}

//grabbing ADC data ISR (for n channel)
void bitBang ()  {
  //a for loop to bitbang the values fom the analogue (ADC) channels (maximum 8) sequentially storing them in a variable array (equal to the channels of the ADC)
  for(int thisChannel=0; thisChannel<channelCount; thisChannel++){
  //send ADC read pin low to bitbang the first channel
  digitalWrite(RD, LOW);
  //read the state of the 16 pins and store in a variable
  rawData[0] = digitalRead(DB15);
  rawData[1] = digitalRead(DB14);
  rawData[2] = digitalRead(DB13);
  rawData[3] = digitalRead(DB12);
  rawData[4] = digitalRead(DB11);
  rawData[5] = digitalRead(DB10);
  rawData[6] = digitalRead(DB9);
  rawData[7] = digitalRead(DB8);
  rawData[8] = digitalRead(DB7);
  rawData[9] = digitalRead(DB6);
  rawData[10] = digitalRead(DB5);
  rawData[11] = digitalRead(DB4);
  rawData[12] = digitalRead(DB3);
  rawData[13] = digitalRead(DB2);
  rawData[14] = digitalRead(DB1);
  rawData[15] = digitalRead(DB0);
  //convert into 16bit 2s compliment and store in a variable array
  adcData[thisChannel] = rawData[0] | (rawData[1] << 1) | (rawData[2] << 2) | (rawData[3] << 3) | (rawData[4] << 4) | (rawData[5] << 5) | (rawData[6] << 6) | (rawData[7] << 7) |  (rawData[8] << 8) | (rawData[9] << 9) | (rawData[10] << 10) | (rawData[11] << 11) | (rawData[12] << 12) | (rawData[13] << 13) | (rawData[14] << 14) | (rawData[15] << 15);
  //send ADC pin high to say we have read the first channel
  digitalWrite(RD, HIGH);
  //repeat for n channels
  }
}

//counting pulses ISRs
void pulseCounter1(){
  // Increment the pulse counter
  pulseCount1++;
}
void pulseCounter2(){
  // Increment the pulse counter
  pulseCount2++;
}
void pulseCounter3(){
  // Increment the pulse counter
  pulseCount3++;
}

if ((millis() - oldTime) == 50) { .... what happens if the program briefly hangs up and misses the 50ms difference?

Did you think about jsotola's comment? If not, I suggest you think about it very very carefully. The advice in the answer below is good advice, but it might just be the comment  that saves you - and exposes a new problem when you realise the answer....

I'm running tests on it now. Do you know what? As little as 10 days ago that part of code said if ((millis() - oldTime >= 50) { and it has said that for months. I don't know when or how the double equal crept in. I'll let you know the outcome soon. Thanks

Yeah, that seems to have fixed the issue. Absolutely kicking myself for somehow  adding in the bug without realising it, oh well, humanum est errare as the old saying goes. Thank you for everyone for your help, especially to the person that voted my question up thus awarding me enough reputation to comment everywhere - a very special day for me. What is the etiquette here? I can't accept a comment as an answer so should I accept the @Michel Keijzer one? thanks again

So it turns out the actual problem was this line of code
if ((millis() - oldTime) == 50) {
it needed to be changed to
if ((millis() - oldTime >= 50) {
I really appreciate all the help everyone gave me to get to the bottom of it and especially thankful to @Michel for handing some solid advice to someone who isn't in the know.
Hopefully I will be able to repay in kind to another learner one day.
:D

Some tips:

Do not open the open and close the file in every loop sequence (I think you can use the flush command to save/update the file.
Do not save strings, but save the raw data and pulse string. This will take 16 * 2 (raw data + 3 bytes for the pulse data = 35 bytes per 16 samples, meaning 35 bytes/samples * 20 samples/s = 700 bytes (I think your calculation of 1100 bytes is incorrect).
Try to avoid string, and even more string concatenation. I don't know if this will be the bottleneck, but in any case String operations are expensive and for concatenation there is a chance (or is always the case) that memory needs to be allocated dynamically. Use a string buffer instead.

Thanks for your suggestions. I have read about strings being problematic, and the C string class should be used instead. I will implement the first 2 bulletpoints today but will have to do a bit of research before taking on the third. i will kyp.

File I/O operations are normally quite expensive, so it's good to keep them to a minimum. The third point might be a bit more work, but except for very simple sketches, try using C string (char* instead). Tip: to test with the C strings, do not use an Arduino, but do it on a PC, that's much more quicker, than if the code works or you know how c strings work, move it to the Arduino IDE.

OK, so I use command prompt on my laptop?

No, I suggest you install either Visual Studio 2019 or Eclipse C(++) ... both are free. You create your non Arduino specific code on the PC with either those two IDEs, and when it works you copy it to the Arduino IDE. The advantage is that you can use debugging and you don't have to upload the program/sketch every time.

That's great advice, I'm definitely gonna take it :) Thanks again.

@Microk It's especially useful if you make large programs.

UPDATE: I have got rid of all the strings completely. I can't seem to initiate the flush without the sd card crashing after a short while, 0-2 mins. But I have stable code that does exactly what I wanted to. So thanks again for all the help

You're welcome ... and if the program works stable, don't change it (you always can add a remark/todo  for the flush in case you run in problems next time).

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


text:
I cannot open/write to dataFile SD shield in mySketch but have no problem with Datalogger example sketch from the SD library...?
Hello Arduino Community
I am collecting data and attempting to log it on to a Deek Robot SD shield via a Mega.
I have the data  in a dataString which I can Serial.print to the monitor but would like to log it to an SD card instead. When I run the the Datalogger example sketch from the SD library I can see the data and access the datalog file from the SD card (as per point of the example) but when I try to cross-pollinate the example with mySketch the debugging message

error opening datalog.txt

is all I get.
I've uploaded the sketch, apologies it is pretty long, there's some adc stuff going on, the call for the data file open and write etc starts on line 200 and ends on 212.
I've tried positioning the datafile functions in different places in the code, using other libraries, reading forum posts but I am getting nowhere. if anyone could point out what I'm doing wrong I would be eternally grateful.
Cheers,
Michael

//!!!change this to name of sketch!!!!
#define SKETCH_VERSION "SD for loop array test"

//include relevant libraries
#include <EnableInterrupt.h>
#include <SPI.h>
#include <SD.h>

//globally define pins
#define BUSY 3    //purple*
#define RD 4      //yellow* RD+CS tied together
#define RESET 5   //grey*
#define CONVST 6  //green* CONVSTA+CONVSTB soldered together on the board
#define RANGE 7   //blue*   *not permanent - double check!!!*

#define DB0 38
#define DB1 39
#define DB2 40
#define DB3 41
#define DB4 42
#define DB5 43
#define DB6 44
#define DB7 45
#define DB8 46
#define DB9 47
#define DB10 48
#define DB11 49
#define DB12 50
#define DB13 51
#define DB14 52
#define DB15 53

byte statusLed       = 13;
byte sensorPin1       = 10;
byte sensorPin2       = 11;
byte sensorPin3       = 12;

int sensorValue[8];
int rawData[16];

//change the size  of these arrays to match the amount of channels being read by the ADC
int adcChannel[5];
int adcData[5];
int channelCount=5;

volatile byte pulseCount1;
volatile byte pulseCount2;
volatile byte pulseCount3;

int pulses[3];

// cs pin for sd-shield *NB 53 for Mega
const int chipSelect = 53;

unsigned long oldTime;

void setup() {             //set up the hardware

  Serial.begin(9600);
  //sd card.....
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }
  Serial.println("card initialized.");

  enableInterrupt(BUSY, bitBang, FALLING);

  oldTime            = 0;

  pinMode(DB0, INPUT_PULLUP);
  pinMode(DB1, INPUT_PULLUP);
  pinMode(DB2, INPUT_PULLUP);
  pinMode(DB3, INPUT_PULLUP);
  pinMode(DB4, INPUT_PULLUP);
  pinMode(DB5, INPUT_PULLUP);
  pinMode(DB6, INPUT_PULLUP);
  pinMode(DB7, INPUT_PULLUP);
  pinMode(DB8, INPUT_PULLUP);
  pinMode(DB9, INPUT_PULLUP);
  pinMode(DB10, INPUT_PULLUP);
  pinMode(DB11, INPUT_PULLUP);
  pinMode(DB12, INPUT_PULLUP);
  pinMode(DB13, INPUT_PULLUP);
  pinMode(DB14, INPUT_PULLUP);
  pinMode(DB15, INPUT_PULLUP);

  pinMode(RESET, OUTPUT);
  pinMode(CONVST, OUTPUT);
  pinMode(RD, OUTPUT);
  pinMode(RANGE, OUTPUT);
  pinMode(BUSY, INPUT);

  //reset ADC to begin conversion
  digitalWrite(RESET, HIGH);
  delayMicroseconds(10);
  digitalWrite(RESET, LOW);

  digitalWrite(CONVST, LOW);
  digitalWrite(RD, HIGH);
  digitalWrite(RANGE, LOW);
  digitalWrite(BUSY, LOW);

  delayMicroseconds(100);

  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  pinMode(sensorPin1, INPUT);
  digitalWrite(sensorPin1, HIGH);

  pinMode(sensorPin2, INPUT_PULLUP);
  digitalWrite(sensorPin2, HIGH);

  pinMode(sensorPin3, INPUT_PULLUP);
  digitalWrite(sensorPin3, HIGH);

  pulseCount1        = 0;
  pulseCount2        = 0;
  pulseCount3        = 0;

  oldTime            = 0;

  // the hall effect sensors are configured to trigger on a FALLING state change
  // (transition from HIGH state to LOW state)
  enableInterrupt(sensorPin1, pulseCounter1, FALLING);
  enableInterrupt(sensorPin2, pulseCounter2, FALLING);
  enableInterrupt(sensorPin3, pulseCounter3, FALLING);

  //this prints the name of the sketch !!!read line 1!!!
  Serial.print("sketch version: ");
  Serial.println(SKETCH_VERSION);

}

void loop() {
  //Serial.print("hello");
  //change this value to preferred sampling rate
  if ((millis() - oldTime) == 1000) {

    oldTime = millis();

    //Serial.print(millis());
    //Serial.print("\t");

    //tell ADC to start read (converting analogue input to digital output)
    delayMicroseconds(10);
    digitalWrite(CONVST, LOW);
    delayMicroseconds(10);
    digitalWrite(CONVST, HIGH);
    //when read-conversion is complete ADC sends the BUSY pin low triggering the bitBang ISR

    //print ADC data from array within the bitBang ISR to a string
    String adcString = "";
    for(int thisChannel=0; thisChannel<channelCount; thisChannel++){
      adcString += String(adcData[thisChannel]);
      adcString += ",";
    }

    //disable interrupt to access current pulse count
    disableInterrupt(sensorPin1);
    disableInterrupt(sensorPin2);
    disableInterrupt(sensorPin3);
    //grab current pulse count and store in a variable
    pulses[0] = pulseCount1;
    pulses[1] = pulseCount2;
    pulses[2] = pulseCount3;
    //reset pulse count
    pulseCount1 = 0;
    pulseCount2 = 0;
    pulseCount3 = 0;
    //enable interrupt and start incrementing pulse count again
    enableInterrupt(sensorPin1, pulseCounter1, FALLING);
    enableInterrupt(sensorPin2, pulseCounter2, FALLING);
    enableInterrupt(sensorPin3, pulseCounter3, FALLING);

    String pulseString = "";
    for(int i=0; i<3; i++){
      pulseString += String(pulses[i]);
      if (i<2) {
        pulseString += ",";
      }
    }

    String dataString = String(adcString + pulseString);
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }

 //Serial.println(dataString);

  }
//start again
}

//grabbing ADC data ISR (for n channel)
void bitBang ()  {
  //a for loop to bitbang the values fom the analogue (ADC) channels (maximum 8) sequentially storing them in a variable array (equal to the channels of the ADC)
  for(int thisChannel=0; thisChannel<channelCount; thisChannel++){
  //send ADC read pin low to bitbang the first channel
  digitalWrite(RD, LOW);
  //read the state of the 16 pins and store in a variable
  rawData[0] = digitalRead(DB15);
  rawData[1] = digitalRead(DB14);
  rawData[2] = digitalRead(DB13);
  rawData[3] = digitalRead(DB12);
  rawData[4] = digitalRead(DB11);
  rawData[5] = digitalRead(DB10);
  rawData[6] = digitalRead(DB9);
  rawData[7] = digitalRead(DB8);
  rawData[8] = digitalRead(DB7);
  rawData[9] = digitalRead(DB6);
  rawData[10] = digitalRead(DB5);
  rawData[11] = digitalRead(DB4);
  rawData[12] = digitalRead(DB3);
  rawData[13] = digitalRead(DB2);
  rawData[14] = digitalRead(DB1);
  rawData[15] = digitalRead(DB0);
  //convert into 16bit 2s compliment and store in a variable array
  adcData[thisChannel] = rawData[0] | (rawData[1] << 1) | (rawData[2] << 2) | (rawData[3] << 3) | (rawData[4] << 4) | (rawData[5] << 5) | (rawData[6] << 6) | (rawData[7] << 7) |  (rawData[8] << 8) | (rawData[9] << 9) | (rawData[10] << 10) | (rawData[11] << 11) | (rawData[12] << 12) | (rawData[13] << 13) | (rawData[14] << 14) | (rawData[15] << 15);
  //send ADC pin high to say we have read the first channel
  digitalWrite(RD, HIGH);
  //repeat for n channels
  }
}

//counting pulses ISRs
void pulseCounter1(){
  // Increment the pulse counter
  pulseCount1++;
}
void pulseCounter2(){
  // Increment the pulse counter
  pulseCount2++;
}
void pulseCounter3(){
  // Increment the pulse counter
  pulseCount3++;
}

I think the shield doesn't use 53 as CS. usually pin 10 or 4 is used for Uno compatible shields. but pin 53 must be used as OUTPUT if Mega is SPI master

The SD card uses SPI for communications.  You appear to be using those pins for some other purpose.  If you want to use the SD card, then you need to choose other pins and let the SD card have 50, 51, 52, and 53.

Thank you Delta G, you are a G!  I was using an old version of my sketch, what an idiot! I had all the wires connected to the correct pins but hadn't double checked it in the sketch - schoolboy error 101. Thanks again and like I said, I'm eternally grateful. Hit me up if you're ever in Blighty - I owe you a drink at the very least.  Cheers,  Michael


text:
24V LED Lights with Arduino
I need help on determining how I can control 24VDC Auer Stack lights with an Arduino. I intend to activate these lights with a RF control and monitor them via IoT; the latter is just something else, not my main concern right now. However, I don´t know if I need to use normal relays, solid state relays or MOSFETs such as an IRF520.
The lights are 24V, consume around 22mA-33mA, they are pre-wired and only have the 4 wires (from the amount of lights I intend to use) and a common wire.
Thanks in advance!

Thank you for your quick response! I can see the IRF520 might be too much. What about the IRF520 arduino module, it has lower current and voltage rates, do you think it might work?

I don't think the IRF520 is a logic level MOSFET. You need one that can be driven to satuation with 5V. I've used this one from Adafruit for several projects: https://www.adafruit.com/product/355
It worked fine. It's also overkill, but so what?
(It looks like that same part number, IRLB8721, is available from several other manufacturers for cheaper than the Adadfruit part.)
It's dirt simple to use. You can drive the gate directly from an Arduino digital pin. It will handle plenty of current and up to 60V, so it should meet your needs.

At the currents involved the R_DSON even for a non-logic-level MOSFET like this doesn't really figure that much. It could be 100Ω@5V and you really wouldn't notice.  Personally I use STD19N3LLH6AG for my more powerful driving requirements - but then I can't remember the last time I used a through-hole component...

Pardon my ignorance (I am not an electronics expert). I thought the IRF520 Arduino Module was logic level (by the fact that it is driven by an Arduino). What do you mean by "driven to situation with 5V"..

Sorry, that was a typo. (Must have been auto-correct.) The phrase I intended to type is "driven to saturation" That means fully turned on. I don't know if the Arduino module boosts the gate voltage somehow. Getting an Arduino "module" is a little silly, given that all you need is a logic-level MOSFET, which costs less than a dollar US. There's no need for a PC board or other stuff.

All that differs between those LEDs and 12V LEDs is the voltage. You do exactly the same as you would do with 12V LEDs - you just make sure the components you use are rated for at least 24V.
The IRF520 is overkill for this application. It's rated for 100V and 9A - far more than you need. But that's not to say it won't work - it'll work just fine. But you don't need one as big or beefy.

Thank you for your quick response! I can see the IRF520 might be too much. What about the IRF520 arduino module, it has lower current and voltage rates, do you think it might work?

As long as the voltage rating is at least 24V, sure. It's probably the connectors and copper clearances on the board that dictate the voltage rating more than the MOSFET.

An IRF520 Arduino module is just a IRF520 on a PC board, with screw terminals, a connector, and an indicator LED. It doesn't add any real value over using a "bare" IRF520, and has the same restrictions.


text:
Nodemcu Server with multiple sensors
I am trying to connect my nodemcu client with nodemcu server, while my client is connected with two sensors (DHT11 and Soil Moisture) and it is workign perfectly, but on the server side I am unable to get all values, it is only giving me value of one parameter.
Server Side Code

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
String apiWritekey = "PBD5LAJC4BSV3OKC"; // replace with your THINGSPEAK WRITEAPI key here
const char* ssid = "Dhamaal";// your wifi SSID name
const char* password = "03334204224" ;// wifi pasword
///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~///

///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~///
const char* httpserver = "api.thingspeak.com";
ESP8266WebServer server;
WiFiClient client;

// Configuration parameters for Access Point
char * ssid_ap = "ESP_AP";
char * password_ap = "123456789";
IPAddress ip(192,168,11,4); // arbitrary IP address (doesn't conflict w/ local network)
IPAddress gateway(192,168,11,1);
IPAddress subnet(255,255,255,0);
// Set up the server object

// Keep track of the sensor data that's going to be sent by the client
float t1=0.0;
float h1=0.0;
float s1=0.0;

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

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(ip,gateway,subnet);
  WiFi.softAP(ssid_ap,password_ap);

  // Configure the server's routes
  server.on("/",handleIndex); // use the top root path to report the last sensor value
  server.on("/update",handleUpdate); // use this route to update the sensor value
  server.begin();
}
void handleIndex() {
    server.send(200,"text/plain",String(t1));
    server.send(200,"text/plain",String(h1));
    server.send(200,"text/plain",String(s1));// we'll need to refresh the page for getting the latest value
}

void handleUpdate() {

  // The value will be passed as a URL argument
 t1 = server.arg("value").toFloat();
  h1 = server.arg("value").toFloat();
  s1 = server.arg("value").toFloat();

  delay(100);
  WiFi.begin(ssid, password);

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("");
  Serial.print("NodeMcu connected to wifi...");
  Serial.println(ssid);
  Serial.println();
  Serial.println(WiFi.localIP() );

  delay(1000);
  ///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~///
 float t2 = t1;
 float h2 = h1;
 float s2 = s1;
  if (client.connect(httpserver,80))
  {
         String tsData = apiWritekey;
           tsData+="&field1=";
           tsData+=String(t2);
           tsData+="&field2=";
           tsData+=String(h2);
           tsData +="&field3=";
           tsData += String(s2);
           tsData += "\r\n\r\n";

     client.print("POST /update HTTP/1.1\n");//command to update
     client.print("Host: api.thingspeak.com\n");//host name here thingspeak.com
     client.print("Connection: close\n");//closing connection
     client.print("X-THINGSPEAKAPIKEY: "+apiWritekey+"\n");
     client.print("Content-Type: application/x-www-form-urlencoded\n");
     client.print("Content-Length: ");
     client.print(tsData.length());
     client.print("\n\n");  // the 2 carriage returns indicate closing of Header fields & starting of data
     client.print(tsData);

     Serial.print("Temp: ");
     Serial.print(t2);//printing on serial monitor
     Serial.print("Humi: ");
     Serial.print(h2);
     Serial.print("Soil: ");
     Serial.print(s2);
     Serial.println("uploaded to Thingspeak server....");//dialogue box
  //}
  digitalWrite(D4, LOW);

  client.stop();//stopping client

  Serial.println("Waiting to upload next reading...");
  Serial.println();
  delay(5000);

} }

void loop() {
server.handleClient();

}

and the output of it is

while the code of my client is
#include <DHT.h>
#include <ESP8266WiFi.h>

// Initialize sensor parameters
// Initialize network parameters
const char* ssid = "ESP_AP";
const char* password = "123456789";
const char* host = "192.168.11.4"; // as specified in server.ino

#define DHTPIN 0          //pin where the dht11 is connected

DHT dht(DHTPIN, DHT11);

// Set up the client objet
WiFiClient client;

// Configure deep sleep in between measurements
const int sleepTimeSeconds = 2;

void setup() {

  // Connect to the server
  WiFi.begin(ssid,password);
  Serial.begin(115200);
  dht.begin();
  while(WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("IP Address (AP): "); Serial.println(WiFi.localIP());

void loop() {
  // put your main code here, to run repeatedly:
   while (WiFi.status() == WL_CONNECTED) {
    delay(500);
    int s = analogRead(A0);
    float h = dht.readHumidity();
    float t = dht.readTemperature();
  Serial.print("Temperature: "); Serial.println(t);
  Serial.print("Humidity: "); Serial.println(h);
  Serial.print("Soil Moisture: "); Serial.println(s);
  // Connect to the server and send the data as a URL parameter
  if(client.connect(host,80)) {
    String url = "/update?value=";
    url += String(t);
    String url1 = "/update?value=";
    url1 += String(h);
    String url2 = "/update?value=";
    url2 += String(s);
    client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host +  "\r\n" +
                 "Connection: keep-alive\r\n\r\n"); // minimum set of required URL headers
     client.print(String("GET ") + url1 + " HTTP/1.1\r\n" + "Host: " + host +  "\r\n" +
                 "Connection: keep-alive\r\n\r\n"); // minimum set of required URL headers
     client.print(String("GET ") + url2 + " HTTP/1.1\r\n" + "Host: " + host +  "\r\n" +
                 "Connection: keep-alive\r\n\r\n"); // minimum set of required URL headers
    delay(5000);

  }
    // Read all the lines of the response and print them to Serial
    Serial.println("Response: ");
    while(client.available()){
      String line = client.readStringUntil('\r');
      Serial.print(line);
  }
}
}

and its output is

Kindly help me to get all values at server side, Thanks

Using a web server for communication between two NodeMCUs is insanely over-engineering it. Far simpler to use a basic TCP connection and treat it much like a serial communication channel.

You use the same name value for all /update? parameters. And the format of url parameters is ?name1=value1&name2=value2
Use
String url = "/update?t=";
url += String(t);
String url1 = "&h=";
url1 += String(h);
String url2 = "&s=";
url2 += String(s);

send it as one GET request
and read server.arg("t"),  server.arg("h") and  server.arg("s").
Note 1: Sending more responses with serverSend to one request from browser has no effect. Only the first will work.
Note 2: this kind of use of String class will fragment the memory and cause a crash
Note 3: You don't need to use HTTP to communicate between your devices over TCP network. You can use simple TCP socket connections without HTTP protocol overhead.

kindly can you tell me what should be my 'serversend' command?

now all values are showing as zero :-(

sorry, I edited the Answer

@MuhammadJahanzaib, does it work now?

Yes it worked any how, now I have different situation, I want to connect 2 clients to the same server, one client is working perfectly but confused how to connect server with other client


text:
ARDUINO flashing lights
I'm making a circuit with my Arduino so that when it receives a '1' or
'2' or 'a' it turns on or off the LEDS. But I wanted the lights to
flash and do not know how to do loops in loops or if that's what I
need to do at all. Any help would be very much appreciated and the
code will be below.
//-----------------ELECTRONICS-----------------//

int left = 11;
int stoP = 12;
int right = 8;

//variables
int Received = 0;
int left_state =0;
int stoP_state = 0;
int right_state = 0;

void setup() {
  Serial.begin(9600);
  pinMode(left,OUTPUT);
  pinMode(stoP,OUTPUT);
  pinMode(right,OUTPUT);
}

void loop() {

  if (Serial.available() > 0)
  {
    Received = Serial.read();
  }

////////////////LEFT//////////////////

if (left_state == 0 && Received == '1')

{
  digitalWrite(left,HIGH);
  Received = 0;
  left_state = 1;
}

if (left_state == 1 && Received == '1')

{
  digitalWrite(left,LOW);
  Received = 0;
  left_state = 0;
}
///////////////////////////////////

///////////////stop////////////////

if (stoP_state == 0 && Received == 'a')

{
  digitalWrite(stoP,HIGH);
  Received = 0;
  stoP_state = 1;
}

if (stoP_state == 1 && Received == 'a')

{
  digitalWrite(stoP,LOW);
  Received = 0;
  stoP_state = 0;
}

 ////////////////////////////////

 ///////////right///////////////

if (right_state == 0 && Received == '2')

{
  digitalWrite(right,HIGH);
  Received = 0;
  right_state = 1;
}

if (right_state == 1 && Received == '2')

{
  digitalWrite(right,LOW);
  Received = 0;
  right_state = 0;
}
}

You could turn off the LEDs after a short time using millis(). You can look at the BlinkWithoutDelay example, that comes with the Arduino IDE

As chrisl already mentions, you have to use the millis function.
Besides setting a pin HIGH, you keep a variable for each state for the start time and set it when the corresponding state is set to 1:
unsigned long left_start_time = millis();

Than within the loop you check for each state when it is 1 (on or actually flashing) and switch the pin on or off, example:
if (left_state == 1)
{
    digitalWrite((millis() - left_startTime % 400) < 400 / 2) ? HIGH : LOW);
}

What this does is for the first half of the 400 ms period (time % 400 < 200) to be HIGH, and the last half (time % 400 >= 200) to be LOW.
Improvements:

Do not use 400 but a constant value.
Do not use separate variables for left/right/stop, but put them in a structure, keeping the state, time, pin, and activation key ('1', '2', 'a') together.
If you do the above, you can make your program more simpler (and avoid code duplication) by parameterize your code.


text:
74HC595 not working properly
I've used the following code to light 8 yellow leds sequentially but it only runs as it's supposed to be on Proteus. However in my breadboard the 8 leds keeps blinking all together, the resistors used are 220 ohms. Also when i'm trying to change the value of the variable "leds" to be for example 0x0F, it doesn't light, I've read in the Arduino shiftout tutorial that 0.1F capacitor on the latch pin will even the flickers so now I'm really confused.
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;

byte leds = 0;

void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
}

void loop()
{
  leds = 0;
  updateShiftRegister();
  delay(500);
  for (int i = 0; i < 8; i++)
  {
    bitSet(leds, i);
    updateShiftRegister();
    delay(100);
  }
}

void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, LSBFIRST, leds);
   digitalWrite(latchPin, HIGH);

}

The delay after "updateShiftRegister" is only 100ms? This means that within a second all LED's get updated. This would make them appear like blinking?
Also; did you try the 0.1F capacitor?

what does blinking all together mean?

SOLVED!
 i've tried many solutions to make it work but it just didn't and here are the solutions i tried
a) to use  0.1µf or 10µf between VCC and ground pin of the 74hc595 .
b) to set the clockPin and dataPin zero before sending data .
c) replacing the resistors from 220 ohm to 470 .
however,  i connected pin13 of the 74HC595 to an arduino pin and drive it to zero so the 8 output are ready to go then digitalWrite(out_enable_Pin, HIGH) ,send data as shown in the following code then digitalWrite(out_enable_Pin, LOW) again .
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;
int out_enable_Pin=13;
int resetPin=5;
char leds = 0;

void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(out_enable_Pin, OUTPUT);
  pinMode(resetPin, OUTPUT);
}

void loop()
{
  digitalWrite(out_enable_Pin, LOW);
  digitalWrite(resetPin, HIGH);

  for (int i = 0; i <255; i++)
  {
    leds=i;
    updateShiftRegister();
    delay(1000);
  }
}

void updateShiftRegister()
{
    digitalWrite(out_enable_Pin, HIGH);
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, MSBFIRST, leds);
   digitalWrite(out_enable_Pin, LOW);
   digitalWrite(latchPin, HIGH);
}


text:
State Machine Logic problem with added states monitoring safety switches
I have been working on getting a state machine to work correctly but am having trouble with adding in the last bit of logic. What it needs to do is several things:

Read two button inputs.
Make sure they are pressed and held within a certain amount of time of each other as defined by "PushTimeWindow" and if not wait til both are released.
Wait for a certain period as defined by "PushSafetyWindow".
Turn on a relay for an amount of time as specified by "RelayOnTime".
After the relay is off wait for both buttons to be released before they can be read again.
If at any time one or both released turn off the relay and wait for both to be released to be pushed again.
Count the number of successful relay periods and display them

Almost everything is doing what I had hoped it would do with the exception that I can't get the program to only allow the two switches to be pushed within a certain time frame as defined by the PushTimeWindow. Either button one needs to be pushed and held and then the second button pressed within the specified time. This window of time is intended to only allow the relay to be turned on if both buttons have been pushed within the set time. I have two states that I am trying to use to handle it but it seems to ignore them. Cases ONE_PUSHED and PUSHED_WINDOW are intended to handle this and seem to be ignored by the program. These two were added to handle that additional logic but otherwise the rest of the program works great and handles the other functions fine. I can't figure out what I am doing wrong with that logic. This is an added function to a previous question answered by user Jot
here.
I suspect that the two new cases might be redundant and true no matter what and that is why they seem to be ignored, or is it that they are never called on to be tested as true or not?
The sketch uses the Bounce2 library to debounce the noisy switches and each button has pull down resistors and otherwise works well.
Here is the sketch (Updated 10/17/17):
// 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,
  ONE_PUSHED,
  PUSHED_WINDOW,
  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
const unsigned long PushSafetyWindow = 50; // Safety Delay after push

// 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 ONE_PUSHED:
      //One button is pushed
      if(inputState == SOMETHING_ELSE)
      {
        //One button was pushed
        Serial.println("One button Pushed");
        previousMillis = currentMillis;
        state = PUSHED_WINDOW;
      }
      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;

    //Check to see if the other button is pushed, if not wait for both off
    case PUSHED_WINDOW:
      if(currentMillis - previousMillis >= PushTimeWindow)
      {
        Serial.println("Going to WAIT_FOR_BOTH_ON state 2");
        state = WAIT_FOR_BOTH_OFF;
        previousMillis = currentMillis;
      }
      //If window to push has expired go to WAIT_FOR_BOTH_OFF state
      else if(inputState == BOTH_ON)
      {
        Serial.println("Going to SAFETY_WINDOW 2");
        state = SAFETY_WINDOW;
      }
    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 >= 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
        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);
}

The part of the sketch that doesn't seem to run are these two cases that should be called when one button is pressed:
case ONE_PUSHED:
      //One button is pushed
      if(inputState == SOMETHING_ELSE)
      {
        //One button was pushed
        Serial.println("One button Pushed");
        previousMillis = currentMillis;
        state = PUSHED_WINDOW;
      }
      break;

The sketch should then run the case PUSHED_WINDOW to check if the inputState goes to BOTH_ON within the window defined in PushTimeWindow. If that time has been exceeded the sketch should then wait until both buttons are released again and then wait for another try.
case PUSHED_WINDOW:
      if(currentMillis - previousMillis >= PushTimeWindow)
      {
        Serial.println("Going to WAIT_FOR_BOTH_ON state 2");
        state = WAIT_FOR_BOTH_OFF;
        previousMillis = currentMillis;
      }
      //If window to push has expired go to WAIT_FOR_BOTH_OFF state
      else if(inputState == BOTH_ON)
      {
        Serial.println("Going to SAFETY_WINDOW 2");
        state = SAFETY_WINDOW;
      }

Unfortunately the sketch never seems to run either of the cases which is where I am having trouble debugging.
The sketch will run on an Arduino Nano with an ATmega328P programmed with Arduino 1.8.5. The two input buttons are Rees mushroom head momentary industrial switches that are software debounced and have smoothing capacitors to hardware debounce as well. Inputs have 1K pull down resistors and the system is powered by a 9V power supply. The output to the relay pin drives the base of a NPN TIP31C transistor that powers the input of a relay with 9V. The relay has a capacitor with a resistor across it on its input to smooth out back spikes that occur when the relay triggers. The hardware all seems to be working fine and as intended.
Edit 10/20/2017
The solution to the question is included in the below code. The problem was with the state machine seeming to skip the window required to press the button. Some of the enum names were also changed as per suggested but if possible will be renamed again if better names come to me to be more clear what they are to do.
Edit 10/23/2017
Tried to name everything as clearly as possible and include documentation as to source and function of sketch.
Here is the final sketch:
// This sketch reads inputs from two buttons to turn on a relay
// 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
// 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 Nano board on Arduino 1.8.5
// 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);

enum
{
  WAIT_FOR_BOTH_LOW,
  WAIT_FOR_BUTTON,
  ONE_PUSHED_WAIT_FOR_OTHER_BUTTON,
  SAFETY_WINDOW,
  RELAY_ON,
} state;       // an 'enum' is automatically an integer.

// 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.
};

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

// 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 = 50; // Safety Delay after push

// 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();

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(15); //Debounce time

  pinMode(RelayPin, OUTPUT);  // OUTPUT to Relay
  pinMode(IndicatorPin, OUTPUT); // OUTPUT to Indicator LED
  Serial.println("Going to WAIT_FOR_BOTH_LOW state");
  state = WAIT_FOR_BOTH_LOW;
}

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_LOW:
      // Both buttons must be released to be able to continue.
      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 !
      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:
      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 SAFETY_WINDOW state");
        previousMillis = currentMillis;
        state = SAFETY_WINDOW;
      }
      break;
    case SAFETY_WINDOW:
      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");
        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:
      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
        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 WAIT_FOR_BOTH_LOW state");
        lcd.setCursor(0,1);
        lcd.print(success);
        digitalWrite(RelayPin, LOW);  // Turn Off RelayPin
        digitalWrite(IndicatorPin, LOW); // Turn Off IndicatorPin
        state = WAIT_FOR_BOTH_LOW;
      }
      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_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);
}

Do you know why no one is answering ? I can help, but then I will be asking many questions, maybe between 10 and 20 and you will have to put a lot of effort in it. Are you ready for it ?

Hello, any help is greatly appreciated. I hope it is not because I am that far off from what I was trying to have it do that there weren't any suggestions. I am also open to suggestions if I am posting questions incorrectly. I try to only ask a question when I am really stumped so I may not be posting in a manner that people are expecting to since I don't ask often. I am ready and eager to dive in. I have been trying to wrap my head around the FSM logic and have been reading an article on hackingmajenkoblog and I thought I had the logic correct but something is off.

Intro
You did not get any answers, because someone has to read the whole sketch and you have not explained which problem you want to solve with the two extra states and you did not fully explain what the extra states do.
I don't see a problem with my original example for the 'SAFETY_WINDOW' state. As soon as one button is released, it bails out.
I can image that the state rushes through 'WAIT_FOR_BOTH_OFF' and 'WAIT_FOR_BOTH_ON' when there is a lot of noise. Slowing it down in the sketch or with Bounce2 is a good improvement.
I could have made a mistake that I don't see, but now it is up to you to investigate where the problem comes from.
Software
You already found Majenko about FSM. Good, I hope you have studied it.
Perhaps you should make a sketch, just for fun, with a simple state machine.
As you can see, the integer 'state' rules it all.
The large switch-case statement contains the seperate pieces of code for each state. The order of those pieces of code does not matter. The integer 'state' defines what will be executed.
You never set the variable 'state' to 'ONE_PUSHED', therefor that piece of code will never be executed. However, please don't add that somewhere in the sketch. Explain why you want to detect if just one button is pushed.
Every piece of code of every state should make sense. I think that you have gone a little too far and the sketch is going haywire and is not going in a direction.
Is the problem that during the time that both buttons needs to be pressed (just before the relay turns on), the sketch thinks that both are pressed, even when one button is released ? Is that the problem ?
When that would be caused by a bug in the sketch, then the bug should be fixed. Trying to make a workaround around a bug is bad. If the workaround contains a bug itself, then fixing a bug with another bug is something you will never get out.
Please add a welcoming message to the display and the serial port. That way you can see if the Arduino was reset.
The software thing to do
There is a problem. Please describe it clearly. Then make the smallest possible test sketch to investigate that problem.
Perhaps a small sketch using the function "getInputState" and display it a number of times per second.
Hardware
The input impedance of an Arduino pin is very high. It could be a few hundred MegaOhms. That means if one pin is connected to something, and the pin next to it is open (not connected), then the open pin might read the same signal as its neighbour pin, just by sensing the nearby voltage through the air.
Can you make a photo of that button ?
Is there a spring inside the button ?
How long are the wires or cables to the Arduino ?
Are there other cables alongside that cable ?
Are there electrical devices nearby that could cause spikes ?
How is the button and the pullup/pulldown resistor connected ? Can you show it in a diagram ? You can even make a drawing and make a photo of that.
Are you sure it is like that, can you verify that ?
Verify it once more with a multimeter. Measure the Arduino pin with the button(s) pressed and released. Is the really going HIGH when the corresponding button is pressed ?
Can you try to connect the buttons to other pins of the Arduino board ? Perhaps an input is blown.
Is the GND of the Arduino connected to a computer, and the computer to earth ground ?
Are the wires to the buttons somehow connected to some kind of ground ?
Or to a metal enclosure or something like that ?
Is there another ground problem ?
Do you use a good and certified power supply for the Arduino ? I hope not a very cheap power supply that is leaking the mains voltage to the output.
I forgot which Arduino board you use. Which Arduino board and which Arduino IDE version do you use ?
Common mistakes
There are a number of common mistakes. I think you made a few of them. If you can recognize them, perhaps you can avoid them.

The famous XY-problem: xyproblem.info.
This happens a lot.
Someone is too focussed to fix a problem, and wandering away from the
original problem.
Trying to get a result right now.
No experienced software designer
does that. Investigate the problem by excluding the rest.
Make small tests.
Make a good description/explanation.
If it is an art or a skill,
describing something in a logical way is very important.
It can be half the work.
Ground problems.
Ground problems is a major problem. When everything is connected okay,
the ground could be connected in the wrong place.
This is a tough subject.
Never trust your tools.
Once someone knows how to make something work, but there is a bug
somewhere that is impossible to find, then perhaps there is no bug.
It can be a broken Arduino board, or other bad hardware or a bug
in the Arduino software. It happens.

ADDED
I understand now that both buttons should be pushed within a certain time. That is the third millis timer that will be needed. I have a problem with the names that you choose for this new situation. I hope you don't mind that I made my own names. You had most of the conditions and the timeout, but bailing out as soon as the one button was released was missing.
The possibility that both buttons are pressed at the same time should also be accepted.
I did test my previous sketch, but I did not test this code. I had to draw a time diagram on a piece of paper to see the sequence of the states. I suggest you do the same.
The states are still in sequential order, there is no need for a parallel path in the state machine, or wildly jumping to all kind of states. Everything flows in a logic way from one state to the next in a sequential way.
My diagram on my piece of paper tells me that the "WAIT_FOR_BOTH_ON" has to be replaced by two other states. It needs other conditions and it should get a timeout. Let's call the new states "WAIT_FOR_BUTTON" and "ONE_PUSHED_WAIT_FOR_OTHER_BUTTON".
You might give this next constant a better name (it is the time frame in which the second button has to be pushed after the first one is pushed):
const unsigned long TimeFrameForSecondButton = 200;

Waiting for both off is still the same. The next state is changed into "WAIT_FOR_BUTTON".
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_BUTTON state");
    state = WAIT_FOR_BUTTON;
  }
  break;

Then wait for a button (just one or perhaps two at the same time).
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 !
  if(inputState == SOMETHING_ELSE || inputState == BOTH_ON)
  {
    // 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;

While waiting for the second button, if anything is wrong then return to the state to wait for both off.
case ONE_PUSHED_WAIT_FOR_OTHER_BUTTON:
  if(inputState == BOTH_OFF)
  {
    // 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_OFF state");
    state = WAIT_FOR_BOTH_OFF;
  }
  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("Going to WAIT_FOR_BOTH_OFF state");
    state = WAIT_FOR_BOTH_OFF;
  }
  else if(inputState == BOTH_ON)
  {
    // The timeout has not ended and is still running.
    // And now both buttons are pressed.
    // Hurray, we can continue.
    // Start the timer for the SAFETY_WINDOW state.
    Serial.println("Going to SAFETY_WINDOW state");
    previousMillis = currentMillis;
    state = SAFETY_WINDOW;
  }
  break;

Can you merge this in the code ? And remove the things that are not used ?
I'm still unhappy with the names of the variables and states and so. When you look at it a year later, you must know what is going on. Can you give that a thought, it does not matter if the names are very long.
Reaction to 10/20/2017
Awesome!
A medium-complex problem solved in a straightforward logical way without using delay.
A few tips:
The header should explain what it is; the date; which Arduino board; which Arduino IDE version; a link to this stackexange.com page and so on.
Your indents are not always the same. Can you get all the "case" blocks like the others ?
Normally, using three timers with millis() requires three 'previousMillis' variables. The 'previousMillis' is used three times. That needs some extra explanation:
// The 'previousMillis' is exclusively for the state machine only.
// It is used for different software timers in different states.
// That is okay, because the states are seperated from each other.
unsigned long previousMillis;

Now that I think of it, the state machine does not rule the sketch, it processes the buttons.
If you would add a buzzer, and it would need a timeout to turn off, then that timeout must be done outside the state machine. That timeout should also get it's own variable, for example: previousBuzzerMillis.
What about the names for the input states. Is "BOTH_BUTTONS_ON", "BOTH_BUTTONS_OFF, "JUST_ONE_BUTTON" better ? Or "BOTH_BUTTONS_PUSHED", "BOTH_BUTTONS_RELEASED", "ONLY_ONE_BUTTON" ?
I can't think of better names for other variables at the moment. Even the name "SAFETY_WINDOW" seems obvious.
Correction nov 3, 2017
I just learned that 'enum' is not automatically an integer. An 'enum' is its own type.

Hello, the original example sketch you posted works great and as intended. The issues with bouncing have been cleared up with the combination of the Bounce2 library and smoothing capacitors. What I am trying to do is add the additional logic on top of the existing logic that when one button is pushed the program checks to make sure the second button is pushed within PushTimeWindow and if it is not it waits for both to be released and stay in WAIT_FOR_BOTH_OFF state and for the operator to try again. When that additional criteria is met the sketch should move to SAFETY_WINDOW.

I attempted to set the state to ONE_PUSHED when the inputState returned as SOMETHING_ELSE. It detects BOTH_ON and BOTH_OFF just fine and it seems that it should do the same when SOMETHING_ELSE is the inputState. The rest of the sketch works great as is and pushes are detected reliably and the relay operates as intended it is just the extra logic that seems to be getting ignored. I will add more hardware details in the original question to clarify more.

I've been going through the explanations about state machines and have set up smaller additional ones for practice. I think that is where I may have a disconnect. I can see that the "state" is what drives the sketch, I think I have a disconnect as to why the state machine ignores the new ONE_PUSHED case when it seems like it is set up like the other two.

@HiWay If I did not understand your question, then I'm very sorry. I hope I was not to hars on you. I read you question a few times, but I still don't understand what you want to do. Can you edit your question and explain it once more (assuming I'm really dumb). When I read it now, it seems that "PushTimeWindow" and "PushSafetyWindow" do the same thing. If you can not detect if one button is pressed, then you should make a minimal test sketch to test just that. That is why I asked so many questions about the hardware. That both buttons must be pressed for some time was already in the sketch.

Hello, no worries. I will try to edit it a bit if I can phrase it differently. The "SAFETY_WINDOW" waits a moment before initiating the relay and works well as is, thank you. What PUSHED_WINDOW is supposed to do is detect the first push and make sure the second push happens within a specified amount of time after the first button is pushed. Failing to meet that window should return the state back to waiting for both buttons to be released again so the operator can try again. If pushed in the proper amount of time the state should then enter the safety window.

So they still need to be pushed both to start the timer, but the button that is pressed second has to be pushed within a certain time after the first button is pushed. Can you add that to your question ? That changes the logic that was first in the sketch. I will try to think about it and add it to my answer at the bottom with ADDED.

Correct, the second button needs to be pressed and held so the rest of the sketch can operate as before. I will add it to the question so it is a bit clearer. Thank you for taking a look at it.

It doesn't matter which button is pressed first. Just one button then the other within the window.

The ADDED section is there.

Thanks! The sketch is working as expected. I am seeing where I had some holes in the logic of the state machine. I was not accounting for the possibility of both being push already so it seems it was not moving through the states properly since WAIT_FOR_BOTH_ON seems to have been making the sketch jump over the window for the second press. I will put the final sketch in the question so people can see how it works. Thanks again, I couldn't get the last bit of logic worked out.

A few last tips added in the section Reaction to 10/20/2017.

I tried to include everything and do house cleaning on the spacing. I renamed a few things referring to buttons as HIGH or LOW. Seemed logical to me in case someone used a photo interrupter or similar rather than a switch to infer it is the input. The other variables seemed to be named nice and clear to me as well. Thanks again.

It looks like you are correct that the ONE_PUSHED and PUSHED_WINDOW branches are being ignored, because you never set the state to ONE_PUSHED.
I believe your just need to update the WAIT_FOR_BOTH_OFF 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 ONE_PUSHED state");
        state = ONE_PUSHED;
      }
      break;

Hello, thanks for taking a look at the sketch. Altering the case in the way suggested seems to prevent the sketch from ever entering the BOTH_ON state. I tried setting the state to ONE_PUSHED when the sketch enters getInputState and returns SOMETHING_ELSE to then enter the ONE_PUSHED state. The two states do appear to be getting ignored.

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