Issues with Function Re-entry and Button Press Handling for State Transitions

Hi all,

I'm working on a project where I need to switch between two modes (ICT and FCT) using button presses. A single button press triggers ICT, and a long press triggers FCT. Once in FCT, a single press should keep me in FCT, and a long press should switch to Lux. Similarly, in Lux, I want a single press to go back to FCT.

However, I'm experiencing issues where my code keeps re-entering the void setup functions, starting from the first and the transitions aren't working as expected. Below are some key snippets of my code. I don't know where is the mistake why my code is not working? Can someone please help me.

#include <LiquidCrystal.h>
#include <Wire.h>
#include "SparkFun_VEML6030_Ambient_Light_Sensor.h"

#define AL_ADDR 0x29

SparkFun_Ambient_Light light(AL_ADDR);
const int rs = 12, en = 11, d4 = 3, d5 = 4, d6 = 5, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
float gain = .125;
int time = 100;
long luxVal = 0;
int buttonstate;
int button = 2;
int vPIN = A1;
float voltage;
float R1 = 10000.0;
float R2 = 10000.0;
int value = 0;
int analogPin = A0; 
int raw = 0; 
float Vin = 5.0; 
float Vout = 0; 
float R3 = 0; 
float buffer = 0;
int pin1=13;
int pin2=A3;
int pin3=9;
int pin4=10;
int pin5 = 7;
int pin6 =8;
int r=0;
int lvpin = A2;
int out=0;
float ic_volt;
int sum=0;
int avg=0;
int i=0;
int buf[10]={0};
int count =10;
int total=0;

volatile unsigned long pressStartTime = 0;
volatile unsigned long pressDuration = 0;
volatile bool isPressed = false;
const unsigned long longPressThreshold = 500; // Threshold for long press in ms

bool inFCT = false; // Variable to track if we're in the FCT mode

void buttonPinInterrupt() {
  if (digitalRead(button) == LOW) { // Button pressed
    if (!isPressed) { // Only trigger when button is initially pressed
      pressStartTime = millis();  // Record the time when the button is pressed
      isPressed = true;
    }
  } else { // Button released
    if (isPressed) {
      pressDuration = millis() - pressStartTime; // Calculate press duration
      isPressed = false; // Reset press state
    }
  }
}

void setup() {
  Serial.begin(9600);
  pinMode(button, INPUT_PULLUP); 
  attachInterrupt(digitalPinToInterrupt(button), buttonPinInterrupt, CHANGE); 
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  pinMode(pin5, OUTPUT);
  pinMode(pin6, OUTPUT);
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, LOW);
  digitalWrite(pin5, LOW);
  digitalWrite(pin6, LOW);
  lcd.begin(16, 2);
  
  Wire.begin();
  light.begin();
  
  if(light.begin())
    Serial.println("Ready to sense some light!"); 
  else
    Serial.println("Could not communicate with the sensor!");

  light.setGain(gain);
  light.setIntegTime(time);

  Serial.println("Reading settings..."); 
  Serial.print("Gain: ");
  float gainVal = light.readGain();
  Serial.print(gainVal, 3); 
  Serial.print(" Integration Time: ");
  int timeVal = light.readIntegTime();
  Serial.println(timeVal);
}  

void loop() {
  if (isPressed) {
    return; // Wait until button is released
  }
  
  if (pressDuration > 0) {
    if (pressDuration < longPressThreshold) {
      // Handle single tap
      pressDuration = 0; // Reset
      if (!inFCT) {
        Serial.println("Single tap detected: Executing ICT");
        ICT();  
      } else {
        Serial.println("Single tap detected in FCT: Staying in FCT");
      }
    } else {
      // Handle long press
      pressDuration = 0; // Reset
      if (inFCT) {
        Serial.println("Long press detected in FCT: Switching to Lux");
        Lux();
      } else {
        Serial.println("Long press detected: Executing FCT");
        FCT();  
      }
    }
  }
}


void ICT() 
{
  lcd.clear();
  lcd.setCursor(3, 0); // Set cursor to the first row
  lcd.print("RESISTANCE");
  lcd.setCursor(3,1);
  lcd.print("MEASUREMENT");
  delay(3000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("RESISTANCE MODE");
  lcd.setCursor(0, 1); // Set cursor to the first row
  lcd.print("PROBE-J2,C8,C3");
  delay(500);
  r=1;
  while(r==1)
  {
     raw = analogRead(analogPin); 
     if(raw)
     { 
        buffer = raw * Vin; 
        Vout = (buffer)/1024.0; 
        buffer = (Vin/Vout) - 1; 
        R3 = (R1 * buffer); 
        Serial.println(R3);
        delay(100);
      
        if(R3 > 500 && R3 < 500000)
        {
           digitalWrite(pin1,HIGH);
           digitalWrite(pin2,LOW);
           lcd.clear();
           lcd.setCursor(0, 0); // Set cursor to the first row
           lcd.print("RESISTANCE TEST");
           lcd.setCursor(5,5);
           lcd.print("PASS");
         }
         if(R3 < 500)
         {
           digitalWrite(pin1,LOW);
           digitalWrite(pin2,HIGH);
           lcd.clear();
           lcd.setCursor(0, 0); // Set cursor to the first row
           lcd.print("RESISTANCE TEST");
           lcd.setCursor(3,1);
           lcd.print("FAIL");
         }
         if(R3 > 500000)
         {
             digitalWrite(pin1,LOW);
             digitalWrite(pin2,LOW);
             lcd.clear();
             lcd.setCursor(0,0);
             lcd.print("RESISTANCE MODE");
             lcd.setCursor(0, 1); // Set cursor to the first row
             lcd.print("PROBE-J2,C8,C3");
             delay(500);
         }  
     }  
    buttonstate = digitalRead(button);
    if(buttonstate==LOW)
    {
        Serial.println("ok");
        r=0;
        voltage_res();
    } 
  }
}

void voltage_res() {
  lcd.clear();
  lcd.setCursor(5, 0); 
  lcd.print("VOLTAGE");
  lcd.setCursor(3,1);
  lcd.print("MEASUREMENT");
  delay(3000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("VOLTAGE MODE");
  lcd.setCursor(0, 1);
  lcd.print("PROBE-J2,C8,C3");
  delay(500);
  r = 1;
  while(r == 1) {
    value = analogRead(vPIN);
    voltage = value * (5.0/1024)*((R1 + R2)/R2);
    Serial.print("Voltage =");
    Serial.println(voltage);
    delay(100);
  
    if(voltage > 3.45 && voltage < 4) {
       digitalWrite(pin3,HIGH);
       digitalWrite(pin4,LOW);
       lcd.clear();
       lcd.setCursor(3, 0); 
       lcd.print("VOLTAGE TEST");
       lcd.setCursor(7,1);
       lcd.print("PASS");
    }
  
    if(voltage < 1) {
       digitalWrite(pin3,LOW);
       digitalWrite(pin4,LOW);
       lcd.clear();
       lcd.setCursor(0,0);
       lcd.print("VOLTAGE MODE");
       lcd.setCursor(0, 1);
       lcd.print("PROBE-J2,C8,C3");
       delay(500);
    }
    if(voltage > 4) {
        digitalWrite(pin4,HIGH);
        digitalWrite(pin3,LOW);
        lcd.clear();
        lcd.setCursor(4, 0);
        lcd.print("VOLTAGE TEST");
        lcd.setCursor(7,1);
        lcd.print("FAIL");
    }
 
  buttonstate = digitalRead(button);
    if(buttonstate==LOW)
    {
      r=0;
      Serial.println(buttonstate);
      driver_ic();
    }
   
  }
   
}

void driver_ic()
{
  lcd.clear();
  lcd.setCursor(1, 0); // Set cursor to the first row
  lcd.print("DRIVER IC TEST");
  delay(3000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("DRIVER IC MODE");
  lcd.setCursor(0, 1); // Set cursor to the first row
  lcd.print("PROBE ACROSS C8");
  delay(500);
  r=1;
  while(r==1)
  {
    out = analogRead(lvpin);
    ic_volt = out * (5.0/1024)*((R1 + R2)/R2);
    Serial.print("Voltage =");
    Serial.println(ic_volt);
    delay(100);
    
    if(ic_volt > 1 && ic_volt < 7)
    {
       digitalWrite(pin5,LOW);
       digitalWrite(pin6,HIGH);
       lcd.clear();
       lcd.setCursor(0, 0); // Set cursor to the first row
       lcd.print("DRIVER IC TEST");
       lcd.setCursor(5,1);
       lcd.print("FAIL");
    }
    if(ic_volt < 1)
    {
       digitalWrite(pin5,LOW);
       digitalWrite(pin6,LOW);
       lcd.clear();
       lcd.setCursor(0,0);
       lcd.print("DRIVER IC MODE");
       lcd.setCursor(0, 1); // Set cursor to the first row
       lcd.print("PROBE ACROSS C8");
       delay(500);
    }
    if(ic_volt > 7)
    {
       digitalWrite(pin5,HIGH);
       digitalWrite(pin6,LOW);
       lcd.clear();
       lcd.setCursor(0, 0); // Set cursor to the first row
       lcd.print("DRIVER IC TEST");
       lcd.setCursor(5,1);
       lcd.print("PASS");
    }
    buttonstate = digitalRead(button);
    if(buttonstate==LOW)
    {
       r=0;
       ICT();
    }
  }
}

void FCT() {
  
  inFCT = true; // Set the FCT flag to true
  Serial.println("Entered FCT mode");
 lcd.clear();
  lcd.setCursor(5, 0); 
  lcd.print("LUX VALUE");
  lcd.setCursor(3, 1);
  lcd.print("MONITORING");
  delay(3000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("BEFORE POTTING");
  lcd.setCursor(0, 1);
  lcd.print("PRESS ENTER KEY");

  r = 1;
  while (r == 1) 
  {
    buttonstate = digitalRead(button);
    
    // When button is pressed, process the lux value
    if (buttonstate == LOW) 
    {
       lcd.clear();
       lcd.print("Processing...");
       int lux = light.readLight();
       Serial.print("Ambient Light Reading: ");
       Serial.print(lux);
       Serial.println(" Lux");  
       delay(1000);

       int value = lux - 70;
       sum = 0;

       for (i = 0; i < count; i++) 
       { 
          Serial.println("CAME");        
          buf[i] = value;
          sum += buf[i];
       }
      
       avg = sum / count;
       Serial.println(avg);
         
       // Display PASS/FAIL result
       lcd.clear();
       lcd.setCursor(0, 0); 
       lcd.print("LUX VALUE TEST");
       if (avg <= 115) 
       {
          lcd.setCursor(5, 1);
          lcd.print("PASS");
       }
       else 
       {
          lcd.setCursor(5, 1);
          lcd.print("FAIL");
       }
       delay(5000);  // Short delay to allow user to read result
       r=0;
    }
  }
}

void Lux() 
{
  lcd.clear();
  lcd.setCursor(5, 0); 
  lcd.print("LUX VALUE");
  lcd.setCursor(3, 1);
  lcd.print("MONITORING");
  delay(3000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("AFTER POTTING");
  lcd.setCursor(0, 1);
  lcd.print("PRESS ENTER KEY");
  r = 1;
  while (r == 1) 
  {
    buttonstate = digitalRead(button);
    
    // When button is pressed, process the lux value
    if (buttonstate == LOW) 
    {
       lcd.clear();
       lcd.print("Processing...");
       int lux = light.readLight();
       Serial.print("Ambient Light Reading: ");
       Serial.print(lux);
       Serial.println(" Lux");  
       delay(1000);
       int value = lux - 55;
       sum = 0;

       for (i = 0; i < count; i++) 
       { 
          Serial.println("CAME");        
          buf[i] = value;
          sum += buf[i];
       }
      
       avg = sum / count;
       Serial.println(avg);
       lcd.clear();
       lcd.setCursor(0, 0); 
       lcd.print("LUX VALUE TEST");
       if (avg <= 55) 
       {
          lcd.setCursor(5, 1);
          lcd.print("PASS");
       }
       else 
       {
          lcd.setCursor(5, 1);
          lcd.print("FAIL");
       }
       delay(5000);  // Short delay to allow user to read result
       r=0;

  // Add logic for Lux sensing and exit from FCT
  inFCT = false; // Reset the FCT flag after Lux test
  Serial.println("Completed Lux sensing, exited FCT mode");
 // loop();
}
  }
 
}

Your topic does not seem to indicate a problem with IDE 1.x and hence has been moved to a more suitable location on the forum.

1 Like

This

code keeps re-entering the void setup functions

shouldn't happen and usually means you have some kind of not-software problem. Please say what all is attached and how power is provided; a schematic would be nice. Hand drawn is easiest, take a snap and post it.

Paste a complete sketch.

Your description seems incomplete.

If ICT and FCT are modes, where do we start? Not in either?

Once FCT is entered, you can switch between FCT and Lux. Is there no way or no need to switch to ICT?

Yes, perhaps scrutiny of your partial code woukd reveal the parts that aren't clear of how this is to work.

Why are you using interrupts to handle the button? Is the button operated by a human?

This seems like a place for regular button handling. Use a library we can recommend several that will take care of reporting presses and releases and long and short, and use a finite state machine to move between states.

The triggered functions could probably be freed of any need to look at the button.

Yes, a total rewrite. I'm in a bad mood, never mind about that, and the code you did post is not inviting me to look closer.

It seems like the actual work parts could be salvaged and used to inform the creation of a state machine approach using the IPO model. Read about it here in the abstract:

The IPO Model

It just means your loop checks for inputs, does some processing based on the current state and those inputs, then acts or prints or whatever. Rinse and repeat.

It can feel like turning a traditional program inside out, and is key to leveraging the resources in the little computers we play with.

a7

Thanks for your reply. My goal is if the human press the button for single time it should go to ICT loop and do the function if the person press the button for long time it should go to FCT loop and do the function again inside the FCT loop it should check for button press if the button is pressed for single time it should stay in FCT loop and if long press happens it should go to lux loop. If I do this my code is going to ICT loop and coming of the ICT loop and going to void setup function again and again. This is happening actually without using interrupts and using buttonstate I have checked the same thing is hapenning.

So if you were to modify any sketch you've tried as follows

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

//... 

you would see "running setup" when you were not expecting it?

Then you probably have a hardware issue.

a7

Here's a sketch that moves between states with button presses short and long. It is my hope that this wets your appetite for the approach I am advocating. We wrote it under the umbrella and tested it with the Wokwi simulator. It was maybe what you are going for, hard to say.

Try it here:

Wokwi_badge UA FSM Example


The code:
// https://wokwi.com/projects/409656968534780929
// https://forum.arduino.cc/t/issues-with-function-re-entry-and-button-press-handling-for-state-transitions/1303722

# include <EasyButton.h>

# define BUTTON_PIN 2

# define BAUDRATE 115200

EasyButton button(BUTTON_PIN);

bool xShortPress;
bool xLongPress;

void longPress()
{
  xLongPress = true;
}

void shortPress()
{
  xShortPress = true;
}

void setup()
{
  // Initialize Serial for debuging purposes.
  Serial.begin(BAUDRATE);
  Serial.println();

  button.begin();
 
  button.onPressedFor(500, longPress);
  button.onPressed(shortPress);
}

enum {IDLE, ICT, FCT, LUX, NO_STATE};
byte state = IDLE;

char *tags[] = {"Idle.", "ICT", "FCT", "LUX", "Rotten Denamrk!"};

void loop() {

  xLongPress = false;
  xShortPress = false;
  
  button.read();

// whatcha doing, Marshall McLuhan?
  static byte printedState = NO_STATE;
  static int couter;
  if (printedState != state) {
    Serial.print(couter); couter++;
    Serial.print(" : ");
    Serial.println(tags[state]);

    printedState = state;
  }
  
  switch (state) {
  case IDLE :
    if (xShortPress) state = ICT;
    if (xLongPress) state = FCT;

    break;

  case ICT :
//    Serial.println("do ICT.");
    state = IDLE;

    break;

  case FCT :
//    Serial.println("doing FCT.");
    if (xShortPress) state = IDLE;
    if (xLongPress) state = LUX;

    break;

  case LUX :
//    Serial.println("doing LUX.");
    if (xShortPress) state = IDLE;
    if (xLongPress) state = FCT;

    break;
  }
}

// test loop to learn up on EasyButton
void loop0()
{
  button.read();

  if (xShortPress) {
    Serial.println("button pressed");
    xShortPress = false; // handled
  }
  
  if (xLongPress) {
    Serial.println("button long pressed");
    xLongPress = false; // handled
  }
}

If you go from this, you will need to download the EasyButton library by evert-arias, see

HTH

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.