Button used in two situations

Hi,
Here is the code of my project. I simplified it . The purpose is to automatically fill bottles (with beer !) using a scale and a pump driven by a PWM signal with a mosfet board
I did a simple user interface. I have a “menu" with 3 items and I can change the selected item with my rotary encoder. When I press button_encodeur, the push button of the rotary encoder, I can launch the callback of the selected item. Everything is working well.
When I selected item 2, I can start “action_2” which will fill the bottle with the pump using the PWM signal.
My problems are :

  1. I want to use the same button_encodeur for my menu interface and also to stop the pump in case of problem during the filling in action 2 (ie switching stop_button to true) . I thought about long pressing the button with the longpress_button_encodeur callback but it does not work. I did try to create an interrupt with the button while using it as a normal button. It quite works, but is is so ugly… and then I have problem 2. Is there a nice way to do it ?
  2. EMC ! Without power input on the pump, I don"t have problems. With the power, the pump start few seconds and stops because, for some reason it trigger the interrup of the longpress_button_encodeur ! It is not a power problem. I have a separate power supply for the pump. I am using this board Panneau de commande pour arduino, interrupteur à gâchette MOS FET, Module d'entraînement, régulateur PWM, 15a, 400W | AliExpress

Thanks for your comments

#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include "OneButton.h"
#include <ESP32Encoder.h>


#include "HX711.h"
// HX711 circuit wiring  -Alimentation en 5v
#define DOUT 0
#define CLK  2
HX711 scale;
const float calibration_factor = -1103;


boolean stop_button = false;
static const int pin_pwm_pump = 21;


#define PIN_button_encodeur 13

OneButton button_encodeur(PIN_button_encodeur, true);


ESP32Encoder encoder;
int last_roto = 0;
int nb_buttons_menu = 3;
int item_selected = 0;


void action_0() {
  Serial.println("Action 0");
  delay(100);
}

void action_1() {
  Serial.println("Action 1");
  delay(200);

}

void action_2() {
  Serial.println("Action 2");
  stop_button == false;

  unsigned long time_now = 0;
  int period = 100;

  scale.power_up();

  float weight = scale.get_units();
  float old_weight;


  float final_weight = 300;

  // PWM ON
  ledcWrite(0, 128);

  while ((stop_button == false) && (weight < final_weight))
  {
    weight = scale.get_units();
    
    Serial.print("weight");
    Serial.println(weight);


    // wait 100ms
    while (millis() < time_now + period) {
      //wait approx. [period] ms
    }

  }

  // PWM OFF
  ledcWrite(0, 0);
  scale.power_down();              // put the ADC in sleep mode


}

void (*menu_callbacks[1][3])(void) = {
  { action_0, action_1, action_2}
};


void click_button_encodeur() {
  Serial.println("click");

  menu_callbacks[0][item_selected]();
}

void longpress_button_encodeur() {
  Serial.println("long_click");
  stop_button = true;
}


void encodeur() {

  int new_value = (int32_t)encoder.getCount() / 2;

  if (new_value != last_roto) {

    item_selected += new_value;
    if (item_selected  >= nb_buttons_menu  ) item_selected = 0;
    if (item_selected  <= -1 ) item_selected = nb_buttons_menu - 1;
    last_roto = 0;
    encoder.setCount(last_roto);

    Serial.print("item_selected ");
    Serial.println(item_selected);


  }

}


void setup(void) {

  //Serial
  Serial.begin(57600); // For debug
  delay(200);


  ////////////////////////////////////////// scale
  scale.begin(DOUT, CLK);
  scale.set_scale();
  scale.tare();  //Reset the scale to 0
  scale.set_scale(calibration_factor); //Adjust to this calibration factor



  // Boutons
  // 500ms for long press button
  button_encodeur.setPressTicks(500);
  button_encodeur.attachClick(click_button_encodeur);
  button_encodeur.attachLongPressStop(longpress_button_encodeur);

  // Encodeur
  ESP32Encoder::useInternalWeakPullResistors = UP;
  // Attache pins for use as encoder pins
  encoder.attachHalfQuad(12, 14);
  encoder.setCount(last_roto);


  // PWM on channel 0 for the pump
  ledcAttachPin(pin_pwm_pump, 0);
  ledcSetup(0, 20000, 7);
  ledcWrite(0, 0);


  // First Menu
  Serial.print("item_selected ");
  Serial.println(item_selected);


}


void loop() {
  button_encodeur.tick();
  encodeur();

}

I thought about long pressing the button with the longpress_button_encodeur callback but it does not work.

"does not work" is not a helpful description.

Does your code detect the long press and print "long_click"?

What piece of the code is supposed to respond when stop_button == true?

I solved my problem 1) with the following code. I will post problem 2 in a second thread.
Thanks

#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include "OneButton.h"
#include <ESP32Encoder.h>


#include "HX711.h"
// HX711 circuit wiring  -Alimentation en 5v
#define DOUT 0
#define CLK  2
HX711 scale;
const float calibration_factor = -1103;


boolean stop_button = false;
static const int pin_pwm_pump = 21;


#define PIN_button_encodeur 13

OneButton button_encodeur(PIN_button_encodeur, true);

void IRAM_ATTR button_interrupt() {
  stop_button = true;

}

ESP32Encoder encoder;
int last_roto = 0;
int nb_buttons_menu = 3;
int item_selected = 0;


void action_0() {
  Serial.println("Action 0");
  delay(100);
}

void action_1() {
  Serial.println("Action 1");
  delay(200);

}

void action_2() {
  Serial.println("Action 2");
  stop_button = false;
  unsigned long time_now = 0;
  int period = 100;

  scale.power_up();

  float weight = scale.get_units();
  float final_weight = 300;

  // PWM ON
  ledcWrite(0, 128);

  while ((stop_button == false) && (weight < final_weight))
  {
    weight = scale.get_units();

    Serial.print("weight ");
    Serial.println(weight);


    // wait 100ms
    while (millis() < time_now + period) {
      //wait approx. [period] ms
    }

  }

  // PWM OFF
  ledcWrite(0, 0);
  scale.power_down();              // put the ADC in sleep mode


}

void (*menu_callbacks[1][3])(void) = {
  { action_0, action_1, action_2}
};


void click_button_encodeur() {
  Serial.println("click");
  menu_callbacks[0][item_selected]();
}




void encodeur() {

  int new_value = (int32_t)encoder.getCount() / 2;

  if (new_value != last_roto) {

    item_selected += new_value;
    if (item_selected  >= nb_buttons_menu  ) item_selected = 0;
    if (item_selected  <= -1 ) item_selected = nb_buttons_menu - 1;
    last_roto = 0;
    encoder.setCount(last_roto);

    Serial.print("item_selected ");
    Serial.println(item_selected);


  }

}


void setup(void) {

  //Serial
  Serial.begin(57600); // For debug
  delay(200);


  ////////////////////////////////////////// scale
  scale.begin(DOUT, CLK);
  scale.set_scale();
  scale.tare();  //Reset the scale to 0
  scale.set_scale(calibration_factor); //Adjust to this calibration factor



  // Boutons
  //  attachInterrupt(digitalPinToInterrupt(PIN_button_encodeur), checkTicks, CHANGE);
  attachInterrupt(PIN_button_encodeur, button_interrupt, RISING);


  // 500ms for long press button
  button_encodeur.setPressTicks(500);
  button_encodeur.attachClick(click_button_encodeur);

  // Encodeur
  ESP32Encoder::useInternalWeakPullResistors = UP;
  // Attache pins for use as encoder pins
  encoder.attachHalfQuad(12, 14);
  encoder.setCount(last_roto);


  // PWM on channel 0 for the pump
  ledcAttachPin(pin_pwm_pump, 0);
  ledcSetup(0, 20000, 7);
  ledcWrite(0, 0);


  // First Menu
  Serial.print("item_selected ");
  Serial.println(item_selected);


}


void loop() {
  button_encodeur.tick();
  encodeur();

}

I don't know anything about the encoder library you are using but it seems to me there is no need for a long press. Instead have a variable that keeps track of the state of the system - it might have the value 'W' for waiting or 'F' for filling. Then if the button is pressed while the system is Filling the program would know to stop everything - something like this pseudo code

if (button is pressed) {
   if (systemState == 'W') {
      // code for normal response to button
   }
   else if (systemState == 'F') {
      stop everything
   }
}

...R

Hi,
Here is the code of my project. I simplified it . The purpose is to automatically fill bottles (with beer !) using a scale and a pump driven by a PWM signal with a mosfet board

I did a simple user interface. I have a "menu" with 3 items and I can change the selected item with my rotary encoder. When I press button_encodeur, the push button of the rotary encoder, I can launch the callback of the selected item. Everything is working well.

When I selected item 2, I can start "action_2" which will fill the bottle with the pump using the PWM signal.
My problems is I think related to EMC. Without power input on the mosfet board, pump, I dont have problems. I can see the LED on the mosfet board indicating that the PWM is 100%. With the power, the pump start few seconds and stops. The button_interrupt, for some reason, is triggered ! I have a powerful power supply. Without the interrupt function, the pump does not stop.

I have a separate power supply for the pump. I am using this board Panneau de commande pour arduino, interrupteur à gâchette MOS FET, Module d'entraînement, régulateur PWM, 15a, 400W | AliExpress

You can see my ugly schematic

Thanks for your comments

#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include "OneButton.h"
#include <ESP32Encoder.h>


#include "HX711.h"
// HX711 circuit wiring  -Alimentation en 5v
#define DOUT 0
#define CLK  2
HX711 scale;
const float calibration_factor = -1103;


boolean stop_button = false;
static const int pin_pwm_pump = 21;


#define PIN_button_encodeur 13

OneButton button_encodeur(PIN_button_encodeur, true);

void IRAM_ATTR button_interrupt() {
  stop_button = true;

}

ESP32Encoder encoder;
int last_roto = 0;
int nb_buttons_menu = 3;
int item_selected = 0;


void action_0() {
  Serial.println("Action 0");
  delay(100);
}

void action_1() {
  Serial.println("Action 1");
  delay(200);

}

void action_2() {
  Serial.println("Action 2");
  stop_button = false;
  unsigned long time_now = 0;
  int period = 100;

  scale.power_up();

  float weight = scale.get_units();
  float final_weight = 300;

  // PWM ON
  ledcWrite(0, 128);

  while ((stop_button == false) && (weight < final_weight))
  {
    weight = scale.get_units();

    Serial.print("weight ");
    Serial.println(weight);


    // wait 100ms
    while (millis() < time_now + period) {
      //wait approx. [period] ms
    }

  }

  // PWM OFF
  ledcWrite(0, 0);
  scale.power_down();              // put the ADC in sleep mode


}

void (*menu_callbacks[1][3])(void) = {
  { action_0, action_1, action_2}
};


void click_button_encodeur() {
  Serial.println("click");
  menu_callbacks[0][item_selected]();
}




void encodeur() {

  int new_value = (int32_t)encoder.getCount() / 2;

  if (new_value != last_roto) {

    item_selected += new_value;
    if (item_selected  >= nb_buttons_menu  ) item_selected = 0;
    if (item_selected  <= -1 ) item_selected = nb_buttons_menu - 1;
    last_roto = 0;
    encoder.setCount(last_roto);

    Serial.print("item_selected ");
    Serial.println(item_selected);


  }

}


void setup(void) {

  //Serial
  Serial.begin(57600); // For debug
  delay(200);


  ////////////////////////////////////////// scale
  scale.begin(DOUT, CLK);
  scale.set_scale();
  scale.tare();  //Reset the scale to 0
  scale.set_scale(calibration_factor); //Adjust to this calibration factor



  // Boutons
  //  attachInterrupt(digitalPinToInterrupt(PIN_button_encodeur), checkTicks, CHANGE);
  attachInterrupt(PIN_button_encodeur, button_interrupt, RISING);


  // 500ms for long press button
  button_encodeur.setPressTicks(500);
  button_encodeur.attachClick(click_button_encodeur);

  // Encodeur
  ESP32Encoder::useInternalWeakPullResistors = UP;
  // Attache pins for use as encoder pins
  encoder.attachHalfQuad(12, 14);
  encoder.setCount(last_roto);


  // PWM on channel 0 for the pump
  ledcAttachPin(pin_pwm_pump, 0);
  ledcSetup(0, 20000, 7);
  ledcWrite(0, 0);


  // First Menu
  Serial.print("item_selected ");
  Serial.println(item_selected);


}


void loop() {
  button_encodeur.tick();
  encodeur();

}

void IRAM_ATTR button_interrupt() {
  stop_button = true;}
//boolean stop_button = false;
volatile boolean stop_button = false;

Because the stop_button variable is changed in the interrupt and accessed in the main code ti should be declared as volatile.

Thanks cattledog. But It was not enough. The DC motor does create too much perturbation that it still triggers the interruption.
Anyway I found my solution. Each time, the interruption is triggered, it only checks the button state. And I create a doubleclick action. This way I don’t have any more problems. See the code below

#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include "OneButton.h"
#include <ESP32Encoder.h>


#include "HX711.h"
// HX711 circuit wiring  -Alimentation en 5v
#define DOUT 0
#define CLK  2
HX711 scale;
const float calibration_factor = -1103;


volatile boolean stop_button = false;
static const int pin_pwm_pump = 21;


#define PIN_button_encodeur 13

OneButton button_encodeur(PIN_button_encodeur, true);


ICACHE_RAM_ATTR void checkTicks()
{
  // include all buttons here to be checked
  button_encodeur.tick(); // just call tick() to check the state.
}

ESP32Encoder encoder;
int last_roto = 0;
int nb_buttons_menu = 3;
int item_selected = 0;


void action_0() {
  Serial.println("Action 0");
  delay(100);
}

void action_1() {
  Serial.println("Action 1");
  delay(200);

}

void action_2() {
  Serial.println("Action 2");
  stop_button = false;
  unsigned long time_now = 0;
  int period = 100;

  scale.power_up();

  float weight = scale.get_units();
  float final_weight = 300;

  // PWM ON
  ledcWrite(0, 128);

  while ((stop_button == false) && (weight < final_weight))
  {
    weight = scale.get_units();

    Serial.print("weight ");
    Serial.println(weight);


    // wait 100ms
    while (millis() < time_now + period) {
      //wait approx. [period] ms
    }

  }

  // PWM OFF
  ledcWrite(0, 0);
  scale.power_down();              // put the ADC in sleep mode


}

void (*menu_callbacks[1][3])(void) = {
  { action_0, action_1, action_2}
};


void click_button_encodeur() {
  Serial.println("click");
  menu_callbacks[0][item_selected]();
}

void doubleClick()
{
  Serial.println("doubleClick detected.");
  stop_button = true;

}



void encodeur() {

  int new_value = (int32_t)encoder.getCount() / 2;

  if (new_value != last_roto) {

    item_selected += new_value;
    if (item_selected  >= nb_buttons_menu  ) item_selected = 0;
    if (item_selected  <= -1 ) item_selected = nb_buttons_menu - 1;
    last_roto = 0;
    encoder.setCount(last_roto);

    Serial.print("item_selected ");
    Serial.println(item_selected);


  }

}


void setup(void) {

  //Serial
  Serial.begin(57600); // For debug
  delay(200);


  ////////////////////////////////////////// scale
  scale.begin(DOUT, CLK);
  scale.set_scale();
  scale.tare();  //Reset the scale to 0
  scale.set_scale(calibration_factor); //Adjust to this calibration factor



  // Boutons
  //  attachInterrupt(digitalPinToInterrupt(PIN_button_encodeur), checkTicks, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_button_encodeur), checkTicks, CHANGE);


  // 500ms for long press button
  button_encodeur.setPressTicks(500);
  button_encodeur.attachClick(click_button_encodeur);
  button_encodeur.attachDoubleClick(doubleClick);


  // Encodeur
  ESP32Encoder::useInternalWeakPullResistors = UP;
  // Attache pins for use as encoder pins
  encoder.attachHalfQuad(12, 14);
  encoder.setCount(last_roto);


  // PWM on channel 0 for the pump
  ledcAttachPin(pin_pwm_pump, 0);
  ledcSetup(0, 20000, 7);

  // PWM A zero au cas ou...
  ledcWrite(0, 0);


  // First Menu
  Serial.print("item_selected ");
  Serial.println(item_selected);


}


void loop() {
  button_encodeur.tick();
  encodeur();

}

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