array of Bounce objects ?

Hey Guys,
I'm having the same Problem.
I m working on a Project with at least 20-30 Buttons, and i would love to use the Bounce library, but not with single varibles.

im ok with pointers, but i could not get my Bounce-POINTer-Array-Construct to work...

Can someone post a small code excerpt, or did you, Z.K. find a solution???

thanks a lot!

ok with pointers, but i could not get my Bounce-POINTer-Array-Construct to work...

You need to post your code, otherwise we'd be doing your programming, and that would be no fun for you.

try this:

Bounce bouncer[5] = {
  Bounce( BUTTON1,5 ),
  Bounce( BUTTON2,5 ),
  Bounce( BUTTON3,5 ),
  Bounce( BUTTON4,5 ),
  Bounce( BUTTON5,5 )
};

Weird. I tried this declaration WizenedEE earlier my self, but it did not work.

Now i copied yours and it worked!!!
maybe some stupid syntax error :slight_smile:

You need to post your code, otherwise we'd be doing your programming, and that would be no fun for you.

@ AWOL you are completely right, but it was really rubish in the end, now it works anyway!

Thanks guys

Hi,

I recently came across this post, and have a related question:

Would it be possible to use some sort of for loop to create an array of bounce objects? I'm trying to do something like this:

int BUTTON[] = {2,3,4,5,6};  //button pins
const int numButtons = 5;  


Bounce bouncer[5]; 

for( int i = 0; i < numButtons; i++){
   Bounce bouncer[i] = (BUTTON[i], 5);
}

But keep getting a:

"no matching function for call to 'Bounce::Bounce()'"

error...it seems to be choking on the object array declaration? Any advice on this would be great...

Thanks!

ccerrito:
Would it be possible to use some sort of for loop to create an array of bounce objects? I'm trying to do something like this:

Not like that. You could use dynamic memory management (which you don't really want to do), but other than that you have to do it like I showed.

That's one of the main reasons why it's a good idea to give every class a no-argument constructor --- you can just make an array and then assign the needed values later.

What's happening here is that the C++ standard guarantees every object will have a constructor called. So if you make an array of objects, it must call a constructor for each one of them right then and there (if it was allowed to wait you might do something with them before their constructors were called). Thus, you have to give every value it needs right then and there.

ccerrito:

   Bounce bouncer[i] = (BUTTON[i], 5);

That doesn't make sense. You're declaring a local array of Bounce of length i, named bouncer. And you're initialising it to the number 5.

Given that you declared a global array of Bounce, those objects now already exist. It's too late to try to construct them. If you declared the global array bouncer to be an array of pointers to Bounce then you could loop through the array and create a new Bounce and store the addresses in the array. It'd mean accessing them through pointers, but I don't suppose that will bother you.

I think the OP here was trying to create one point of set-up to make the program expandable
(to add buttons)
I'm not sure I understand the limitation against it quite yet but here is a working example without
for those still stumbling upon this topic like I did today.

#include <Bounce.h>

// This code turns a led on/off through debounced buttons
// Buttons wired one side to pin the other 330oms to ground

//#define B0 4// i have a feeling there is 
//#define B1 5// an injection issue with these first two
#define B2 6
#define B3 7
byte buttons[]={6,7,4,5};//seperate array from definitions to set up the pins
#define NUMBUTTONS sizeof(buttons)//gives size of array *helps for adding buttons

#define LED 13
int ledValue = LOW;

// I really dont see getting around doing this manually
Bounce bouncer[] = {//would guess thats what the fuss is about
  Bounce(4,5),
  Bounce(5,5),
  Bounce(B2,5),
  Bounce(B3,5)
};

void setup() {
   for (byte set=0;set<NUMBUTTONS;set++){//sets the button pins
     pinMode(buttons[set],INPUT);
     digitalWrite(buttons[set],HIGH);//<-comment out this line if not using internal pull ups
   }//-----------------------------------and change read()==to high if your set up requires
  pinMode(LED,OUTPUT);//------------------otherwise event will occure on release
}

void loop() {
 // test turning on a led with any of the debounced buttons
 for(int num=0;num<NUMBUTTONS;num++){
   if ( bouncer[num].update()) {
     if ( bouncer[num].read() == LOW) {
       if ( ledValue == LOW ) {
         ledValue = HIGH;
       } else {
         ledValue = LOW;
       }
       digitalWrite(LED,ledValue);
     }
   }
   
 }
}

jackokring:
I think you need an array of size five of POINTER to bounce. Ten fill it by addressing each new bounce via & and assigning it to an array element. Then dereference via * before using an element of the array. Object arrays are filled with default bounce objects, and there is no default no argument constructor.

This seems like the best solution to what the OP wanted to do, and sorry this is an old thread but It's kind of bugging me that this is the first post that comes up in google, and there isn't a demonstration of this suggestion.

It's been a long time since I've done C++ programming, so someone please tell me if I'm mistaken but this would do it, right?

int numButtons = 5;
int debounce = 5;
    
// create array of pointers of Bounce size
Bounce *buttPtrs[numButtons];

int pins[] = {2, 3, 4, 5, 6};

void setup() {

    Serial.begin(38400);

    for (int i = 0; i < numButtons; i++) {
        int pin = pins[i];
        // any other setup, like setting pinmode
        pinMode(pin, INPUT_PULLUP);

        // create a Bounce object
        Bounce bb = Bounce(pin, debounce);
        // assign its address to the pointer in the array
        butrPtrs[i] = &bb;
    }
}

void loop() {
    for (int i = 0; i < numButtons; i++) {
        // Get the object at the address held by the pointer
        Bounce butt = *buttPtrs[i];

        butt.update();
        if (butt.fallingEdge()) {
            Serial.print("Button ");
            Serial.print(i);
            Serial.println(" has been pressed!");
        }
        if (butt.risingEdge()) {
            Serial.print("Button ");
            Serial.print(i);
            Serial.println(" has been released!");                
        }
    } 
}

No, that will not work. Bounce bb is created with local scope, so it is destroyed and reconstructed on every iteration. It is then destroyed for good when the loop is over. All you have accomplished was to fill the array with dangling pointers.

Jiggy-Ninja:
No, that will not work. Bounce bb is created with local scope, so it is destroyed and reconstructed on every iteration. It is then destroyed for good when the loop is over. All you have accomplished was to fill the array with dangling pointers.

No, that is wrong. bb, the pointer to the new object, is destroyed, but the object itself is not. c++ does NOT do garbage collection, so the object remains allocated unless and until the code explicitly deletes the object. That snippet will work just fine (well, assuming the obvious typo is fixed...). And bb is created on each iteration of the loop, and destroyed at the end of each iteration of the loop. There is no "destroyed for good when the loop is over".

Regards,
Ray L.

Someone needs to learn the difference between stack and heap allocation.

Jiggy-Ninja:
Someone needs to learn the difference between stack and heap allocation.

Yes, I mis-read that but a very simple change fixes it, and is much more helpful than just telling him "that won't work":

Bounce *bb = new Bounce(pin, debounce);

Regards,
Ray L.

There's a reason I didn't fix it. Using heap allocation is generally discouraged on microcontrollers with severely limited memory. It won't cause a problem here since the objects are not being created and destroyed as needed, but since that's the case you don't need to use heap allocation. Initialize them properly as global variables and then they'll be counted as used memory when you compile the sketch.

The other answers before yours are better.

Jiggy-Ninja:
There's a reason I didn't fix it. Using heap allocation is generally discouraged on microcontrollers with severely limited memory.

Only on this forum. I've been doing embedded development since the '70s and using dynamic allocation nearly all of that time, with never a problem... Used properly, it is perfectly safe and reliable, despite the "everybody knows it's inherently evil" constantly, and wrongly, repeated here...

Regards,
Ray L.

RayLivingston:
Used properly, it is perfectly safe and reliable, despite the "everybody knows it's inherently evil" constantly, and wrongly, repeated here...

I absolutely agree.

Heap allocation adds 2 bytes that hold the length of the allocation (IIRC), so there is a small penalty.

Whandall:
I absolutely agree.

Heap allocation adds 2 bytes that hold the length of the allocation (IIRC), so there is a small penalty.

And.... dynamic allocation is often the key to making the MOST EFFICIENT use of limited memory, as in many applications it will REDUCE peak memory usage. Static allocation ties up memory whether the objects are currently needed or not, which is a poor use of a limited resource. Dynamic allocation allows the objects to be created when needed, and tossed once no longer needed, freeing that memory to be used for other things. This will often greatly increase the functionality that can be implemented in limited memory. Anyone who says dynamic allocation should never be used has probably never learned to use it properly.

Regards,
Ray L.

RayLivingston:
Only on this forum. I've been doing embedded development since the '70s and using dynamic allocation nearly all of that time, with never a problem... Used properly, it is perfectly safe and reliable, despite the "everybody knows it's inherently evil" constantly, and wrongly, repeated here...

Regards,
Ray L.

"Used properly" is the qualifier there. Most people here do not have 4 and a half decades of career experience with this. Probably a majority don't even have that much experience at life (I don't).

This might just be a years-long holdout from when the AVR-GCC implementation of new was buggy. There's also been a few instances I've seen here of people using the capital-S String class in an unstable program, and all the instability went away when they change to locally declared string buffers. The constant allocation and deletion of temporary String objects was wrecking their memory.

And.... dynamic allocation is often the key to making the MOST EFFICIENT use of limited memory, as in many applications it will REDUCE peak memory usage. Static allocation ties up memory whether the objects are currently needed or not, which is a poor use of a limited resource. Dynamic allocation allows the objects to be created when needed, and tossed once no longer needed, freeing that memory to be used for other things. This will often greatly increase the functionality that can be implemented in limited memory. Anyone who says dynamic allocation should never be used has probably never learned to use it properly.

Regards,
Ray L.

I will defer to your experience here.

Jiggy-Ninja:
"Used properly" is the qualifier there. Most people here do not have 4 and a half decades of career experience with this. Probably a majority don't even have that much experience at life (I don't).

This might just be a years-long holdout from when the AVR-GCC implementation of new was buggy. There's also been a few instances I've seen here of people using the capital-S String class in an unstable program, and all the instability went away when they change to locally declared string buffers. The constant allocation and deletion of temporary String objects was wrecking their memory.I will defer to your experience here.

"Used properly" is very simple: ALWAYS check the return value from the malloc or new, to ensure it was successful. ALWAYS use free or delete when the memory is no longer required. Be aware of how much memory you have, and use it appropriately. My first exposure to malloc was in about 1981. All it took was a little reading to understand how it works, and how to use it. It does NOT require "4 and a half decades of career experience" - a few hours is more than adequate.

The (long since fixed) problems with the Arduino String implementation are just that - problems with the Arduino String implementation. They have nothing whatsoever to do with whether or not dynamic allocation is "safe" any more than a single model of car with a design flaw in its engine means all cars should be avoided as they will all have design flaws in their engines.

Regards,
Ray L.