/************************************************************************
16 Buttons on 9 Pins - dlloydev
===============================
⦿ Built-in 32 ms debounce for all buttons
⦿ Multiple pressed button detection up to 8 per row (use keyboard and mouse).
⦿ Uses pwm timer tp provide 3 input states and for debounce sample period .
⦿ No pullup or pulldown resistors required for buttons.
⦿ One pwm current limiting resistor required per button pair (column).
⦿ Can be scaled for more or fewer buttons.
⦿ No external GPIO expander ICs required
***********************************************************************/
const char label1[9] = "ABCDEFGH";
const char label2[9] = "IJKLMNOP";
const byte pin[] = {4, 5, 6, 7, 16, 17, 18, 19};
volatile byte row1[] = {0, 0, 0, 0, 0, 0, 0, 0};
volatile byte row2[] = {0, 0, 0, 0, 0, 0, 0, 0};
volatile byte status1 = 0, status2 = 0;
volatile byte prevStatus1 = 0, prevStatus2 = 0;
volatile bool readyToRead;
void setup() {
Serial.begin(115200);
pwmTimerInit();
}
void loop() {
checkButtons();
}
ISR (TIMER2_COMPA_vect) { //16 ms pwm and debounce timer
static int counter = 0;
counter++;
if (counter == 2) { //8 ms * 2
PORTD ^= (1 << PD3);
counter = 0;
for (int i = 0; i < 8; i++) { //prepare for next reading
row1[i] <<= 1;
row2[i] <<= 1;
}
readyToRead = true;
}
}
void checkButtons() {
if (readyToRead) {
cli(); //stop interrupts
prevStatus1 = status1;
prevStatus2 = status2;
for (int i = 0; i < 8; i++) {
if (digitalRead(pin[i])) row1[i] |= 1;
else row2[i] |= 1;
if (!((row1[i] & 0xE0) == 0xE0)) bitWrite(status1, i, 0); // top row button just released
if ((row1[i] & 0x07) == 0x07) bitWrite(status1, i, 1); // top row button just pressed
if (!((row2[i] & 0xE0) == 0xE0)) bitWrite(status2, i, 0); // bottom row button just released
if ((row2[i] & 0x07) == 0x07) bitWrite(status2, i, 1); // bottom row button just pressed
}
sei(); //allow interrupts
if (prevStatus1 != status1 || prevStatus2 != status2) {
if (!status1 && !status2) Serial.println(F("All released"));
else {
Serial.print(F("Pressed "));
for (int i = 0; i < 8; i++) {
if (status1 & 1 << i) Serial.print(label1[i]);
if (status2 & 1 << i) Serial.print(label2[i]);
}
Serial.println();
}
}
readyToRead = false;
}
}
void pwmTimerInit() { //initialize pwm / debounce timer
TCCR2A = (1 << WGM21); // wave form mode 2: CTC, OC2A disconnected
TCCR2B = (1 << CS22) + (1 << CS21) ; // prescaler = 256
TIMSK2 = (1 << OCIE2A); // interrupt when compare match with OCR2A
OCR2A = 249;
pinMode(3, OUTPUT);
}