Learning Arrays

After finally getting the code to work with one switch I am now trying to understand how to get the code to handle multiple switches.

For those who have not followed along with me I am using an on off toggle switch as a joystick button. Basically using the following code:

#include <Joystick.h>

Joystick_ Joystick;

void setup() {
  // Initialize Button Pins - Mine starts with pin D3 because the D2 pin was burned out.
  pinMode(3, INPUT_PULLUP);

  // Initialize Joystick Library
  Joystick.begin();
}

// Constant that maps the phyical pin to the joystick button. Again, I use pin 3.
const int pinToButtonMap = 3;

// Last state of the button
int buttonState = HIGH ;
int lastButtonState = LOW ;

void loop() {
  // read the pushbutton input pin: Again, I use pin 3.

  buttonState = digitalRead(3);


  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:

// "press" the joystick button for 10 milliseconds

       Joystick.setButton(0, HIGH);
       delay(50);
       Joystick.setButton(0, LOW);


    } else {

// "press" the joystick button for 10 milliseconds

       Joystick.setButton(0, HIGH);
       delay(50);
       Joystick.setButton(0, LOW);

    }

    delay(50);
  }
    // NOTE: save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;
}

This works great for one switch. It sends a quick pulse as if pressing a button (button 1 on the joystick) and letting go each time the switch is toggled. For those who have followed you can see that I am now actually following a button lol.

But now I need to learn how to get a second, and third switch to act the same. I was told that to do this I would need to use a “For” statement and an array. So I’ve been reading about those.

But I’m not sure I understand how the For command works. I get that in the () it says int x = 0 meaning whatever x is it is equal to 0. So if buttonState = 3 would that mean I can put buttonState = 0? And how does the next part (x <= 2; 2++) work? How would it be expressed in the above code?

Sorry, but I’m one of those people that has to see something already working to reverse engineer it to learn HOW it works. It’s hard for me to build something without having a working model to go by. I have checked out the tutorials but I need it explained in a different way than 99% of them do (have you noticed how so many websites copy and paste the same tutorials word for word).

The for statement reference.

Getting one thing to work, then suddenly wanting a bunch of things to work the same? This is what writing a class if good for.

class myThing {

 public:

           myThing(int pinNum);
virtual  ~ myThing(void);

        void somethingItShouldDo(int stuff);
        void somethingElseItShouldDo(char* moreStuff);

        int   someVariable;
        bool anotherVariable;
};

Once you get one thing working, just clone out a bunch of them with their own pin numbers.

-jim lee

consider (add as many button/leds to the arrays as you need)

// recognize multiple button presses; tgl LED when pressed

byte butPins [] = { A1, A2, A3 };
byte ledPins [] = { 10, 11, 12 };

#define N_PINS sizeof(butPins)

byte butLst [N_PINS] = {};


// -----------------------------------------------------------------------------
void setup (void)
{
    for (unsigned n = 0; n < N_PINS; n++)  {
        digitalWrite (ledPins [n], OFF);
        pinMode      (ledPins [n], OUTPUT);

        pinMode      (butPins [n], INPUT_PULLUP);
        butLst [n]  = digitalRead (butPins [n]);
    }
}

// -----------------------------------------------------------------------------
void loop (void)
{
    for (unsigned n = 0; n < N_PINS; n++)  {
        byte but = digitalRead (butPins [n]);

        if (butLst [n] != but)  {
            butLst [n] = but;

            if (LOW == but)     // button pressed
                digitalWrite (ledPins [n], ! digitalRead (ledPins [n]));
        }
    }

    delay (10);         // debounce
}

Since there’s a one-to-one correspondence between Buttons and LEDs, you should bind them together in a struct. Then, then create an array of sturct for as many combinations as you have:

struct LedAndButton {
  uint8_t button;
  uint8_t led;
};

LedAndButton buttonSet[] = {{A1, 10}, {A2, 11}, {A3, 12}};
constexpr uint8_t numButtons = sizeof(buttonSet) / sizeof(buttonSet[0]);
uint8_t lastState[numButtons];


void setup() {
  for (uint8_t i = 0; i < numButtons; i++) {
    pinMode(buttonSet[i].button, INPUT_PULLUP);
    lastState[i] = digitalRead(buttonSet[i].button);
    pinMode(buttonSet[i].led, OUTPUT);
    digitalWrite(buttonSet[i].led, LOW);
  }
}

void loop() {
}

gfvalvo:
Since there's a one-to-one correspondence between Buttons and LEDs, you should bind them together in a struct…

Yes. That struct could also, one day, be the place you put other things that need to be kept for each button/LED or as in the OP's case the button, the Arduino pin that is, and the joystick equivalent.

Like a timer for debouncing unique to each push button. Or an indication, however, that a particular button should be momentary or (again the OP's original inquiry) push-on push-off to act more like a toggle switch. Whether the button is normally pullt down or up.

If it ever got to a touch screen, for example, you might store the coordinates of the screen area where the button is to be displayed and the colors to use for pressed and not pressed. And the text label.

And so forth. You get the idea I hope.

Arrays of structs, yes that'll get things interesting.

a7

I have not had time to dive into all of these replies, but I will.

For now let me ask if I would be correct in saying that if I did

// Last state of the button
int buttonState3 = HIGH ;
int lastButtonState3 = LOW ;

Last state of the button
int buttonState4 = HIGH ;
int lastButtonState4 = LOW ;

void loop() {
// read the pushbutton input pin: Again, I use pin 3.

buttonState3 = digitalRead(3);

buttonState4 = digitalRead(4);

I could then just repeat the items in the loop with the different button state numbers?

Like this:

compare the buttonState to its previous state
  if (buttonState3 != lastButtonState3) {
    // if the state has changed, increment the counter
    if (buttonState3 == HIGH) {
      // if the current state is HIGH then the button went from off to on:

// "press" the joystick button for 10 milliseconds

       Joystick.setButton(0, HIGH);
       delay(50);
       Joystick.setButton(0, LOW);


    } else {

// "press" the joystick button for 10 milliseconds

       Joystick.setButton(0, HIGH);
       delay(50);
       Joystick.setButton(0, LOW);

    }

    delay(50);
  }
    // NOTE: save the current state as the last state, for next time through the loop
  lastButtonState3 = buttonState3;
}
if (buttonState4 != lastButtonState4) {
    // if the state has changed, increment the counter
    if (buttonState4 == HIGH) {
      // if the current state is HIGH then the button went from off to on:

// "press" the joystick button for 10 milliseconds

       Joystick.setButton(1, HIGH);
       delay(50);
       Joystick.setButton(1, LOW);


    } else {

// "press" the joystick button for 10 milliseconds

       Joystick.setButton(1, HIGH);
       delay(50);
       Joystick.setButton(1, LOW);

    }

    delay(50);
  }
    // NOTE: save the current state as the last state, for next time through the loop
  lastButtonState4 = buttonState4;
}

duplicating code is a bad practice: it make the code bigger and any change in the algorithm requires changes in each copy of the code.

you say your "Learning Arrays" so try to use arrays

gcjr:
duplicating code is a bad practice: it make the code bigger and any change in the algorithm requires changes in each copy of the code.

you say your "Learning Arrays" so try to use arrays

I am taking it step by step. If I can understand the code in it's drawn out form and know that it works then I can learn to shorten the code with an array, if that makes sense. I have a strange way of learning.

Basically if the above code can work then I'll understand how the array works to shorten it.

gcjr:
duplicating code is a bad practice: it make the code bigger and any change in the algorithm requires changes in each copy of the code.

Plus, when duplicating code as a human you’re prone to making a “copy and paste error”. e.g. writing code block for “B”, but accidentally still using the variable for code block “A”. These kind of bugs can be hard to spot and require testing each and every code path.

Whereas, if you use the same code, instead of unrolling, if you test the code and it works for “A” you can be fairly certain it will work for “B” also...

personally if someone is struggling with the concept of a for() statement to iterate an array, and the actual point of this that going into structures and class design is a cruel and unusual punishment - may not be a bad end goal but step by step…

sometimes a level of bad practice is useful for teaching how something works, then move on to how to do it better once the principle is understood.

something thus may help, a bit abstract but there you go

uint8_t ButtonPins[3] = {3,4,5}; // an array, with three elements to hold the pins the buttons connect to, defined and populated so the first element is 3, second is 4 and so on

uint8_t ButtonValues[3] = {LOW}; // array to hold the button current states, initialise as being LOW, assuming your buttns are normally LOW unless pressed

...

// walk the three buttons, reading each in turn

for (uint8_t cntr = 0; cntr < 3; cntr++)
{
  // within this loop the variable 'cntr' will be given the values 0, 1 and 2 and the code will run three times

  // read each pin, in turn, here 3,4 & 5 and store them in the array to hold values
  ButtonValue[cntr] = digitalRead(ButtonPins[cntr]);
}

// you now have the value of the first button in ButtonValue[0], the second in ButtonValue[1] and so on

you can do the same with the times, an array of unsigned longs to store the times.

basically where you used a variable, you use an array to store several and can then walk though them easily

if you use a #define to specify the array size its easy to walk the array thus

#define ARRAY_SIZE 10

...

for (uint8_t X = 0; X < ARRAY_SIZE; X++)
{
...
}

one I find useful is to have a global for “TNow” and read the time from millis() or micros() at the top of your loop then use that throughout

dale_needham:
personally if someone is struggling with the concept of a for() statement to iterate an array, and the actual point of this that going into structures and class design is a cruel and unusual punishment - may not be a bad end goal but step by step…

sometimes a level of bad practice is useful for teaching how something works, then move on to how to do it better once the principle is understood.

Agree. Been there.

What the OP proposes would certainly work. For just two buttons it may be satisfactory. By the time it is any more, the for loop iteration and the struct (or simpler: start with parallel arrays) will be superior for the reasons pointed out.

Maybe writing out the second code block helped you see a pattern, that will become second nature. You just have to get the syntax of arrays. Many noobs want to construct variable names on the fly, and that is possible in some languages but not C/C++.

So your buttonState3 and buttonState4, currently separate scalar values become something like buttonState[ii] with the variable "ii" serving as the index, set to 3 to talk the first and 4 to talk about the second. A for loop is a nice way of getting a variable to step through a series of values to use as the index.

@dale_needham put the pin numbers in one array ButtonPins and made a place for the value of the digital read in ButtonValue.

I never can decide whether the array name should be plural or not, and I'm not even consistent within one sketch. Here I would say ButtonPin and ButtonValue are good names for those arrays.

And looking ahead (obsessed with debouncing switches!) to a time when you might need it, a third array of unsigned long ints could store a timer that could be used. Each button has information at the same index in both (or all) the arrays.

struct just sorta rolls up the parallel arrangement as a convenience, nothing to be scared of when you get to it.

a7

granted, point though is without actually understanding what you are doing, likely learnt through small and simple steps so you do actually understand it you may as well copy & paste stuff from stack overflow..

agree on the 'should an array be singular or plural', I personally go with whatever sounds easier when you say it out loud, but some sort of standard is certainly better practice.

get used to the arrays then when thats understood consider moving to a structure to hold them and an array of the structures - but understand pointers first, then perhaps consider a class.

but sometimes, especially when talking about small scale hardware its not 'n' inputs, its 3, or 4, or whatever small number that you know because you have the thing in front of you and sometimes actually just the basic arrays work fine.

trick is to use something that works and that you understand and can maintain.

and not to copy me for variable names

and possibly to consider debouncing in hardware, but that doesn't answer the question actually asked