123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /* demo several 4x4 and 3x4 keyboard scanners
- *
- * on ESP8266, full 8 pins, using gpios 15,13,14,12 2,0,4,5
- *
- * note: on the Wemos, gpio15 has an external pulldown
- * and gpio16 does not have an internal pullup
- * making both awkward to use
- *
- * using the module that has 16 tact buttons, connector at the left, S1 top left, S16 bottom right
- * the pins are bottom to top : row 4..1, col 1..4
- */
- int rows[] = {5,4,0,2}; // driven
- int cols[] = {14,12,13,15}; // input only
- //#define FIVE_PIN 1
- //#define SEVEN_PIN 1
- #define FOUR_PIN 1
- void setup() {
- delay(1000);
- Serial.begin(115200);
- // set all rows as 0, ready for interrupt sensing
- rowsSet(0);
- // set up all column pins as inputs with pullups
- pinMode(cols[0],INPUT_PULLUP);
- pinMode(cols[1],INPUT_PULLUP);
- pinMode(cols[2],INPUT_PULLUP);
- attachInterrupt(digitalPinToInterrupt(cols[0]), kbd_irq, FALLING);
- attachInterrupt(digitalPinToInterrupt(cols[1]), kbd_irq, FALLING);
- attachInterrupt(digitalPinToInterrupt(cols[2]), kbd_irq, FALLING);
- Serial.println();
- }
- // 0, set all rows low, anything else is a bit pattern of hi/lo
- // simulate open-drain with pullup
- void rowsSet(int rowPattern) {
- for (int r=0; r<4; r++) {
- if (rowPattern & 1)
- pinMode(rows[r],INPUT_PULLUP);
- else {
- pinMode(rows[r],OUTPUT);
- digitalWrite(rows[r],0);
- }
- rowPattern >>= 1;
- }
- }
- // state machine 0=ready, 1=interrupt detected, 2=interrupt handled waiting for release
- const int KEY_NONE = 0;
- const int KEY_DETECTED = 1;
- const int KEY_PROCESSED = 2;
- static int key_state;
- ICACHE_RAM_ATTR void kbd_irq(void) {
- // inform the main code
- if (key_state == KEY_NONE)
- key_state = KEY_DETECTED;
- }
- static char lut4[] = "123A456B789C*0#D"; // used in 4x4 keypad
- static char lut[] = "123456789*0#"; // used with 3x4 kaypad
- int char_count;
- // calculator demo
- // key=0, ignore key=ascii '0'...'9' data key='*' addition key='#' show total
- void calculator(char key) {
- if (key) {
- static int acc = 0, sum=0;
- if (key>='0' && key<='9') {
- acc = acc*10+(key&0x0f);
- }
- else if (key=='*') { // addition
- sum += acc;
- acc = 0;
- }
- else if (key=='#') { // finish and show total
- sum += acc;
- Serial.println(String("total: ")+String(sum));
- sum = acc = 0;
- }
- }
- }
- #ifdef SEVEN_PIN
- // check all the column inputs, return a number, 1/2/3=pressed 0=nokey
- int readColumns() {
- // return 10 - digitalRead(cols[0]) - 2*digitalRead(cols[1]) - 3*digitalRead(cols[2]) - 4*digitalRead(cols[3]);
- return 6 - digitalRead(cols[0]) - 2*digitalRead(cols[1]) - 3*digitalRead(cols[2]);
- }
- const int NO_KEYS = 0;
- int rowPattern [] = {~1, ~2, ~4, ~8};
- void loop() {
- // put your main code here, to run repeatedly:
- int row, col;
- switch(key_state) {
- case KEY_NONE:
- break;
- case KEY_DETECTED:
- // just got an interrupt, scan the keys
- for (row=0; row<4; row++) {
- rowsSet(rowPattern[row]);
- delayMicroseconds(10);
- col = readColumns();
- if (col)
- break;
- }
- rowsSet(0);
- key_state = KEY_PROCESSED;
- // keyboard scan done, the information is in (row,col)
- if (col) {
- Serial.print(String(lut[3*row+col-1])); // <---the key that was pressed
- if (++char_count >= 16)
- char_count=0, Serial.println();
- }
- break;
- case KEY_PROCESSED:
- // wait for release
- col = readColumns();
- if (col == NO_KEYS)
- key_state = KEY_NONE;
- break;
- }
- }
- // NOTE: even though a 7 pin connection allows 2-key rollover, the code example
- // above does NOT handles 2 keys pressed at the same time.
- #endif
- #ifdef FIVE_PIN
- // column decode these are octal values, groups of 3 bits
- // check all the column inputs, return the pattern; no key press returns 0b111
- int readColumns() {
- return digitalRead(cols[0]) + 2*digitalRead(cols[1]) + 4*digitalRead(cols[2]);
- }
- const int NO_KEYS = 07;
- int rowPattern [] = {0b11, 0b10, 0b01, 0b00};
- // column sense patterns, as the rowPattern is cycled; these are octal values, 3 bits at a time
- int fiveKeyLUT[] = {06666, 05555, 03333, // 123
- 07676, 07575, 07373, // 456
- 07766, 07755, 07733, // 789
- 07666, 07555, 07333}; // *0#
- void loop() {
- // put your main code here, to run repeatedly:
- int row, col, d;
- char key = 0;
- switch(key_state) {
- case KEY_NONE:
- break;
- case KEY_DETECTED:
- //Serial.println("got key");
- // just got an interrupt, scan the keys
- d = 0;
- for (row=0; row<4; row++) {
- //Serial.println(String("scan row ")+String(row)+" using pattern 0b"+String(rowPattern[row],BIN));
- rowsSet(rowPattern[row]);
- delayMicroseconds(10);
- d = 8*d + readColumns(); // shift left by 3, and read next 3
- //Serial.println(String("and rows read as: 0")+String(d,OCT));
- }
- rowsSet(0);
- key_state = KEY_PROCESSED;
- // now analyze the column reads
- //Serial.println(String("final d=")+String(d,OCT));
- for (int i=0; i<sizeof(fiveKeyLUT)/sizeof(fiveKeyLUT[0]); i++)
- if (d==fiveKeyLUT[i]) {
- key = lut[i];
- break;
- }
-
- if (key) {
- Serial.print(key);
- if (++char_count >= 16)
- char_count=0, Serial.println();
- }
- break;
- case KEY_PROCESSED:
- // wait for release
- col = readColumns();
- if (col==NO_KEYS)
- key_state = KEY_NONE;
- break;
- }
-
- calculator(key);
- }
- #endif
- #ifdef FOUR_PIN
- // decode these are hex values
- const int fourKeyLUT[] = { 0xaa, 0x55, 0x00, // 123
- 0xee, 0xdd, 0xcc, // 456
- 0xfa, 0xf5, 0xf0, // 789
- 0xea, 0xd5, 0xc0 // *0#
- };
-
- // check all the column inputs, return a number, 01/10/00=pressed 11=nokey
- int readColumns() {
- return digitalRead(cols[0]) + 2*digitalRead(cols[1]);
- }
- const int NO_KEYS = 0x3;
- int rowPattern [] = {0b11, 0b10, 0b01, 0b00};
- void loop() {
- // put your main code here, to run repeatedly:
- int row, col, d;
- char key=0;
- switch(key_state) {
- case KEY_NONE:
- break;
- case KEY_DETECTED:
- //Serial.println("got key");
- delay(5); //wait for the bounce to settle
- // just got an interrupt, scan the keys
- d = 0;
- for (row=0; row<4; row++) {
- //Serial.println(String("scan row ")+String(row)+" using pattern 0b"+String(rowPattern[row],BIN));
- rowsSet(rowPattern[row]);
- delayMicroseconds(10);
- d = 4*d + readColumns(); // shift left by 2, and read next 2
- //Serial.println(String("and rows read as: 0x")+String(d,HEX));
- }
- rowsSet(0);
- key_state = KEY_PROCESSED;
- // now analyze the column reads
- // Serial.println(String("final d=")+String(d,HEX));
- key = 0;
- for (int i=0; i<sizeof(fourKeyLUT)/sizeof(fourKeyLUT[0]); i++)
- if (d==fourKeyLUT[i]) {
- key = lut[i];
- break;
- }
-
- if (key) {
- Serial.print(key);
- if (++char_count >= 16)
- char_count=0, Serial.println();
- }
- break;
- case KEY_PROCESSED:
- // wait for release
- col = readColumns();
- if (col==NO_KEYS)
- key_state = KEY_NONE;
- break;
- }
- calculator(key);
- }
- #endif
|