// 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.
// There are some extra components at the bottom of the circuit, adjacent
// to the UNO. These were used for troubleshooting and investigating how
// different components acted in WOKWI, and to see when different logic
// levels were obtained. The only components required for the provided
// sketch are the UNO, and 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
}
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.
}
}
}
}
}