Shrink this Button code

Is there a way to make the code smaller (less space on arduino)
it uses a lot of variables (Yes i made it)
I do not know how to make the same logic with less variables.

onbuttonReleased
buttonPressed
holdbutton

void setup() {
  Serial.begin(115200);
  // put your setup code here, to run once:
 initalizeSetup();
}

void loop() {
  // put your main code here, to run repeatedly:
  
  if(buttonPressed(0)){
    Serial.println("b1 down");
  }
  /* pin, repeat each 500 millis, if you hold it*/
  if(buttonPressed(1,500)){
    Serial.println("b2 down");
  }
  /* pin, repeat each 500 millis, after 5 seconds*/
  if(buttonPressed(2,500,5000)){
    Serial.println("b3 down");
  }
  if(buttonPressed(3)){
    Serial.println(isbuttonDown(1)?"b1 is down":"b1 is up");
  }


    if(onbuttonReleased(0)){
    Serial.println("b1 realeased");
  }

    if(onbuttonReleased(1)){
    Serial.println("b2 realeased");
  }
    if(onbuttonReleased(2)){
    Serial.println("b3 realeased");
  }
    if(onbuttonReleased(3)){
    Serial.println("b4 realeased");
  }
  
}

/*define pins for the buttons*/
/*do not forget to change number_of_buttons*/
const int buttonpins[] = {A0,A1,3,4};
const int number_of_buttons = 4;

/*remove if you dont need*/
bool btdown[number_of_buttons];
bool cycle[number_of_buttons];
bool registeredPress[number_of_buttons];
bool btreleased[number_of_buttons];
bool RepeatPressedActionifHolding[number_of_buttons];
int btnreleaseinterval[number_of_buttons];
int RepeatPressedActionInterval[number_of_buttons];
int RepeatPressedActionAfter_X_millis_Interval[number_of_buttons];
unsigned long previousMillis[number_of_buttons];
unsigned long FirstMillis[number_of_buttons];
unsigned long currentMillis=0;

void initalizeSetup(){  
  //int *myArray = (int *) malloc(numberOfEntries * sizeof(int));  
  for(int i=0;i<number_of_buttons;i++){
    /*use pullup inside arduino*/
    /*connect switch to ground not to vcc!*/
    pinMode(buttonpins[i],INPUT_PULLUP);
    btnreleaseinterval[i]=100;
    btdown[i]=false;
    previousMillis[i]=0;
    registeredPress[i]=false;
    btreleased[i]=false;
    RepeatPressedActionifHolding[i]=false;
    RepeatPressedActionAfter_X_millis_Interval[i]=0;
    RepeatPressedActionInterval[i]=0;
    FirstMillis[i]=0;
    cycle[i]=false;
 }

}



/*remove if you dont need*/
bool onbuttonReleased(int btn){
  if(!registeredPress[btn]&&btreleased[btn]){
    btreleased[btn]=false;
    return true;
  }
  return false;
}
/*remove if you dont need*/
bool isbuttonDown(int btn){
  return registeredPress[btn];
}

bool buttonPressed(int btn,int repeatInterval){
  return buttonPressed(btn,repeatInterval,repeatInterval);
}

bool buttonPressed(int btn,int repeatInterval,int After_X_millis_Interval){
  RepeatPressedActionifHolding[btn]=true;
  RepeatPressedActionInterval[btn]=repeatInterval;
  RepeatPressedActionAfter_X_millis_Interval[btn]=After_X_millis_Interval;
  return buttonPressed(btn);
}

bool buttonPressed(int btn){
  btdown[btn]=!digitalRead(buttonpins[btn]);
  /*ask the time*/
  currentMillis=millis();
    if(btdown[btn])
  {
     previousMillis[btn] = currentMillis;
     /*if you click the button, it will return a true*/
     /*so your code will run at this point, It will only run once! except if you enable Holding*/
     if(!registeredPress[btn])
       {
          FirstMillis[btn] = currentMillis;
          registeredPress[btn]=true;
          return true;
       }
  } 
  /*handle hold after first cycle*/
if(cycle[btn]&&btdown[btn]&& registeredPress[btn]&& (unsigned long)currentMillis - FirstMillis[btn] >= (unsigned long)(RepeatPressedActionInterval[btn]) && RepeatPressedActionifHolding[btn]){
        FirstMillis[btn] = (unsigned long)currentMillis;
        RepeatPressedActionifHolding[btn]=false;
        return true;
   }
   /*handle hold*/
if(!cycle[btn]&&btdown[btn]&& registeredPress[btn]&& (unsigned long)currentMillis - FirstMillis[btn] >= (unsigned long)(RepeatPressedActionAfter_X_millis_Interval[btn]) && RepeatPressedActionifHolding[btn]){
         FirstMillis[btn] = (unsigned long)currentMillis;
         cycle[btn]=true;
        RepeatPressedActionifHolding[btn]=false;
        return true;
   }
  /*check if you are still holding the button (corrects a faulty button)*/
  if(!btdown[btn]&&registeredPress[btn]&& (unsigned long)(currentMillis - previousMillis[btn]) >= btnreleaseinterval[btn])
  {
    cycle[btn]=false;
    btreleased[btn]=true;
    registeredPress[btn]=false;
  }
  return false;
}

You could save memory by not explicitly initialising globals to zero/false.
You could use smaller variables or even single bits for some variables.
What do you want to save? RAM or flash?

I want to have SD card + oled + buttons + more (I had to edit the oled code to.)
this code alone uses 20% of my local variables

What are you trying to save? RAM or flash?

for(int i=0;i<number_of_buttons;i++){
    pinMode(buttonpins[i],INPUT_PULLUP);
    btnreleaseinterval[i]=100;
 }

Where a number will never exceed 255 use a byte rather than an int. In this line, for example

const int buttonpins[] = {A0,A1,3,4};

...R

It is so complicated now. I want it to be simple and not using a lot of variables but more logic.

Robin2:
Where a number will never exceed 255 use a byte rather than an int. In this line, for example

const int buttonpins[] = {A0,A1,3,4};

...R

Ty so much, i will look in to it!

You could lose all the "btn-1" stuff, simply by starting numbering your items from zero.

TolpuddleSartre:
You could lose all the “btn-1” stuff, simply by starting numbering your items from zero.

you are right but that is just to make it easy

geyhax:
you are right but that is just to make it easy

?

It makes your code more complicated.

TolpuddleSartre:
?

It makes your code more complicated.

if i want to look if the first button is pressed i will type in 1 not 0 it will distract me while coding

Whatever - I thought you were looking for advice and help.

TolpuddleSartre:
Whatever - I thought you were looking for advice and help.

geyhax:
you are right but that is just to make it easy

you are right<< I do appreciate it, but that is not what i meant. I will remove it

Just delete this intire topic then if you bullshitting around, My English is not so well.

I can't delete a topic, only my responses.
You can't delete the topic, only your responses.

I offered and gave advice and code, so to be accused of bullshitting means I leave you to your problem now.

C arrays start at zero. Learn to live with it.

What you are trying to do is fairly complicated and is going to take about as much code as you have written, regardless of how it is done.

However, you can definitely get rid of a great deal of the bulk of your code by using a class rather than using a number of corresponding arrays. Classes allow you to bundle together variables and the code that used those variables.

It's a fun little exercise. Seeing as you have had the courtesy to post code that compiles, I'll just do the refactor as an exercise and post the result. Give me a minute …

OK!

Here’s your original sketch refactored using a class. The sketch should do exactly what it did before, but the code has been reorganised. That is: if your original sketch works, then this should work too. IF your original sketch didn’t work, then this should not work in exactly the same way:

class Button {
    const byte pin;

    bool btdown = false;
    bool cycle = false;
    bool registeredPress = false;
    bool btreleased = false;
    bool RepeatPressedActionifHolding = false;
    int btnreleaseinterval = 100;
    int RepeatPressedActionInterval = 0;
    int RepeatPressedActionAfter_X_millis_Interval = 0;
    unsigned long previousMillis = 0;
    unsigned long FirstMillis = 0;

  public:
    Button(byte pin) : pin(pin) {}

    void setup() {
      pinMode(pin, INPUT_PULLUP);
    }

    bool onReleased() {
      if (!registeredPress && btreleased) {
        btreleased = false;
        return true;
      }
      return false;
    }

    bool isDown() {
      return registeredPress;
    }

    bool pressed(int repeatInterval) {
      return pressed(repeatInterval, repeatInterval);
    }

    bool pressed(int repeatInterval, int After_X_millis_Interval) {
      RepeatPressedActionifHolding = true;
      RepeatPressedActionInterval = repeatInterval;
      RepeatPressedActionAfter_X_millis_Interval = After_X_millis_Interval;
      return pressed();
    }

    bool pressed() {
      btdown = !digitalRead(pin);
      /*ask the time*/
      const unsigned long currentMillis = millis();
      if (btdown)
      {
        previousMillis = currentMillis;
        /*if you click the button, it will return a true*/
        /*so your code will run at this point, It will only run once! except if you enable Holding*/
        if (!registeredPress)
        {
          FirstMillis = currentMillis;
          registeredPress = true;
          return true;
        }
      }
      /*handle hold after first cycle*/
      if (cycle && btdown && registeredPress && (unsigned long)currentMillis - FirstMillis >= (unsigned long)(RepeatPressedActionInterval) && RepeatPressedActionifHolding) {
        FirstMillis = (unsigned long)currentMillis;
        RepeatPressedActionifHolding = false;
        return true;
      }
      /*handle hold*/
      if (!cycle && btdown && registeredPress && (unsigned long)currentMillis - FirstMillis >= (unsigned long)(RepeatPressedActionAfter_X_millis_Interval) && RepeatPressedActionifHolding) {
        FirstMillis = (unsigned long)currentMillis;
        cycle = true;
        RepeatPressedActionifHolding = false;
        return true;
      }
      /*check if you are still holding the button (corrects a faulty button)*/
      if (!btdown && registeredPress && (unsigned long)(currentMillis - previousMillis) >= btnreleaseinterval)
      {
        cycle = false;
        btreleased = true;
        registeredPress = false;
      }
      return false;
    }
};

Button button[] = {
  Button(A0), Button(A1), Button(3), Button(4)
};

const int number_of_buttons = sizeof(button) / sizeof(*button);

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < number_of_buttons; i++) {
    button[i].setup();
  }
}

void loop() {
  // put your main code here, to run repeatedly:

  if (button[0].pressed()) {
    Serial.println("b1 down");
  }
  /* pin, repeat each 500 millis, if you hold it*/
  if (button[1].pressed(1, 500)) {
    Serial.println("b2 down");
  }
  /* pin, repeat each 500 millis, after 5 seconds*/
  if (button[2].pressed(500, 5000)) {
    Serial.println("b3 down");
  }
  if (button[3].pressed()) {
    Serial.println(button[1].isDown() ? "b1 is down" : "b1 is up");
  }

  for(int i = 0 ; i<number_of_buttons; i++) {
    if (button[i].onReleased()) {
      Serial.print("b");
      Serial.print(i+1);
      Serial.println(" released");
    }
  }

}

With this done, you can do several things. You can move the class into its own .hpp and .cpp files if you want.

Another useful thing to do would be to use descriptive names for the buttons rather than using array indexes. (I don’t know what names would be appropriate, so I’ll make something up :slight_smile: ). To accomplish this, you just need to revisit the stuff outside the class definition.

Again, this code should do the same as your original sketch (except that I have changed the messages).

Button btnLeft = Button(A0);
Button btnRight = Button(A1);
Button btnDoor = Button(3);
Button btnWindow = Button(4);

void setup() {
  Serial.begin(115200);
  btnLeft.setup();
  btnRight.setup();
  btnDoor.setup();
  btnWindow.setup();
}

void loop() {
  // put your main code here, to run repeatedly:

  if (btnLeft.pressed()) {
    Serial.println("left!");
  }
  /* pin, repeat each 500 millis, if you hold it*/
  if (btnRight.pressed(1, 500)) {
    Serial.println("right!");
  }
  /* pin, repeat each 500 millis, after 5 seconds*/
  if (btnDoor.pressed(500, 5000)) {
    Serial.println("Door!");
  }
  if (btnWindow.pressed()) {
    Serial.println(btnRight.isDown() ? "Window, right is down" : "window, right is up");
  }


  if (btnLeft.onReleased()) {
    Serial.println("left released");
  }

  if (btnRight.onReleased()) {
    Serial.println("right released");
  }
  if (btnDoor.onReleased()) {
    Serial.println("door released");
  }
  if (btnWindow.onReleased()) {
    Serial.println("window released");
  }

}

Now, rather than using a mysterious “button 3”, youcan read the code and see that it says “if the window is down, then print a message that depends on whether or not the right button is down”.

Making use of the F macro (to move fixed text to progmem) in the serial print statements will save around 100 bytes of RAM.

Wow thanks! Amazing so organized!!

now i don't have to worry about this

const int buttonpins = {A0,A1,3,4};
const int number_of_buttons = 4;

  /* pin, repeat each 500 millis, if you hold it*/
  if (button[1].pressed(1,500)) {
    Serial.println(F("b2 down"));
  }

shoeld be

  /* pin, repeat each 500 millis, if you hold it*/
  if (button[1].pressed(500)) {
    Serial.println(F("b2 down"));
  }

sterretje:
Making use of the F macro (to move fixed text to progmem) in the serial print statements will save around 100 bytes of RAM.

Like this? Serial.println(F("Hello from arduino!"));

Yes.

geyhax:
shoeld be

Can't find the "blush" emoji. Yeah - I remember messing up something around that region while I was doing this. Oh well.

For a more complete rundown on C++ classes, google "C++ tutorial". Most C++ tutorial are adapted towards command-line programs running on full computers, and there's a couple of caveats for arduino programming (avoid the C 'String' class, collections, and dynamic memory allocation).

Classes is the way I go about doing arduino programming. Check the link in my sig below for more of the same.

PaulMurrayCbr:
Can't find the "blush" emoji. Yeah - I remember messing up something around that region while I was doing this. Oh well.

For a more complete rundown on C++ classes, google "C++ tutorial". Most C++ tutorial are adapted towards command-line programs running on full computers, and there's a couple of caveats for arduino programming (avoid the C 'String' class, collections, and dynamic memory allocation).

Classes is the way I go about doing arduino programming. Check the link in my sig below for more of the same.

Thank you sir!