Tom_nl and myself have been building arduino based interfaces that have both switches and push buttons in a matrix that uses diodes. This code solution assumes you're already down the path using serial interfacing with buttons and switches but want to maximise how many you can use with just one micro-controller. For example using a matrix you can 64 inputs using 16 pins arranged as 8 columns that feed 8 rows via the button and a signal diode (64 diodes in total and you can buy in packs of 100 for a couple of pounds/dollars/euros).
There are libraries out there for buttons and for switches but Tom_nl figured this out with some little tweaks from myself. It also has the debounce delay to stop the misreading of the multiple changes as switch contacts physically bounce very rapidly on being switched.
The code reads the matrix and populates two arrays with the current state of the switch 1 or 0 and if it has been toggled from its previous state toggled=1 or =0. If a change is detected to the matrix (has a button been pressed or a switch switched) I'm then jumping out of this loop to my checkswitches() void subroutine to figure out what action is to be taken and what needs to be sent via serial to FG.
In this example I'm using a Arduino Mega and a 7x8 array giving 56 buttons or switch positions. Note, you can accommodate a rotary switch by connecting a column to the common pin on the switch and then connecting the switch pins to individual rows (but only rows that are fed by that column).
The only thing to note is I couldn't get the very first array position array[0] to trigger the checkswitches void even though I could see the array address value changing from 1 to 0 and the toggle value changing too, so if you're going to use it just don't connect a switch or button to the very first location - or, if you're good at this you might be able to figure out why and share your thoughts.
In your variables:
- Code: Select all
// =================== new variables for button array =====================
const int butcols = 7;
const int butrows = 8;
const int bcArray[butcols] = {22,24,26,28,30,32,34}; //7 col pins can link to up to 8 buttons or switch (positions)
const int brArray[butrows] = {23,25,27,29,31,33,35,37}; //'make' or 'on' makes a circuit connect to these rows with diodes pointing towards rows
int arrayelement;
const int numbuttons = butrows*butcols;
unsigned long debouncedelay = 70; // minimum time between button presses to filter out bounces (in milliseconds).
unsigned long lastdebouncetime[numbuttons] = {}; // array storing the last time the output pin was toggled - stores time in milliseconds
bool buttonpressed = false; // bool "flag" to indicate a button press event. checkSwitches() then decides what to do
// arrays
bool buttonstate[numbuttons]; // array for storing button state (on/off)
bool buttontoggle[numbuttons] = {}; // array on/off button toggle switch (toggles between 1 and 0 when button pressed) initialises to zero
bool lastbuttonstate[numbuttons] = {}; // array for storing previous button state - for debouncing
In setup:
- Code: Select all
// set up button rows
for (int i = 0; i < butrows; i++)
{
pinMode(brArray[i], OUTPUT);
}
// set up button columns
for (int i = 0; i < butcols; i++)
{
pinMode(bcArray[i], INPUT_PULLUP);
}
In my main loop I call the read matrix subroutine using: readbuttons_array()
The readbuttons void will then call checkSwitches() if a change is detected, your checkswitches void decides what to send over serial for that particular switch or button.
Big thanks to Tom_nl for this:
- Code: Select all
void readbuttons_array()
{
// reads the buttons as an array function
for (int j = 0; j < butrows; j++) // sets up the loop for the row
{
digitalWrite(brArray[j], LOW); // sets the row pins to ground
for (int i = 0; i < butcols; i++) // sets up the loop for the columns
{
int arrayelement = i + (j * butcols); // set array element to update, saves having to compute (j* butcols) each time
lastbuttonstate[arrayelement] = buttonstate[arrayelement];
if (digitalRead(bcArray[i]) == 0)
{
// check if enough time has passed from lastpress to consider it a switch press
if ((millis() - lastdebouncetime[arrayelement]) > debouncedelay && lastbuttonstate[arrayelement] == 0)
{
buttonstate[arrayelement] = 1; // set button state to 1
checkSwitches();
if (buttontoggle[arrayelement] == 0) // do the toggling
{
buttontoggle[arrayelement] = 1; // set toggle to 1
}
else // if (buttontoggle[arrayelement] == 1)
{
buttontoggle[arrayelement] = 0; // set toggle to 0
}
}
}
else if ((millis() - lastdebouncetime[arrayelement]) > debouncedelay && lastbuttonstate[arrayelement] == 1) // or by implication button not pressed - i.e. pin
is 'high;
{
buttonstate[arrayelement] = 0; // sets button state to off
checkSwitches();
}
}
digitalWrite(brArray[j], HIGH);
lastdebouncetime[arrayelement] = millis(); // set last pressed time for debounce
}
}
Example within checkswitches() to read the autothrottle toggle switch, assuming ATarmSW = x where x is the array position you're switch is connected to.
- Code: Select all
if(buttonstate[ATarmSW] == 1 )
{
AtArm = true;
SendData();
}
else if(buttonstate[ATarmSW] == 0 )
{
AtArm = false;
SendData();
}
Example of checking for a pushbutton for the radar traffic
- Code: Select all
//RdrTfc
if(buttonstate[RdrTfcBut] )
{
RdrTfc = buttontoggle[RdrTfcBut];
SendData();
}
Example of checking the alt hold push button, note sending false then true each time. Flightgear seemed to like the state to change from 0 to 1 each time to trigger things and I'm guessing this is something to do with how the listeners are monitoring the property tree for changes.
- Code: Select all
if(buttonstate[AltHoldBut] )
{
altholdbut = false;
SendData();
altholdbut = true;
SendData();
altholdbut = false;
}
Volador