/*
Charlieplexing Demo - 12 buttons from 4 pins a, b, c, d
This method allows detecting or controlling a large number of buttons
or components(C), using a minimum number of control lines(N), C = N*N-N.
With 6 control lines, you could monitor 30 devices, 8 would give you 56,
10 lines would allow 90 buttons, eg. a computer keyboard. Pretty efficient.
Each button needs a diode (not avail on Wokwi) or some other
method to prevent the signal lines from reverse activating.
I have used OR gates instead of diodes, and they are working well, maybe
even better than diodes would, since gates provide a full logic level.
I was originally using LEDs, but found the voltage drop interfered
with the input signals, making reading unreliable.
Buttons are scanned individually in a repeating loop as follows
ab, ac, ad, ba, bc, bd, ca, cb, cd, da, db, dc.
A signal is sent individually from the left side pin, and if
detected on the right side pin, the button is pressed.
All pins are reset to a predeterminied state prior to each read.
I have provided 2 methods to decode the Button pressed,
firstly, a calculation based on gridlines activated, taking
into account that the sending grid appears amongst the receiving
grids, and second, an array based lookup table.
Calculation is relatively simple and saves on variable space.
I have used arrays starting at 1 to simplify calculations and code.
The only components required for the provided sketch are the UNO,
the 4 OR gates and 12 buttons at the top, and the associated connections.
I have tried to lay the connections out logically
and clearly, with the gridlines, 1-4, laid out from bottom to top, and
left to right. Each UNO gridline outputs to 1 OR gate, which then feeds
3 switches, then the 3 switches in each row return to the other 3 gridlines.
This circuit will present false triggers if 3 buttons are pressed together.
Eg. If you press 1, 8, 9 together, it will show a false 3.
When the system scans grid A, the 1 button will pull grid B LOW, the LOW will
travel through 8 then through 9, and pull grid D low, which will then register
as a LOW for 3, even if 3 is not pressed.
*/
byte GL[] = {0, 13, 12, 11, 10}; //Gridline pins
byte Button; //holds the result of the Button calculation
byte Grid[5] [5] = { //Lookup table from gridlines to the correct button
{ 0, 1, 2, 3, 4 },
{ 1, 0, 1, 2, 3 },
{ 2, 4, 0, 5, 6 },
{ 3, 7, 8, 0, 9 },
{ 4, 10, 11, 12, 0 }
};
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
// Display fileName in Serial Window for onBoard identification of Program and Version
Serial.println("Charlieplexing Demo - JCS-02b");
// Place Filename directly into println to save on variable space
Serial.end();
}
void loop() {
// put your main code here, to run repeatedly:
for(byte i=1;i<=4;i++) { //Scan rows
for(byte j=1;j<=4;j++) { //Scan columns
if(i!=j) { //Write pin cannot also be Read pin
for(byte k=1;k<=4;k++) { //Reset all pins prior to reading
pinMode(GL[k], OUTPUT);
digitalWrite(GL[k], HIGH);
}
digitalWrite(GL[i], LOW); //Write pin
pinMode(GL[j], INPUT_PULLUP); //Read pin
delay(10); //De-bounce physical button
if(digitalRead(GL[j])==LOW) { //Check for button, loop if not pressed
Button=i*3+j-3; //Calculate Button from RAW gridlines
if(j>i) {Button--;}; //Miss Write grid when Read on right side
Serial.print(" Row "); Serial.print(i); //RAW gridline Write
Serial.print(" Col "); Serial.print(j); //RAW gridline Read
Serial.print(" Button ");
Serial.print(Button); //Print from Calculation
Serial.print(" Grid ");
Serial.println(Grid[i][j]); //Print from Array
//Need to de-bounce software routine, only print Button once until
//released then allow to continue and press again.
//Need to consider, if you wait until button released, you will
//not be able to read another button simultaneously.
//Need to set a flag for each button to suspend print until released.
}
}
}
}
}