Skip to content

Instantly share code, notes, and snippets.

@AnthonyDiGirolamo
Created May 25, 2020 18:24
Show Gist options
  • Save AnthonyDiGirolamo/c240e49642f4748adf9d3e0a02da0a01 to your computer and use it in GitHub Desktop.
Save AnthonyDiGirolamo/c240e49642f4748adf9d3e0a02da0a01 to your computer and use it in GitHub Desktop.
#include <Wire.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp;
#define NUM_ROWS 5
#define NUM_COLS 10
uint32_t hold_time[NUM_ROWS][NUM_COLS];
char key_matrix[NUM_ROWS][NUM_COLS] = {
{'<', '^', 'v', '>', '1', '2', '3', '4', '5', '6'},
{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'},
{'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '7'},
{'S', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', 'B'},
{'T', 'C', 'A', 'F', ' ', ' ', 'A', 'C', 'S', '\n'},
};
// bit positions
#define COL0 0 // PORTA
#define COL1 1 // PORTA
#define ROW0 2 // PORTA
#define ROW1 3 // PORTA
#define ROW2 4 // PORTA
#define ROW3 5 // PORTA
#define ROW4 6 // PORTA
// nothing on PORTA pin 7
#define COL8 8+0 // PORTB
#define COL9 8+1 // PORTB
#define COL2 8+2 // PORTB
#define COL3 8+3 // PORTB
#define COL4 8+4 // PORTB
#define COL5 8+5 // PORTB
#define COL6 8+6 // PORTB
#define COL7 8+7 // PORTB
uint8_t col_bit_positions[] = {
COL0,
COL1,
COL2,
COL3,
COL4,
COL5,
COL6,
COL7,
COL8,
COL9,
};
uint8_t row_bit_positions[] = {
ROW0,
ROW1,
ROW2,
ROW3,
ROW4,
};
uint16_t last_row_read[NUM_ROWS];
uint16_t this_row_read[NUM_ROWS];
void setup() {
Serial.begin(115200);
delay(2000);
for (uint8_t row=0; row<NUM_ROWS; row++) {
last_row_read[row] = 0;
for (uint8_t col=0; col<NUM_COLS; col++) {
hold_time[row][col] = 0;
}
}
Serial.println("mcp.begin");
mcp.begin(); // use default address 0
// // All pins as inputs
// mcp.writeRegister(MCP23017_IODIRA, b11111111);
// mcp.writeRegister(MCP23017_IODIRB, b11111111);
// // All pull-ups
// mcp.writeRegister(MCP23017_GPPUA, b11111111);
// mcp.writeRegister(MCP23017_GPPUB, b11111111);
// Set all pin output to 0
mcp.writeGPIOAB(0);
Serial.println("iodir");
// COLS as inputs ROWS as outputs
mcp.writeRegister(MCP23017_IODIRA, 0x03); // b00000011
mcp.writeRegister(MCP23017_IODIRB, 0xFF); // b11111111
Serial.println("gppu");
// Pullup COLS
mcp.writeRegister(MCP23017_GPPUA, 0x03); // b00000011
mcp.writeRegister(MCP23017_GPPUB, 0xFF); // b11111111
pinMode(13, OUTPUT); // use the p13 LED as debugging
} // setup()
// Set the row pin we want to scan to LOW (ground) and all others to HIGH
// row: 0-4
void activate_row(uint8_t row) {
// Set current ROW output to LOW
uint8_t current_row;
current_row = 1 << (row+2); // ROW=0: current_row = 00000100
current_row = current_row ^ 0x7C; // ROW=0: current_row = 01111000
mcp.writeRegister(MCP23017_GPIOA, current_row);
}
void activate_cols() {
// ROWS as inputs COLS as outputs
mcp.writeRegister(MCP23017_IODIRA, 0x7C); // b01111100
mcp.writeRegister(MCP23017_IODIRB, 0x00); // b00000000
// Pullup ROWS
mcp.writeRegister(MCP23017_GPPUA, 0x7C); // b01111100
mcp.writeRegister(MCP23017_GPPUB, 0x00); // b00000000
}
void print_16_bits(uint16_t n) {
char s[32];
sprintf(s, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
(n & 0x08000 ? 1 : 0), \
(n & 0x04000 ? 1 : 0), \
(n & 0x02000 ? 1 : 0), \
(n & 0x01000 ? 1 : 0), \
(n & 0x0800 ? 1 : 0), \
(n & 0x0400 ? 1 : 0), \
(n & 0x0200 ? 1 : 0), \
(n & 0x0100 ? 1 : 0), \
(n & 0x080 ? 1 : 0), \
(n & 0x040 ? 1 : 0), \
(n & 0x020 ? 1 : 0), \
(n & 0x010 ? 1 : 0), \
(n & 0x08 ? 1 : 0), \
(n & 0x04 ? 1 : 0), \
(n & 0x02 ? 1 : 0), \
(n & 0x01 ? 1 : 0));
Serial.println(s);
}
bool button_pressed(uint8_t row, uint8_t button_bit_position) {
// !(this button == 0) and (last_button == 1)
return (!(this_row_read[row] & (1<<button_bit_position))
&& (last_row_read[row] & (1<<button_bit_position)));
}
bool button_released(uint8_t row, uint8_t button_bit_position) {
// !(this button == 1) and (last_button == 0)
return ((this_row_read[row] & (1<<button_bit_position))
&& !(last_row_read[row] & (1<<button_bit_position)));
}
bool button_held(uint8_t row, uint8_t button_bit_position) {
return !(this_row_read[row] & (1<<button_bit_position));
}
uint16_t last_update_millis = 0;
uint16_t this_update_millis = 0;
uint32_t current_hold_time = 0;
uint8_t currently_held_key_row = 0;
uint8_t currently_held_key_col = 0;
void loop() {
bool matrix_changed = false;
uint8_t row, r, c;
uint8_t pressed_or_released = 0;
last_update_millis = this_update_millis;
// Save last_row_reads
for (row=0; row<NUM_ROWS; row++) {
last_row_read[row] = this_row_read[row];
}
// Update matrix row values
for (row=0; row<NUM_ROWS; row++) {
activate_row(row);
this_row_read[row] = mcp.readGPIOAB();
if (this_row_read[row] != last_row_read[row]) {
matrix_changed = true;
}
}
this_update_millis = millis();
if (matrix_changed) {
// print out all rows
Serial.write("\n\n\n");
Serial.write("Last millis diff: ");
Serial.println(this_update_millis - last_update_millis);
Serial.println(" C R C");
Serial.println(" 76543298x4321010");
for (r=0; r<NUM_ROWS; r++) {
Serial.print("ROW"); Serial.print(r); Serial.print(": ");
print_16_bits(this_row_read[r]);
}
}
// update debounce time, maybe not necessary?
for (r=0; r<NUM_ROWS; r++) {
for (c=0; c<NUM_COLS; c++) {
if (button_pressed(r, col_bit_positions[c])) {
Serial.print(key_matrix[r][c]);
currently_held_key_row = r;
currently_held_key_col = c;
current_hold_time = this_update_millis - last_update_millis;
}
else if (button_released(r, col_bit_positions[c])) {
current_hold_time = 0;
}
else if (button_held(r, col_bit_positions[c])) {
// only repeat the last key held
if (currently_held_key_row == r && currently_held_key_col == c) {
if (current_hold_time > 230) {
Serial.print(key_matrix[r][c]);
current_hold_time = 200;
}
else {
current_hold_time = current_hold_time + (this_update_millis - last_update_millis);
}
}
}
// else if (button_held(r, col_bit_positions[c])) {
// Serial.print("Held ");
// Serial.print(" Row ");
// Serial.print(r);
// Serial.print(" Col ");
// Serial.println(c);
// }
}
}
// end update hold_time
} // loop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment