keypad_tutorial.ino 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /* demo several 4x4 and 3x4 keyboard scanners
  2. *
  3. * on ESP8266, full 8 pins, using gpios 15,13,14,12 2,0,4,5
  4. *
  5. * note: on the Wemos, gpio15 has an external pulldown
  6. * and gpio16 does not have an internal pullup
  7. * making both awkward to use
  8. *
  9. * using the module that has 16 tact buttons, connector at the left, S1 top left, S16 bottom right
  10. * the pins are bottom to top : row 4..1, col 1..4
  11. */
  12. int rows[] = {5,4,0,2}; // driven
  13. int cols[] = {14,12,13,15}; // input only
  14. //#define FIVE_PIN 1
  15. //#define SEVEN_PIN 1
  16. #define FOUR_PIN 1
  17. void setup() {
  18. delay(1000);
  19. Serial.begin(115200);
  20. // set all rows as 0, ready for interrupt sensing
  21. rowsSet(0);
  22. // set up all column pins as inputs with pullups
  23. pinMode(cols[0],INPUT_PULLUP);
  24. pinMode(cols[1],INPUT_PULLUP);
  25. pinMode(cols[2],INPUT_PULLUP);
  26. attachInterrupt(digitalPinToInterrupt(cols[0]), kbd_irq, FALLING);
  27. attachInterrupt(digitalPinToInterrupt(cols[1]), kbd_irq, FALLING);
  28. attachInterrupt(digitalPinToInterrupt(cols[2]), kbd_irq, FALLING);
  29. Serial.println();
  30. }
  31. // 0, set all rows low, anything else is a bit pattern of hi/lo
  32. // simulate open-drain with pullup
  33. void rowsSet(int rowPattern) {
  34. for (int r=0; r<4; r++) {
  35. if (rowPattern & 1)
  36. pinMode(rows[r],INPUT_PULLUP);
  37. else {
  38. pinMode(rows[r],OUTPUT);
  39. digitalWrite(rows[r],0);
  40. }
  41. rowPattern >>= 1;
  42. }
  43. }
  44. // state machine 0=ready, 1=interrupt detected, 2=interrupt handled waiting for release
  45. const int KEY_NONE = 0;
  46. const int KEY_DETECTED = 1;
  47. const int KEY_PROCESSED = 2;
  48. static int key_state;
  49. ICACHE_RAM_ATTR void kbd_irq(void) {
  50. // inform the main code
  51. if (key_state == KEY_NONE)
  52. key_state = KEY_DETECTED;
  53. }
  54. static char lut4[] = "123A456B789C*0#D"; // used in 4x4 keypad
  55. static char lut[] = "123456789*0#"; // used with 3x4 kaypad
  56. int char_count;
  57. // calculator demo
  58. // key=0, ignore key=ascii '0'...'9' data key='*' addition key='#' show total
  59. void calculator(char key) {
  60. if (key) {
  61. static int acc = 0, sum=0;
  62. if (key>='0' && key<='9') {
  63. acc = acc*10+(key&0x0f);
  64. }
  65. else if (key=='*') { // addition
  66. sum += acc;
  67. acc = 0;
  68. }
  69. else if (key=='#') { // finish and show total
  70. sum += acc;
  71. Serial.println(String("total: ")+String(sum));
  72. sum = acc = 0;
  73. }
  74. }
  75. }
  76. #ifdef SEVEN_PIN
  77. // check all the column inputs, return a number, 1/2/3=pressed 0=nokey
  78. int readColumns() {
  79. // return 10 - digitalRead(cols[0]) - 2*digitalRead(cols[1]) - 3*digitalRead(cols[2]) - 4*digitalRead(cols[3]);
  80. return 6 - digitalRead(cols[0]) - 2*digitalRead(cols[1]) - 3*digitalRead(cols[2]);
  81. }
  82. const int NO_KEYS = 0;
  83. int rowPattern [] = {~1, ~2, ~4, ~8};
  84. void loop() {
  85. // put your main code here, to run repeatedly:
  86. int row, col;
  87. switch(key_state) {
  88. case KEY_NONE:
  89. break;
  90. case KEY_DETECTED:
  91. // just got an interrupt, scan the keys
  92. for (row=0; row<4; row++) {
  93. rowsSet(rowPattern[row]);
  94. delayMicroseconds(10);
  95. col = readColumns();
  96. if (col)
  97. break;
  98. }
  99. rowsSet(0);
  100. key_state = KEY_PROCESSED;
  101. // keyboard scan done, the information is in (row,col)
  102. if (col) {
  103. Serial.print(String(lut[3*row+col-1])); // <---the key that was pressed
  104. if (++char_count >= 16)
  105. char_count=0, Serial.println();
  106. }
  107. break;
  108. case KEY_PROCESSED:
  109. // wait for release
  110. col = readColumns();
  111. if (col == NO_KEYS)
  112. key_state = KEY_NONE;
  113. break;
  114. }
  115. }
  116. // NOTE: even though a 7 pin connection allows 2-key rollover, the code example
  117. // above does NOT handles 2 keys pressed at the same time.
  118. #endif
  119. #ifdef FIVE_PIN
  120. // column decode these are octal values, groups of 3 bits
  121. // check all the column inputs, return the pattern; no key press returns 0b111
  122. int readColumns() {
  123. return digitalRead(cols[0]) + 2*digitalRead(cols[1]) + 4*digitalRead(cols[2]);
  124. }
  125. const int NO_KEYS = 07;
  126. int rowPattern [] = {0b11, 0b10, 0b01, 0b00};
  127. // column sense patterns, as the rowPattern is cycled; these are octal values, 3 bits at a time
  128. int fiveKeyLUT[] = {06666, 05555, 03333, // 123
  129. 07676, 07575, 07373, // 456
  130. 07766, 07755, 07733, // 789
  131. 07666, 07555, 07333}; // *0#
  132. void loop() {
  133. // put your main code here, to run repeatedly:
  134. int row, col, d;
  135. char key = 0;
  136. switch(key_state) {
  137. case KEY_NONE:
  138. break;
  139. case KEY_DETECTED:
  140. //Serial.println("got key");
  141. // just got an interrupt, scan the keys
  142. d = 0;
  143. for (row=0; row<4; row++) {
  144. //Serial.println(String("scan row ")+String(row)+" using pattern 0b"+String(rowPattern[row],BIN));
  145. rowsSet(rowPattern[row]);
  146. delayMicroseconds(10);
  147. d = 8*d + readColumns(); // shift left by 3, and read next 3
  148. //Serial.println(String("and rows read as: 0")+String(d,OCT));
  149. }
  150. rowsSet(0);
  151. key_state = KEY_PROCESSED;
  152. // now analyze the column reads
  153. //Serial.println(String("final d=")+String(d,OCT));
  154. for (int i=0; i<sizeof(fiveKeyLUT)/sizeof(fiveKeyLUT[0]); i++)
  155. if (d==fiveKeyLUT[i]) {
  156. key = lut[i];
  157. break;
  158. }
  159. if (key) {
  160. Serial.print(key);
  161. if (++char_count >= 16)
  162. char_count=0, Serial.println();
  163. }
  164. break;
  165. case KEY_PROCESSED:
  166. // wait for release
  167. col = readColumns();
  168. if (col==NO_KEYS)
  169. key_state = KEY_NONE;
  170. break;
  171. }
  172. calculator(key);
  173. }
  174. #endif
  175. #ifdef FOUR_PIN
  176. // decode these are hex values
  177. const int fourKeyLUT[] = { 0xaa, 0x55, 0x00, // 123
  178. 0xee, 0xdd, 0xcc, // 456
  179. 0xfa, 0xf5, 0xf0, // 789
  180. 0xea, 0xd5, 0xc0 // *0#
  181. };
  182. // check all the column inputs, return a number, 01/10/00=pressed 11=nokey
  183. int readColumns() {
  184. return digitalRead(cols[0]) + 2*digitalRead(cols[1]);
  185. }
  186. const int NO_KEYS = 0x3;
  187. int rowPattern [] = {0b11, 0b10, 0b01, 0b00};
  188. void loop() {
  189. // put your main code here, to run repeatedly:
  190. int row, col, d;
  191. char key=0;
  192. switch(key_state) {
  193. case KEY_NONE:
  194. break;
  195. case KEY_DETECTED:
  196. //Serial.println("got key");
  197. delay(5); //wait for the bounce to settle
  198. // just got an interrupt, scan the keys
  199. d = 0;
  200. for (row=0; row<4; row++) {
  201. //Serial.println(String("scan row ")+String(row)+" using pattern 0b"+String(rowPattern[row],BIN));
  202. rowsSet(rowPattern[row]);
  203. delayMicroseconds(10);
  204. d = 4*d + readColumns(); // shift left by 2, and read next 2
  205. //Serial.println(String("and rows read as: 0x")+String(d,HEX));
  206. }
  207. rowsSet(0);
  208. key_state = KEY_PROCESSED;
  209. // now analyze the column reads
  210. // Serial.println(String("final d=")+String(d,HEX));
  211. key = 0;
  212. for (int i=0; i<sizeof(fourKeyLUT)/sizeof(fourKeyLUT[0]); i++)
  213. if (d==fourKeyLUT[i]) {
  214. key = lut[i];
  215. break;
  216. }
  217. if (key) {
  218. Serial.print(key);
  219. if (++char_count >= 16)
  220. char_count=0, Serial.println();
  221. }
  222. break;
  223. case KEY_PROCESSED:
  224. // wait for release
  225. col = readColumns();
  226. if (col==NO_KEYS)
  227. key_state = KEY_NONE;
  228. break;
  229. }
  230. calculator(key);
  231. }
  232. #endif