Running second loop from menu

HI,

I wonder if someone could assist please.

I have some code using an ESP32 with 2 hardware buttons. Essentially when the device is powered on, you are given a small menu that states Button 1 runs a program and Button 2 shows the voltage of the device. A long (2 sec) press of Button 2 puts the device into deep sleep.

It all sort of works, however when Button 1 is pressed, the main program only runs once. If I press Button 1 again, it runs again and so on.

What is the best method to introduce another loop into 'second_loop()' so that it runs continuously if Button 1 is pressed once or until Button 2 is pressed again please.

Code snipet below of main parts and structure.

Many thanks :slight_smile:

#include <TFT_eSPI.h>

//#define TFT_BL 4 // Display backlight control pin
#define ADC_EN 14
#define ADC_PIN 34
#define BUTTON_1 35
#define BUTTON_2 0

Button2 btn1(BUTTON_1);
Button2 btn2(BUTTON_2);

char buff[512];
int vref = 1100;
int btnCick = false;

void showVoltage()
{
    static uint64_t timeStamp = 0;
    if (millis() - timeStamp > 1000) {
        timeStamp = millis();
        uint16_t v = analogRead(ADC_PIN);
        float battery_voltage = ((float)v / 4095.0) * 2.0 * 3.3 * (vref / 1000.0);
        String voltage = "Voltage :" + String(battery_voltage) + "v";
        Serial.println(voltage);
        tft.fillScreen(TFT_BLACK);
        tft.setTextDatum(MC_DATUM);
        tft.setTextSize(2);
        tft.drawString(voltage,  tft.width() / 2, tft.height() / 2 );
    }
}

void button_init()
{
    btn1.setLongClickHandler([](Button2 & b) {
        btnCick = false;
        int r = digitalRead(TFT_BL);
        tft.fillScreen(TFT_BLACK);
        tft.setTextColor(TFT_GREEN, TFT_BLACK);
        tft.setTextDatum(MC_DATUM);
        tft.setTextSize(1);
        tft.drawString("Press again to wake up",  tft.width() / 2, tft.height() / 2 );
        espDelay(6000);
        digitalWrite(TFT_BL, !r);

        tft.writecommand(TFT_DISPOFF);
        tft.writecommand(TFT_SLPIN);
        //After using light sleep, you need to disable timer wake, because here use external IO port to wake up
        esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
        // esp_sleep_enable_ext1_wakeup(GPIO_SEL_35, ESP_EXT1_WAKEUP_ALL_LOW);
        esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0);
        delay(200);
        esp_deep_sleep_start();
    });
    btn1.setPressedHandler([](Button2 & b) {
        Serial.println("Detect Voltage..");
        btnCick = true;
    });

    btn2.setPressedHandler([](Button2 & b) {
        btnCick = false;
        Serial.println("btn press begin second loop");
        second_loop();
    });
}

void button_loop()
{
    btn1.loop();
    btn2.loop();
}

void setup() {
  pinMode(ADC_EN, OUTPUT);
  digitalWrite(ADC_EN, HIGH);
  
  button_init();

  esp_adc_cal_characteristics_t adc_chars;
  esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars);    //Check type of calibration value used to characterize ADC
  if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
      Serial.printf("eFuse Vref:%u mV", adc_chars.vref);
      vref = adc_chars.vref;
  } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
      Serial.printf("Two Point --> coeff_a:%umV coeff_b:%umV\n", adc_chars.coeff_a, adc_chars.coeff_b);
  } else {
      Serial.println("Default Vref: 1100mV");
  }

  // Rest of Setup Code
}

void loop()
{
    if (btnCick) {
        showVoltage();
    }
    button_loop();
}

void second_loop()
{
  tft.setTextDatum(TL_DATUM);
  tft.fillScreen(TFT_BLACK);
  tft.setTextSize(1);
  tft.setTextColor(TFT_DARKGREY, TFT_BLACK);
  tft.drawString("Build - ", 5, 115, 2);
  tft.drawString((char *) build_date, 55, 115, 2);
  
  // Main Second Loop Code
}

ESP32 has ability to run program on 2 cores, put another loop on second core

Thank you @killzone_kid

I was not aware of that, so thank you for pointing it out. By putting another loop in the second core, will that run constantly as I would only like the second loop to run once Button 1 is pushed (which I presmume is running from the first core).

Are you perhaps able to give a code example please?

Many thanks.

You should post your complete sketch. You are using some kind of button-library but the part that includes and defines the buttons is missing.

This makes it impossible to modify your code and do a compile-test.

Of course an ESP32 can run code in the second core. I have never used this until now.
The other approach is to make your code non-blocking. For this I would need the complete sketch.

Additional I'm unsure what you mean with writing

You have to clearly specifiy what "it runs continiously" means.
You have void loop that is continiously looping.
You have to write down the names of all functions you wish to run continiously

best regards Stefan

There's no need for that ESP32 runs FreeRTOS that supports multiple tasks running on the same core. These tasks can be controlled via inter-task communications techniques (notifications, queues, semaphores, etc) to run / suspend as required.

But, I suspect simpler, more traditional Arduino "multitasking" techniques would solve your problem. It all starts with the "Blink without Delay" example in the Arduino IDE.

is contradictionary to

You should rename your buttons and variables to clearly reflect what they are used for.
This will make it much easier to analyse the code

instead of "btn1" you should name it btnShowVolt
instead of "btn2" you should name it btnStartPrg

or something similar

You use variable btnCick for both buttons. I don't fully understand the logic of your code but my feeling says using the same boolean variable for two different buttons is a bad idea.

best regards Stefan

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