27static constexpr uint8_t ROW_COUNT = 5;
28static constexpr uint8_t COLUMN_COUNT = 7;
29static constexpr uint8_t ROW_PINS[ROW_COUNT] = {0, 1, 2, 3, 4};
30static constexpr uint8_t COLUMN_PINS[COLUMN_COUNT] = {5, 6, 7, 8, 9, 10, 11};
31static constexpr uint16_t ROW_MASK = 0x001F;
32static constexpr uint16_t COLUMN_MASK = 0x0FE0;
35static constexpr char KEY_MAP[COLUMN_COUNT][ROW_COUNT] = {
36 {
'q',
'e',
'r',
'u',
'o'},
37 {
'w',
's',
'g',
'h',
'l'},
38 {
'\0',
'd',
't',
'y',
'i'},
39 {
'a',
'p',
'\0',
'\n',
'\0'},
40 {
'\0',
'x',
'v',
'b',
'$'},
41 {
' ',
'z',
'c',
'n',
'm'},
42 {
'\0',
'\0',
'f',
'j',
'k'},
45static constexpr char SYMBOL_MAP[COLUMN_COUNT][ROW_COUNT] = {
46 {
'#',
'2',
'3',
'_',
'+'},
47 {
'1',
'4',
'/',
':',
'"'},
48 {
'\0',
'5',
'(',
')',
'-'},
49 {
'*',
'@',
'\0',
'\0',
'\0'},
50 {
'\0',
'8',
'?',
'!',
'\0'},
51 {
'\0',
'7',
'9',
',',
'.'},
52 {
'0',
'\0',
'6',
';',
'\''},
55static constexpr uint8_t SYMBOL_ROW = 0;
56static constexpr uint8_t SYMBOL_COLUMN = 2;
72 for (uint8_t row = 0; row < ROW_COUNT; ++row) {
74 delayMicroseconds(50);
77 for (uint8_t column = 0; column < COLUMN_COUNT; ++column) {
78 state[row][column] = (levels & (1UL << COLUMN_PINS[column])) == 0;
86 delayMicroseconds(20);
92 if (row == 0 && column == 2)
return "Symbol";
93 if (row == 2 && column == 3)
return "Right Shift";
94 if (row == 4 && column == 3)
return "Backspace";
95 if (row == 0 && column == 4)
return "Alt";
96 if (row == 0 && column == 6)
return "Mic";
97 if (row == 1 && column == 6)
return "Left Shift";
109 const char key = symbolLayer ? SYMBOL_MAP[column][row] : KEY_MAP[column][row];
111 Serial.print(
"Enter");
112 }
else if (key ==
' ') {
113 Serial.print(
"Space");
114 }
else if (key ==
'\0') {
115 Serial.print(
"Unmapped");
123 const bool symbolLayer = current[SYMBOL_ROW][SYMBOL_COLUMN];
124 for (uint8_t row = 0; row < ROW_COUNT; ++row) {
125 for (uint8_t column = 0; column < COLUMN_COUNT; ++column) {
126 if (current[row][column] ==
keyState[row][column]) {
130 keyState[row][column] = current[row][column];
132 Serial.println(current[row][column] ?
" pressed" :
" released");
139 Serial.begin(115200);
144 Serial.println(
"Failed to find AW9523 - check your wiring and address pins!");
174 detachInterrupt(digitalPinToInterrupt(
SENSOR_IRQ));
175 bool current[ROW_COUNT][COLUMN_COUNT] = {};
IoExpanderAW9523 expander
bool keyState[ROW_COUNT][COLUMN_COUNT]
void scanKeyboard(bool state[ROW_COUNT][COLUMN_COUNT])
void reportChanges(const bool current[ROW_COUNT][COLUMN_COUNT])
void onKeyboardInterrupt()
void printKeyName(uint8_t row, uint8_t column, bool symbolLayer)
const char * specialKeyName(uint8_t row, uint8_t column)
volatile bool keyboardInterrupt
bool begin(SensorCommCustom::CustomCallback callback, uint8_t addr)
Initialize the sensor using custom callback interface.
Driver for the AW9523/AW9523B 16-channel GPIO and LED controller.
bool enableInterrupts(uint16_t pinMask, bool enable=true)
Enable or disable input-change interrupts for selected pins.
bool setPort0PushPull(bool pushPull)
Select the P0 GPIO output driver type.
uint16_t digitalReadPort() override
Read both GPIO input ports.
void digitalWritePort(uint16_t mask, uint16_t values) override
Write selected GPIO outputs while preserving unselected pins.
void digitalWrite(uint8_t pin, bool value)
Write a digital value to an output pin.
void configPins(uint16_t pinMask, uint8_t mode)
Configure multiple pins as input or output simultaneously.