need help with array

I’m on a project that needs to accept an input sequence via buttons and store it in an array
and when i try to display the array in the serial monitor i always don’t get the desired result
here are the errors that i get:
i just pressed one button and the program just ended
when i press button1 i get 1 0 3 as result
for button 2 i get 2 0 3
and for button3 i get 3 0 3

what i need is that

  • wait for an input (pressing the button) from the user before continuing
  • then store the sequence into an array

im using arduino mega2560
Here’s is my code:

#include <Button.h>
Button button1(2);
Button button2(3);
Button button3(4);
boolean test = false;
int val[2];
int i = 0;
int j = 0;
void setup() {
  button1.begin();
  button2.begin();
  button3.begin();
  Serial.begin(9600);
}

void loop() {

  for (i; i < 3; i++) {
    while (test == false) {
      if ((button1.read() == Button::PRESSED) || (button2.read() == Button::PRESSED) || (button3.read() == Button::PRESSED)) {
        test = true;
      }
    }
    if (button1.pressed()) {
      val[i] = 1;
    }
    else if (button2.pressed()) {
      val[i] = 2;
    }
    else if (button3.pressed()) {
      val[i] = 3;
    }
    test = false;
  }

  for (j; j < 3; j++) {
    Serial.print(val[j]);
    Serial.print(" ");
  }


}

button.ino (745 Bytes)

Please read the post by Nick Gammon at the top of this Forum on how to post source code using code tags. Also, before you post your code, use Ctrl-T in the IDE to format your code in a standard style. It will help us help you. Also, you can still use code tags on your first post using the Edit feature here.

for (i;i<3;i++){

This does not initialize i to zero. The first term basically does nothing to i. It will count up to 3 once and then it stays at 3 for the next iteration of loop(). The j loop is the same.

MorganS:

for (i;i<3;i++){

This does not initialize i to zero. The first term basically does nothing to i. It will count up to 3 once and then it stays at 3 for the next iteration of loop(). The j loop is the same.

so i need something like this?

for (int i = 0; i<3; i++){}

i tried this one but with no luck

int val[2];

1) You don't need a int for those small numbers, but whatever 2) Don't you have 3 buttons? Why do you only have 2 elements in your array?

In reference to your above question, yes

@ps991 thanks

still i have a problem it seems that the for loop is not working because whenever i press a single button the program will just execute and end

and it gives me an output of 1 0 0 for button1 and 2 0 0 , 3 0 0 for button2 and button3

After you press a button, it records which button was pressed. However, it then goes on to check again if a button is pressed. Your finger is pressing the button, so your code just assumes you pressed another button. It records it, then checks again, your finger is still on the button, so it records it. Your program now thinks you pressed 3 buttons in a few millionths of a second.

Challenge Question: How do you prevent your code from thinking one button press is more than one?

Your code ends because you have this
for (i; i < 3; i++) when it needs to be for (int i = 0; i < 3; i++)
same goes for the “j” for loop.

  for (j; j < 3; j++) {
    Serial.print(val[j]);
    Serial.print(" ");
  }

This part should not run until AFTER 3 buttons have been pressed.

I looked for that button library. I found one version which claims to be the latest version for Arduino. It was last updated in 2011. You may have a later version.

The button library makes a few beginner mistakes in the code. It also doesn't seem to have any built-in debouncing. You would have to add your own debounce code, which is about as complex as just doing digitalRead() yourself.

Throw away the library. It is holding you back. Learn to use digitalRead(). Learn about debouncing, which is a necessary component for reading mechanical switches.

Now, returning to your actual project, remember that the Arduino is almost infinitely fast. It will be able to take several readings of the input in a millionth of a second. It will be able to detect the button bouncing for many milliseconds. So it needs to ignore those bounces and wait until the button is "really pressed". Then it can do an action.

But that action also takes a millionth of a second. Your finger is still on the button. In fact you are still moving the button down by the time it detects a successful press. So it has to wait until the button comes up. It will run thousands and thousands of times waiting for you. Computers are good at waiting.

So after all of that, you have successfully recognized two changes in "state". The button went down and the button went up. Now it is up to you to take an action when you find those events.

You don't need curly brackets after an if or else if, if there's only one line following it.

Not familiar with the button lib you're using, sounds like something even I could write up without a library.

INTP: You don't need curly brackets after an if or else if, if there's only one line following it.

So ?? I find it actually quite good practice. Reduces the risk of adding a line later and not understanding why it is always executed.

sterretje: So ?? I find it actually quite good practice. Reduces the risk of adding a line later and not understanding why it is always executed.

Absolutely agree...always use the statement block braces. On the Arduinos, since Serial.print() is the most used debugging tool, you probably will eventually need to "brace-out" the if anyway. As sterretje points out, not always using them is a BYITBL waiting to happen (i.e., Bite You In The Butt Later).

/* buttonarrayclass example -- by GoForSmoke 2015 for public domain use

  This uses 2 buttons or switches or jumpers for pins 2 & 3 to GND.
  Depending on switch, debounce value may need tuning. I used 5ms here.

  Button class object output is a state value for the main sketch code.
  -1, Undecided, pin state changed at least debounce-time ago.
  0, button currently still not pressed.
  1, button currently still pressed.
  2, button released since last checked by sketch.
  3, button pressed since last checked by sketch.

  The main sketch may need to track previous output state for real dirty
  switches. A clean switch can work with 3 ms debounce. I use 20 here.
*/

#include "Arduino.h"
#include "buttonlib.h" // check for newest

const byte howManyButtons = 2;
byte buttonIdx;
buttonclass user[ howManyButtons ];

const byte ledpin = 13;

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n  Startup\n" ));

  pinMode( ledpin, OUTPUT ); // default is INPUT LOW, now is OUTPUT LOW
  
  for ( buttonIdx = 0; buttonIdx < howManyButtons; buttonIdx++ )
  {
    user[ buttonIdx ].setButton( 2 + buttonIdx, 5 );
  }
  buttonIdx = 0;
}

void loop()
{
  static byte buttonRead; // allocated once, used often

  user[ buttonIdx ].runButton(); // turns the crank once, make sure it runs often!

  buttonRead = user[ buttonIdx ].readOutput();

  if ( buttonRead == 3 ) // 1st read since pressed
  {
    digitalWrite( ledpin, HIGH );
    Serial.print( F( "button " ));
    Serial.print( buttonIdx );
    Serial.print( F( " pressed millis() == " ));
    Serial.println( millis());
  }
  else if ( buttonRead == 2 )
  {
    digitalWrite( ledpin, LOW );
    Serial.print( F( "button " ));
    Serial.print( buttonIdx );
    Serial.print( F( " released millis() == " ));
    Serial.println( millis());
    Serial.println( );
  }
  
  buttonIdx ^= 1;
}
/*
  buttonlib.h for public domain use by GoForSmoke May 29 2015
  
  to use:
  make a buttonclass object in your sketch
  run that object every time through loop(), it is quickly done
  when you want to know the status of the button, you read the object
  it returns state; UNDECIDED = -1, OFF = 0, ON = 1, justOFF = 2, justON = 3
  when the sketch reads the object, that may change the state of the object
  for instance state 3, justON, is reduced to state 1, ON, when read
  
  Really Dirty switches can false this code, resulting in 2 justOFF or 
  justON reads in a row. Dirty switches require that the main sketch code
  tracks previous state and only acts on change.
*/

#ifndef buttonlib_h
#define buttonlib_h

#include "Arduino.h"

class buttonclass
{
private:
  byte arduPin;
  byte stateHistory; // bit 0 = now, bit 1 = prev
  byte startMillis;
  byte debounceMillis; 
  char buttonOut; // 5-state as below
  char retButton;

public:
  buttonclass( void ); // default
  buttonclass( char, byte ); // pin, pinMode, debounce millis
  void setButton( char, byte ); // pin, pinMode, debounce millis
  void runButton( void );
  char readOutput( void ); // 5-state as below
// 5-state UNDECIDED = -1, OFF = 0, ON = 1, justOFF = 2, justON = 3
// UNDECIDED means not done debouncing, state unstable
};

#endif
/*
  buttonlib.cpp for public domain use by GoForSmoke May 29 2015
*/

#include "Arduino.h"
#include "buttonlib.h"

buttonclass::buttonclass( void ) { }; // default for arrays

void buttonclass::setButton( char ap, byte dbm )// pin, pinMode, debounce millis
{
  arduPin = ap;
  debounceMillis = dbm;
  stateHistory = 1; // pin is INOUT_PULLUP
  buttonOut = 0; // OFF
  pinMode( arduPin, INPUT_PULLUP );
}

buttonclass::buttonclass( char ap, byte dbm )
{
  //  setButton( ap, dbm );
  arduPin = ap;
  debounceMillis = dbm;
  stateHistory = 1; // pin is INOUT_PULLUP
  buttonOut = 0; // OFF
  pinMode( arduPin, INPUT_PULLUP );
}

void buttonclass::runButton( void )
{
  stateHistory &= 1;  // clears all but the last read
  stateHistory <<= 1; // shifts last read to bit 1
  stateHistory += digitalRead( arduPin ); // current state to bit 0

  switch ( stateHistory ) // set for INPUT_PULLUP
  {
    case 0 : // low - low     pressed
      if ( buttonOut < 0 )
      {
        if (( millis() & 0xFF ) - startMillis >= debounceMillis )
        {
          if ( retButton != 3 && retButton != 1 )
          {
            buttonOut = 3; // button pressed - just changed to ON
          }
        }
      }
      break;

    case 1 : // high - low   if state change, debounce!
    case 2 : // low - high
      buttonOut = -1;
      startMillis = millis() & 0xFF;
      break;

    case 3 : // high - high   released
      if ( buttonOut < 0 )
      {
        if (( millis() & 0xFF ) - startMillis >= debounceMillis )
        {
          if ( retButton != 2 && retButton != 0 )
          {
            buttonOut = 2; // button released - just changed to OFF
          }
        }
      }
      break;
  }
}

char buttonclass::readOutput( void )
{
  if ( buttonOut < 0 )  return buttonOut;
  retButton = buttonOut;
  if ( buttonOut > 1 )  buttonOut -= 2; // see change only once
  return retButton;
}

econjack:
Absolutely agree…always use the statement block braces. On the Arduinos, since Serial.print() is the most used debugging tool, you probably will eventually need to “brace-out” the if anyway. As sterretje points out, not always using them is a BYITBL waiting to happen (i.e., Bite You In The Butt Later).

I use them and put the braces on the same level so it’s easier to see and follow through indents without matching the open on the end of one line with the close brace. When the open and close are on the same level it’s a lot easier to visually find and know the indent level of that code. It’s just one possible bug that’s less hard to miss.

Note: with the Arduino IDE, use AutoFormat early and often while you code. It will catch mismatched braces and many other errors, make the code neat and show you what it thinks you wrote.

If the sole purpose is aesthetic appeal in the IDE to throw in excess curly brackets, I still think simply hitting return before and after to visually isolate a 2-line tidbit is easier to look at. But I always put closing curly brackets on their own line so maybe different benefits for other habits.

INTP: If the sole purpose is aesthetic appeal in the IDE to throw in excess curly brackets, I still think simply hitting return before and after to visually isolate a 2-line tidbit is easier to look at. But I always put closing curly brackets on their own line so maybe different benefits for other habits.

Sole purpose aesthetic? In case you missed my post:

Easier For The Eyes Makes Debugging Easier Too.

MorganS: I looked for that button library. I found one version which claims to be the latest version for Arduino. It was last updated in 2011. You may have a later version.

The button library makes a few beginner mistakes in the code. It also doesn't seem to have any built-in debouncing. You would have to add your own debounce code, which is about as complex as just doing digitalRead() yourself.

Throw away the library. It is holding you back. Learn to use digitalRead(). Learn about debouncing, which is a necessary component for reading mechanical switches.

Now, returning to your actual project, remember that the Arduino is almost infinitely fast. It will be able to take several readings of the input in a millionth of a second. It will be able to detect the button bouncing for many milliseconds. So it needs to ignore those bounces and wait until the button is "really pressed". Then it can do an action.

But that action also takes a millionth of a second. Your finger is still on the button. In fact you are still moving the button down by the time it detects a successful press. So it has to wait until the button comes up. It will run thousands and thousands of times waiting for you. Computers are good at waiting.

So after all of that, you have successfully recognized two changes in "state". The button went down and the button went up. Now it is up to you to take an action when you find those events.

Thank you Thank You!!!!!!!!!

i used delay before the for loop ends and it works

i searched for other method but i will use this for a while though i know it has some issues with reliability because it relies to the delay. and what if the user pressed too long or hold the buttons

but anyway thanks for your insights

BTW i observed that people who practice the use of curly braces are quite old maybe in the not so distant past where programming is a real discipline and where error detection is awful. and i look up to them because for me they are the real programming lords : )

MorganS: Now, returning to your actual project, remember that the Arduino is almost infinitely fast. It will be able to take several readings of the input in a millionth of a second.

Not using the digitalRead() command, or at least I haven't. It takes about 5 cycles, port read takes 1.

But once you read the bit you gotta do something with it or it's a wasted read. The fastest pin-check loop with counter I've been able to do using digitalRead() runs in just over 1 microsecond.