Complete Noob - looking for guidance

Hi,

I am very new to Arduino code and would really appreciate some help. I have been working on a set of custom joysticks for gaming and I have the physical model printed out and working well. The next step is the code.

I am using a Micro Atmega32U4 with a total of 11 push buttons. I have looked into how other people make a button box, but they use a matrix wiring setup. I just have a common ground with the positive leads ready to solder into the board.

I am looking for any guidance you are willing to help me out with. I have spent a lot of time on this project and the coding is not something I am good at by any means.

Many thanks,
Adam

Confused :thinking:

You do, or, you do not want to use a matrix of switches ?

I do not have it setup for a matrix and the way the buttons are setup, I cannot make it into a matrix.

Wire the switches as S3 is wired, use INPUT_PULLUP with pinMode( ).

Hmm, so the pinout doesnt necessarily matter? Sorry complete noob

next item on your study list: pin debounce.

In your sketch you read the switches as needed, when needed, then reaction as you wish.

Best read the switches every 50ms, look for a change in state not a switch level.

Is there a spot I can grab a example/sample code and modify for my use? Basically change the number of buttons in the code and what pinouts are used.

There are generic sample sketches in the IDE samples.

These, however, cover basic concepts.

Start with making a Story Board describing what is supposed to happen.

Just because buttons are wired as a matrix doesn't mean they have to be placed in a grid.

You can also wire switches to parallel-to-serial input shift registers daisy-chained on the SPI bus pins. Adding switches means adding to the chain and changing the code.

Arduino Foundations Page --- Bookmark it!

How to add digital inputs with CD4021B chips.

GoForSmoke, I have no idea what you are referring to. I am used to simple wiring with no code work. This is a complete new type of project for me.

I am looking for information that will help me create a sketch, not necessarily overcomplicate it. Maybe that isn't the case, I don't know.

The pull-down menus on that bar near the top... one is named DOCUMENTATION, there's code in every lesson but go to the PLAYGROUND if you want to get in over your head. Lots of beginners do, then they misuse what they don't know and ask baffling questions.

At some point you're going to want to get at CAN buses in cars, right?
Take your time, do it right.

It is getting late, I am going to mess around with the advice given tomorrow. I am sure I will have many more questions.
Thanks

Do you have enough pins for 1 pin to 1 switch, I have example code with debounce built-in. This has the button task and example of using it. It's not dead simple but it is highly responsive and trims RAM use.

// New name -- addButtonArray 
// add-a-sketch_buttons 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, May 6/2018 by GFS. Compiled on Arduino IDE 1.6.9.
/*  Button Debounce Example

  --- for this example connect a button between pin 7 and GND
  --- or stick a jumper in pin 7 and while holding the board steady
  --- tap the free end onto the grounded USB port box to press.

  Yes I'm using a 16 bit micros timer to time fractions of millis as micros.
  The button reader only reads 1 button per call so as to not block void loop().
  Each button has a history byte that holds the last 8 reads with 256 possible
  states but only 4 of them being significant.
  0 is the button held down
  255 is the button left up
  127 is the buton transitioning from up to down, button just released.
  128 is the button transititioning from down to up, button just pressed.
  everything else is to be ignored as bounce.

  For multiple buttons on 1:1 pins the between-reads time is reduced and each
  pin is read in turn. This demo makes pin 0 be ON-RESET/OFF and pin 1 adjusts
  blink time.
*/

// multi_buttons vars
const byte buttons = 2;
byte buttonIndex, lastIndex; // only process 1 button every waitButtonTime micros
byte buttonPin[ buttons ] = { 6, 7 };
byte buttonHistory[ buttons ];
word markButtonTime;        // 16-bit micros timers
const word waitButtonTime = 250; // micros, 20 to 500 / more to fewer buttons.
// type word as micros can time across 65.535 millis before rollover, can be a few late

// added sketch task, on-off blinker vars
byte ledState, ledPin = 13; // use byte for small values, int cost 2 bytes
word startBlink, waitBlink; // 16 bit millis is good to time 65.535 seconds


void multiButtonsTask()
{ // read twice per milli, bits 0 to 6 all same sets the state
  if ( word( micros()) - markButtonTime >= waitButtonTime ) // read occaisoinally
  {
    buttonHistory[ buttonIndex ] <<= 1; // if you don't know <<= look it up in the Arduino Reference
    // keep a browser open to that page when you use the IDE.
    buttonHistory[ buttonIndex ] += digitalRead( buttonPin[ buttonIndex ] ); // read history streams through buttonHistory
    markButtonTime = micros(); // gets the low 16 bits of micros(), time to 60 ms + margin
  }

  // ++buttonIndex pre-increments buttonIndex before comparing to buttons
  if ( ++buttonIndex >= buttons )   buttonIndex = 0;
}

void OnOffBlinker() // only blinks if there's a wait time, can be switched on/off
{
  if ( waitBlink > 0 ) // this is the on/off switch
  {
    // word( millis()) gets the low 16 bits of the 32-bit millis() return.
    if ( word( millis()) - startBlink >= waitBlink ) // difference in time by subtracting start from end
    {
      ledState = !ledState;  // ! is NOT: not_0/true becomes 0/false else 0 becomes 1.
      digitalWrite( ledPin, ledState ); // the led changes state.
      startBlink += waitBlink; // next blink starts when it should, where diff > wait.
    }
  }
  else if ( ledState > 0 ) // waitBlink == 0 turns blinking off
  {
    digitalWrite( ledPin, ledState = LOW ); //  make sure the led is OFF
  } // yes, you can set a variable during calculation in C, the write here is LOW.
}


void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Button Debounce Example, free by GoForSmoke\n" ));
  Serial.println( F( "This code shows use of struct, union, bit fields and 16 bit timers." ));
  Serial.println( F( "It can work with many buttons, uses structs to hold button data." ));
  Serial.println( F( "Button data structs can be arrayed even for matrix arrangements." ));
  Serial.println( F( "\n-- for this example connect a button between pin 7 and GND" ));
  Serial.println( F( "--- or stick a jumper in pin 7 and while holding the board steady" ));
  Serial.println( F( "--- tap the free end onto the grounded USB port box to press." ));

  pinMode( ledPin, OUTPUT );

  for ( byte i = 0; i < buttons; i++ )
  {
    pinMode( buttonPin[ i ], INPUT_PULLUP );
    buttonHistory[ i ] = 255;
  }
};


void loop()
{
  multiButtonsTask();
  /*
    0 is the button held down
    255 is the button left up
    127 is the buton changing from up to down, button just released.
    128 is the button changing from down to up, button just pressed.
    everything else is to be ignored as bounce.
  */

  if ( buttonIndex != lastIndex )
  {
    lastIndex = buttonIndex;

    switch ( buttonHistory[ buttonIndex ] ) // buttonHistory does not change as fast as this runs
    {
      case 128 : // pin is HIGH in bit 7, LOW for 7 reads, up to down detected
        buttonHistory[ buttonIndex ] = 0; // change detected, make it into no change now
        Serial.print( F( "button " ));
        Serial.print( buttonIndex );
        Serial.print( F( "  press detected     " ));
        Serial.println( millis());

        if ( buttonIndex == 0 )  // button zero starts and stops blink
        {
          if ( waitBlink == 0 ) // toggle action tied to button press
          {
            waitBlink = 500; // makes the blinking start
            startBlink = millis(); // gets the low 16 bits
          }
          else 
          {
            waitBlink = 0; // makes the blinking stop
          }
        }
        else // press button 2 changes the blink rate
        {
          if (( waitBlink -= 100 ) < 100 ) // setting a var in an expression is okay C
          {
            waitBlink = 1000;
          }
        }
        break;

      case 127 : // pin is LOW in bit 7, HIGH for 7 reads, down to up detected
        buttonHistory[ buttonIndex ] = 255; // change detected, make it into no change now
        Serial.print( F( "button " ));
        Serial.print( buttonIndex );
        Serial.print( F( "  release detected   " ));
        Serial.println( millis());
        break;
    }
  }

  OnOffBlinker();
}

Not good enough. Explain what you mean and what is the restriction on your wiring?

Whatever prevents you from wiring them as a matrix almost certainly introduces many other restrictions.

I cannot do a matrix wiring setup because 2 of the buttons come from a PCB has a separate common ground. Because the grounds from these buttons are combined, I cannot include them into the other buttons to make a matrix. Since I cannot include those 2, I decided not to make a matrix at all.

Do you have them wired to Arduino pins already?

When you want your code to always see all button press and release, your code can't use delay() without become massive and problematic and always slower response than...

No-blocking, event-driven code that lets you sense and respond 10's of times per millisecond. Your button code reads the contacts bouncing like a dozen press-release events in 2 ms, button debounce routines find ways to determine a stable state or just assume one after 20 to 100 ms which is way too long to wait with multiple buttons, leave some acting dead half the time.
What I wrote takes 3.5 ms of the same pin state after the last bounce, could take less by reading more often than twice a ms.

You don't need to know the button code to use it but may need help expanding from 2 buttons to 11 and reading every 40 or 50 micros instead of 250 --- only 1 pin is read in any read, it shortens void loop() greatly.

YOUR CODE only needs to read buttonHistory[ button # ] for (had to edit an error)
0 is the button held down
255 is the button left up
127 is the button changing from up to down, button just released & stable 3.5 ms.
128 is the button changing from down to up, button just pressed & stable 3.5 ms.
everything else is bounce.

If you see bounce and feel safe, you may assume the next stable state will be the opposite of the last.

For most uses,

void loop()
{
multiButtonsTask();

// make one of these for each button, ask for help making short steps out of long code.
if ( buttonHistory[ 0 ] == 127 ) // buttonHistory does not change as fast as this runs
{
// code for what pressing that button does -- May be broken into steps as switch/case

if ( finished ) or in final case buttonHistory[ 0 ] = 255; // quit triggering
}

Arduino can do light work in about 20 microseconds (320 cycles), if your sketch should read a pin every 50 us then make sure that void loop runs at least that often.

I predict that you will try what looks easiest first.

GoForSmoke,

Thank you for writing that out, I understand that a bit more. I do not have the wires soldered to the Arduino board yet, I wanted to make sure everything was good to go beforehand.

So if I understand correctly, I will have a slight delay in button function when pressing the buttons. Is that correct? Also pressing more than one button at a time will increase this time delay?

When you say button #, do you mean the pinout location from the board?

**

void loop()
{
multiButtonsTask();

// make one of these for each button, ask for help making short steps out of long code.
if ( buttonHistory[ 0 ] == 127 ) // buttonHistory does not change as fast as this runs
{
// code for what pressing that button does -- May be broken into steps as switch/case

if ( finished ) or in final case buttonHistory[ 0 ] = 255; // quit triggering
}

**

I will have 11 of the same code above just different pinout locations for the 11 different buttons, is that correct?

How does the computer know what to do with that button in the game? Doesn't the code need some kind of digital readout?

Yes, what kind depends on the game to a degree. Since you're using a Micro Atmega32U4, it can act as a keyboard and send keystrokes to the game.

I'd assume that needs to be a line of code?