Array of Objects

I am trying to make my beginner project - neater. Currently, I have 4 buttons connected to my breadboard, and I am doing things in a bad way. No millis() etc, and a lot of cut and paste in my loop. My first refactor, is to move the 'logic' code into a function, that I call, passing in parameters for each button.

My loops, currently, looks like this:

void loop() {

  int pinAutopilotValue = digitalRead(AUTOPILOT_PIN);
  int pinHeadingValue = digitalRead(HEADING_PIN);
  int pinAltValue = digitalRead(ALT_PIN);
  int pinFLCValue = digitalRead(FLC_PIN);

  delay(10);

  
  if(buttonAutopilotStatus != pinAutopilotValue) {
    buttonAutopilotStatus = pinAutopilotValue;
    Serial.println(buttonAutopilotStatus);
    if(buttonAutopilotStatus == 0) {
      digitalWrite(13,HIGH);
      Keyboard.press('z');
      delay(50);
      Keyboard.releaseAll();
    } else {
      digitalWrite(13,LOW);
    }
  }

      if(buttonHeadingStatus != pinHeadingValue) {
    buttonHeadingStatus = pinHeadingValue;
    Serial.println(buttonHeadingStatus);
    if(buttonHeadingStatus == 0) {
      digitalWrite(13,HIGH);
      Keyboard.press('h');
      delay(50);
      Keyboard.releaseAll();
    } else {
      digitalWrite(13,LOW);
    }
  }


    if(buttonAltStatus != pinAltValue) {
    buttonAltStatus = pinAltValue;
    Serial.println(buttonAltStatus);
    if(buttonAltStatus == 0) {
      digitalWrite(13,HIGH);
      Keyboard.press('a');
      delay(50);
      Keyboard.releaseAll();
    } else {
      digitalWrite(13,LOW);
    }
  }

   if(buttonFLCStatus != pinFLCValue) {
    buttonFLCStatus = pinFLCValue;
    Serial.println(buttonAltStatus);
    if(buttonFLCStatus == 0) {
      digitalWrite(13,HIGH);
      Keyboard.press('f');
      delay(50);
      Keyboard.releaseAll();
    } else {
      digitalWrite(13,LOW);
    }
  }
}

Poor, I know, but before you vomit - I'm refactoring. My idea is to move the logic into a single function:

void checkButtonState(int pinNumber, int currentState) {

if(buttonFLCStatus != pinFLCValue) {
    buttonFLCStatus = pinFLCValue;
    Serial.println(buttonAltStatus);
    if(buttonFLCStatus == 0) {
      digitalWrite(13,HIGH);
      Keyboard.press('f');
      delay(50);
      Keyboard.releaseAll();
    } else {
      digitalWrite(13,LOW);
    }
  }
}

(with the right code though)

And then, in my loop, itterate through an array of object, calling the function. (Next, I will try interrupts, but... baby steps).

But, I'm stuck early. I am trying to create an array of buttons. With a button being a class of properties I need.

What I am trying is:

#include <Keyboard.h>

const int AUTOPILOT_PIN   = 2;
const int HEADING_PIN     = 3;
const int ALT_PIN         = 4;
const int FLC_PIN         = 5;

class Button {
  public:
    int pinNumber;
    int currentStatus = 0;
};

Button buttonArray[] = new Button[4];


void setup() {
....

However, I'm struck down with the error:

Switch:14:24: error: initializer fails to determine size of 'buttonArray'
** Button buttonArray[] = new Button[4];**
** ^~~~~~~~~~~~~**
C:\Users\craig\Documents\Arduino\Switch\Switch.ino:14:24: warning: array must be initialized with a brace-enclosed initializer [-fpermissive]
Switch:14:24: error: conversion from 'Button*' to non-scalar type 'Button' requested
exit status 1
initializer fails to determine size of 'buttonArray'

If anyone can assist me with this extremely basic thing, it would be much appreciated.

Button buttonArray[4];

Thanks! So no need for my initialisation. Got it. Thank you.

I just moved away from the array idea, and manually construct the 4 buttons. I think it might be better as I have a known set of buttons. I just need to add one line to add a new button when needed, and they can be referenced by name. My code. If you spot anything like "What the hell is he doing that for", I'd like comment. The serial stuff seems strange... I'm a .Net guy, and string interpolation would be nice. :slight_smile:

#include <Keyboard.h>

const byte AUTOPILOT_PIN   = 2;
const byte HEADING_PIN     = 3;
const byte ALT_PIN         = 4;
const byte FLC_PIN         = 5;

class Button {
  public:

    byte pinNumber;
    byte currentStatus;
    char keyStroke;
    String displayName = String(20);

    void setup(byte PinNumber, byte CurrentStatus, char KeyStroke, String DisplayName) {

      pinNumber = PinNumber;
      currentStatus = CurrentStatus;
      keyStroke = KeyStroke;
      displayName = DisplayName;
      pinMode(pinNumber, INPUT_PULLUP);
    
    }

    void checkStatus() {

      int pinValue = digitalRead(pinNumber);
      
      if (currentStatus != pinValue) {
        currentStatus = pinValue;
        Serial.print("Change detected on ");
        Serial.print(pinNumber);
        Serial.print(" (");
        Serial.print(displayName);
        Serial.print(") - New value: ");
        Serial.println(currentStatus);
        
        if (currentStatus == 0) {
          digitalWrite(13, HIGH);
          Keyboard.press(keyStroke);
          delay(50);
          Keyboard.releaseAll();
        } else {
          digitalWrite(13, LOW);
        }
      }
    }
};


Button autopilotMasterButton;
Button headingButton;
Button altitudeButton;
Button flightLevelChangeButton;


void setup() {


  autopilotMasterButton.setup(AUTOPILOT_PIN, 0, 'z', "Auto pilot master");
  headingButton.setup(HEADING_PIN, 0, 'h', "Heading hold");
  altitudeButton.setup(ALT_PIN, 0, 'a', "Altitude Hold");
  flightLevelChangeButton.setup(FLC_PIN, 0, 'f', "Flight Level Change");

  /* Setup the built in LED */
  pinMode(13,             INPUT);

  /* enable the Keyboard and Serial output */
  Keyboard.begin();
  Serial.begin(9600);

  Serial.println("Started...");

}

void loop() {

 autopilotMasterButton.checkStatus();
 headingButton.checkStatus();
 altitudeButton.checkStatus();
 flightLevelChangeButton.checkStatus();

}

I just need to add one line to add a new button when needed

not quite...

You will have to add its setup although this could probably be done when defining the button and then you have to add a line in the loop to call .checkStatus()

if your class were to keep track of its instances (would require a static array of Button* for example to keep each instance and probably ) you could have a unique class method init() that would initialize (pinMode etc...) all the buttons and another one checkStatus() to check all the buttons in one go. Then it would indeed be one line to add a new button when needed

a couple comments your code:

displayName could be a const char* as it's likely never going to change

you are breaking somewhat the OO approach by having the main code in charge of the Keyboard.begin(). Your button class should be in charge.

keyStroke being just a char you'll be limited in terms of what you can send. for example pressing ctrl-n would require to do

  Keyboard.press(ctrlKey);
  Keyboard.press('n');
  delay(100);
  Keyboard.releaseAll();

you do not handle bouncing although the delay(50); in waiting the keypress should be good enough