2 Angajamente 04579d51a4 ... 2cbcb23165

Autor SHA1 Permisiunea de a trimite mesaje. Dacă este dezactivată, utilizatorul nu va putea trimite nici un fel de mesaj Data
  Pat Beirne 2cbcb23165 added sample code 10 luni în urmă
  Pat Beirne 11b3f95e0d added the switch symbol 10 luni în urmă
3 a modificat fișierele cu 302 adăugiri și 1 ștergeri
  1. 1 1
      keypad_to_microcontroller.md
  2. 270 0
      keypad_tutorial.ino
  3. 31 0
      parts/switch-diag.sym

+ 1 - 1
keypad_to_microcontroller.md

@@ -4,7 +4,7 @@ There's a dozen ways to connect a keyboard to a microcontroller, and this paper
 There are similar articles on the internet [[see below](#external-references)], 
 but this paper introduces some new techniques: [row-grounded](#3x4-plus-ground-new-design), 
 [row-grounded-with-diodes](#3x4-plus-ground-and-2-diodes-new-design), 
-[row-grounded-with-4-diodes](#3x4-plus-ground-and-4-diodes-new-design)
+[row-grounded-with-4-diodes](#3x4-plus-ground-and-4-diodes-new-design) and the [sample code](keypad_tutorial.ino)
 
 Some articles focus on a full-function, unambiguous keyboard, 
 where multiple key-presses can be detected. Something

+ 270 - 0
keypad_tutorial.ino

@@ -0,0 +1,270 @@
+/* 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

+ 31 - 0
parts/switch-diag.sym

@@ -0,0 +1,31 @@
+v 20130925 2
+L 200 500 500 800 3 0 0 0 -1 -1
+T 100 400 5 10 0 0 0 0 1
+device=SWITCAP-switch
+P 500 700 800 1000 1 0 1
+{
+T 650 350 5 8 0 1 0 0 1
+pinnumber=2
+T 650 350 5 8 0 0 0 0 1
+pinseq=2
+T 500 300 5 10 0 1 0 0 1
+pinlabel=B
+T 500 300 5 10 0 1 0 0 1
+pintype=io
+}
+P 300 500 0 200 1 0 1
+{
+T 100 250 5 8 0 1 0 0 1
+pinnumber=1
+T 100 250 5 8 0 0 0 0 1
+pinseq=1
+T 300 200 5 10 0 1 0 0 1
+pinlabel=A
+T 300 200 5 10 0 1 0 0 1
+pintype=io
+}
+T 300 0 8 10 1 1 0 0 1
+clock=clk
+T 400 400 8 10 1 1 0 0 1
+refdes=S?
+L 350 650 300 700 3 0 0 0 -1 -1