2

I have done a lot of reading and learning after previous help here and it has been great. I have uploaded and tried many iterations of my code which all worked (Assuming my code was actually good) and i though i had finally cracked my project today. I was writing a bunch at work without my ESP with me so i did a lot of changes and only uploaded it when i got home. The issue is, as soon as i did the ESP got stuck in a really short <500ms reboot loop. I had to ground GPIO0 to get it out of the loop and upload code that does work to get the ESP stable again. My previous versions upload and work as they did before but my latest version just gets it into the loop and i have to again ground GPOI0 to get out. I have compared as best as i know how and i cannot see how the code is so broken. It compiles correctly and the upload output has no errors. Please help.

Todays edits were mostly writing and editing the LED Logic, Timer Logic and Gate Logic

Purpous.

This project is a timer i have built for calculating the time and speed of a model rocket traveling along a cable. It would use 3 light gates (Currently buttons for dev). Gs is the start gate, G1 is the second gate but the first of the speed trap, G2 if the final gate. The first timer starts when the rocket leaves the first gate (Gs), When the rocket passes the second gate (First speed trap gate) (G1) a second timer starts. When it reaches the 3rd and final gate (G2), both timers stop and the system takes the time it took to travel between gate S and 2 to calculate average speed then the time between G1 and G2 to calculate the speed through the speed trap. Distance is entered in a "menu". I am still new to code this complex (Well for me it is) so i have no idea how it broke.

I can upload previous working versions if it would help.

#include <LiquidCrystal_I2C.h>
const int startPin = 12; // Start button Pin
const int stopPin = 11; // Stop button Pin
const int resetPin = 10; // Reset button Pin
const int menuPin = 5; // Menu button Pin
const int Gs = 6; // Start Gate (White)
const int G1 = 7; // Finish Gate 1 Pin (Yellow)
const int G2 = 8; // Finish Gate 2 Pin (Blue)
const int ledr = 2; // Red LED Pin
const int ledg = 3; // Green LED Pin
const int ledy = 4; // Yellow LED Pin
bool WaitM = false; // Timer (Main) waiting for start
bool WaitG = false; // Timer (Gate) waiting to start
bool RunningM = false; // State of speed main timer
bool RunningG = false; // State of speed gate timer
bool Run = false; // Is timer program running?
bool SysState = false; // Is system up?
bool clearscreen = false; // Clear screen state
bool menu = false; // Is the range menu active on the display
int ledgState = LOW; // the current state of the Green LED output pin
int ledyState = LOW; // the current state of the Yellow LED output pin
int ledrState = LOW; // the current state of the Red LED output pin
int startbuttonState; // the current reading from the start button input pin
int startbuttonStateLatch = LOW; // start button latch state after debounce
int laststartbuttonState = LOW; // the previous reading from the start button input pin
int stopbuttonState; // the current reading from the stop button input pin
int stopbuttonStateLatch = LOW; // stop button latch state after debounce
int laststopbuttonState = LOW; // the previous reading from the stop button input pin
int resetbuttonState; // the current reading from the reset button input pin
int resetbuttonStateLatch = LOW; // reset button latch state after debounce
int lastresetbuttonState = LOW; // the previous reading from the reset button input pin
int menubuttonState; // the current reading from the menu button input pin
int menubuttonStateLatch = LOW; // menu button latch state after debounce
int lastmenubuttonState = LOW; // the previous reading from the menu button input pin
int GsState; // State of Start Gate sensor
int lastGsState = LOW; // Last state of Stare Gate button (To be reomved when sensor replaced button)
int G1State; // State of Gate 1 (speed trap start) Sensor
int lastG1State = LOW; // Last state of G1 button (To be reomved when sensors replace buttons)
int G2State; // Stage of Gate 2 (Speed trap and full run) sensor
int lastG2State = LOW; // Last state of G2 button (To be removed when sensors replace buttons)
int Range = 50; // Range length input in M(eters)
int TrapLength = 2; // Trap light gates distance apart in M(eters)
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 25; // the debounce time; increase if the output flickers
unsigned long StartMMillis; // millis at start if Main run
unsigned long StartGMillis; // millis at start of speed trap
unsigned long EndMillis; // millis at end of run
unsigned long RunM; // millis time for main run
unsigned long RunG; // millis time for speed trap
unsigned int TrapS = 0; // Speed between Gate 2(B) & 3(C) (M/S)
unsigned int TrapSMPH = 0; // Speed between Gate 2(B) & 3(C) (MPH)
unsigned int SpeedAVG = 0; // Speed average between Gate 1(A) & 3(C)
LiquidCrystal_I2C lcd(0x27, 20, 4); // LCD setup
void setup() {
 Serial.begin(9600); // Start Serial
 lcd.init(); // Start and config for LCD, backlight and cursor
 lcd.backlight();
 lcd.setCursor(0,0);
 pinMode(startPin, INPUT_PULLDOWN); // Pin setup for buttons, LED's and gate sensors
 pinMode(stopPin, INPUT_PULLDOWN);
 pinMode(resetPin, INPUT_PULLDOWN);
 pinMode(menuPin, INPUT_PULLDOWN);
 pinMode(Gs, INPUT_PULLDOWN);
 pinMode(G1, INPUT_PULLDOWN);
 pinMode(G2, INPUT_PULLDOWN);
 pinMode(ledr, OUTPUT);
 pinMode(ledg, OUTPUT);
 pinMode(ledy, OUTPUT); 
 digitalWrite(ledr, ledrState); // Output for LED's
 digitalWrite(ledg, ledgState);
 digitalWrite(ledy, ledyState);
 Run = false; // Set RUN to false at start
 SysState = false; // Set System State to false at start
}
void loop() {
 // BUTTON DEBOUNCE LOGIC (Adding buttons as needed)
 //Start Button debounce filter
 int readingstart = digitalRead(startPin); //Read state of button into local variable
 //Check to see if button was just pushed (Went from LOW to HIGH), And if you have waited long enough
 //since the last press to ignore any noise
 if (readingstart != laststartbuttonState) { //if the switch changed, due to noise or pressing,
 lastDebounceTime = millis(); //reset debouce millis timer
 }
if ((millis() - lastDebounceTime) > debounceDelay ) { // whatever the reading is at, it's been there for longer than the debounce delay, so take it as the actual current state:
 
 if (readingstart != startbuttonState) { // if the button state has changed:
 startbuttonState = readingstart;
 if (startbuttonState == HIGH) { //only toggle filtered state if the new button state is HIGH
 startbuttonStateLatch = !startbuttonStateLatch;
 }
 }
}
laststartbuttonState = readingstart;
 //Stop Button debounce filter
 int readingstop = digitalRead(stopPin);
 if (readingstop != laststopbuttonState) {
 lastDebounceTime = millis();
 } 
 if ((millis() - lastDebounceTime) > debounceDelay ) {
 
 if (readingstop != stopbuttonState) {
 stopbuttonState = readingstop;
 if (stopbuttonState == HIGH) {
 stopbuttonStateLatch = !stopbuttonStateLatch;
 }
 }
 }
 laststopbuttonState = readingstop;
 //Reset Button debounce filter
 int readingreset = digitalRead(resetPin);
 if (readingreset != lastresetbuttonState) {
 lastDebounceTime = millis();
 } 
 if ((millis() - lastDebounceTime) > debounceDelay ) {
 
 if (readingreset != resetbuttonState) {
 resetbuttonState = readingreset;
 if (resetbuttonState == HIGH) {
 resetbuttonStateLatch = !resetbuttonStateLatch;
 }
 }
 }
 lastresetbuttonState = readingreset;
 
 //menu Button debounce filter
 int readingmenu = digitalRead(menuPin);
 if (readingmenu != lastmenubuttonState) {
 lastDebounceTime = millis();
 } 
 if ((millis() - lastDebounceTime) > debounceDelay ) {
 
 if (readingmenu != menubuttonState) {
 menubuttonState = readingmenu;
 if (menubuttonState == HIGH) {
 menubuttonStateLatch = !menubuttonStateLatch;
 }
 }
 }
 lastmenubuttonState = readingmenu;
 // Once fitted, test lights sensors without debounce to reduce CPU load
 //Gs button debaounce (No latch state required)
 int readingGs = digitalRead(Gs);
 if (readingGs != lastGsState) {
 lastDebounceTime = millis();
 }
 if ((millis() - lastDebounceTime) > debounceDelay) {
 if (readingGs != GsState) {
 GsState = readingGs;
 }
 }
 //G1 button debounce (No latch state required)
 int readingG1 = digitalRead(G1);
 if (readingG1 != lastG1State) {
 lastDebounceTime = millis();
 }
 if ((millis() - lastDebounceTime) > debounceDelay) {
 if (readingG1 != G1State) {
 G1State = readingG1;
 }
 }
 //G2 button debounce (No latch state required)
 int readingG2 = digitalRead(G2);
 if (readingG2 != lastG2State) {
 lastDebounceTime = millis();
 }
 if ((millis() - lastDebounceTime) > debounceDelay) {
 if (readingG2 != G2State) {
 G2State = readingG2;
 }
 }
 // LED Logic
 if (Run) {
 digitalWrite(ledg, HIGH);
 }
 else {
 digitalWrite(ledg, LOW);
 }
 if (WaitM && !RunningM && WaitG && !RunningG){
 digitalWrite(ledy, HIGH);
 }
 else {
 digitalWrite(ledy, LOW);
 }
 if (!Run && !WaitM && !RunningM && !WaitG && !RunningG){
 digitalWrite(ledg, LOW);
 digitalWrite(ledy, LOW);
 digitalWrite(ledr, HIGH);
 }
 // Gate LOGIC
if ((startbuttonState == HIGH) && (GsState == 1) && (G1State == 1) && (G2State == 1)) { //if start button & all 3 gate buttons are true then set both Wait, Run and SysState to true
 stopbuttonStateLatch = LOW;
 WaitM = true;
 WaitG = true;
 Run = true;
 SysState = true;
}
if (stopbuttonState == HIGH) { // if stop button pressed, set Run to false, Keep SysState True
 startbuttonStateLatch = LOW;
 Run = false;
 SysState = true;
 }
if (resetbuttonState == HIGH) { // if reset button pressed, 
 Run = false; // set Run and SysState to false, 
 SysState = false;
 startbuttonStateLatch = LOW; // Set button latch to off and turn off LED's
 digitalWrite(ledg, LOW);
 stopbuttonStateLatch = LOW;
 digitalWrite(ledr, LOW);
}
if ((GsState == 1) && (G1State == 1) && (G2State == 1)){ // if all 3 gates are true
 WaitM = true; // set both wait states to true
 RunningM = false; // set both Running states to false (Should be anyway in normal startup)
 WaitG = true;
 RunningG = false;
}
if ((GsState == 0) && (G1State == 1) && (G2State == 1)){ // When first gate opens (State goes off) WaitM set to false
 WaitM = false;
}
if ((GsState == 0) && (G1State == 0) && (G2State == 1)){ // When first and second gates open, WaitG (2nd) wait state goes false
 WaitG = false;
}
if ((GsState == 0) && (G1State == 0) && (G2State == 0)){ // WHen final gate opens, set Run to false
 Run = false;
}
 // TIMER Logic
 //Rocket leaves start gate
 if (Run && !WaitM && !RunningM){
 StartMMillis = millis();
 RunningM = true;
 }
 // Rocket passes first speed gate
 if (Run && !WaitG && !RunningG){
 StartGMillis = millis();
 RunningG = true;
 }
 // Rocket passes 2nd speed gate, ending run
 if (!Run && RunningM && RunningG){
 EndMillis = millis();
 RunningM = false;
 RunningG = false;
 } 
 // At end, calculate speed in M/s
 if (!Run && !RunningM && !RunningG) {
 RunM = (EndMillis - StartMMillis);
 RunG = (EndMillis - StartGMillis);
 TrapS = (TrapLength / RunG)/1000;
 TrapSMPH = TrapS * 2.237;
 SpeedAVG = ((Range / RunM)/1000)*2.237;
 }
 // SCREEN OPTIONS
 // RANGE ADJUST MENU
 if (menubuttonStateLatch == HIGH) {
 menu = true;
 }
 else {
 menu = false;
 }
 if(menubuttonState == HIGH) {
 lcd.clear();
 }
 if (menu) {
 if(digitalRead(startPin) == HIGH){
 Range = Range + 1;
 lcd.setCursor(0,2);
 lcd.print(" ");
 }
 if(digitalRead(stopPin) == HIGH){
 Range = Range - 1;
 lcd.setCursor(0,2);
 lcd.print(" ");
 }
 
 
 // lcd.clear();
 lcd.setCursor(0,0);
 lcd.print("Range in full M");
 lcd.setCursor(0,1);
 lcd.print(Range);
 }
 // MAIN SCREEN WITH TIMER AND SPEED DISPLAY
 else {
 lcd.setCursor(0,0);
 lcd.print("Run Time (ms)- ");
 lcd.print(RunM);
 lcd.setCursor(0,1);
 lcd.print("Speed (AVG) - ");
 lcd.print(SpeedAVG);
 lcd.setCursor(0,2);
 lcd.print("Speed (MAX) - ");
 lcd.print(TrapSMPH);
 lcd.setCursor(0,3);
 lcd.print("Gate|A");
 lcd.print(digitalRead(Gs));
 lcd.print("|B");
 lcd.print(digitalRead(G1));
 lcd.print("|C");
 lcd.print(digitalRead(G2));
 lcd.print("|");
 
 if (!SysState && !Run) {
 lcd.print(" OFF ");
 }
 if (SysState && Run && WaitM && !RunningM) {
 lcd.print(" Wait ");
 }
 if (SysState && Run && !WaitM && RunningM) {
 lcd.print(" Run ");
 }
 if (SysState && !Run) {
 lcd.print(" Stop ");
 }
 }
 // Serial output
 Serial.print ("Button states : Mom|Lat : ");
 Serial.print ("Start = ");
 Serial.print (startbuttonState);
 Serial.print (startbuttonStateLatch);
 Serial.print (" || Stop = ");
 Serial.print (stopbuttonState);
 Serial.print (stopbuttonStateLatch);
 Serial.print (" || Reset = ");
 Serial.print (resetbuttonState);
 Serial.print (resetbuttonStateLatch);
 Serial.print (" || Menu = ");
 Serial.print (menubuttonState);
 Serial.print (menubuttonStateLatch);
 Serial.println("Gate States: ");
 Serial.print(" Gs (A)-");
 Serial.print(digitalRead(Gs));
 Serial.print(" || G1 (B)-");
 Serial.print(digitalRead(G1));
 Serial.print(" || G2 (C)-");
 Serial.print(digitalRead(G2));
 Serial.println ("System States: ");
 Serial.print("Menu:");
 Serial.print (menu);
 Serial.print (" || Run = ");
 Serial.print (Run);
 Serial.print (" || System State = ");
 Serial.print (SysState);
 Serial.println ("Timer State: ");
 Serial.print ("WaitM = ");
 Serial.print (WaitM);
 Serial.print (" || RunningM: ");
 Serial.print (RunningM);
 Serial.print (" || WaitG: ");
 Serial.print (WaitG);
 Serial.print (" || RunningG: ");
 Serial.println (RunningG);
}
asked Jul 3, 2024 at 17:44
12
  • please edit your post ... copy and paste the content of the serial monitor into your question ... format it as code for readability... no screenshots Commented Jul 3, 2024 at 18:05
  • 1
    the logic of your code is unnecessarily complex ... for example, there is no reason to debounce the inputs ... start by watching only the first sensor ... when the first sensor is tripped, make note of the value of millis() and continue watching only the second sensor ... etc. etc Commented Jul 3, 2024 at 19:09
  • Did you send this much data over serial in the working version? At 9600baud that may take like 200ms each loop iteration (as the buffer is not that big I think). And have you tried removing parts of the code, like the LCD code, to narrow down where the problem is Commented Jul 3, 2024 at 19:25
  • Thanks for the comments so far. @jsotola, there is no serial monitor output to upload. The code does not run as the ESP ends up in a ~500ms reboot loop. I also do need SW debounce. I do not want to have to add discreet circuits to HW debounce this and without the SW, i get a lot of stray operations when using the buttons. Commented Jul 3, 2024 at 20:09
  • 1
    code to a level where a dirty input is not a problem ... in your use case, it is not a problem ... multiple contact bounces do not affect the operation ... first contact closure indicates that the event has occured ... subsequent closures are ignored if you no longer watch the contact Commented Jul 4, 2024 at 0:46

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.