Go Down

Topic: Extended Charlieplexing (Read 1 time) previous topic - next topic

jkj56

I do not have any problem but I found a solution to a problem I have had - hopefully someone else will find it useful.
I have bought some 4x4 16 key matrix membrane keypads - see image. They are very cheap and very useful - but interface to them require normally 4+4=8 ports.
I can use normal charlieplexing and then only use 4 ports but then I cannot use the diagonal keys! 



I tried use the analog method connecting seven resistor coupled as a voltage divider and use only one AD ports - it works but I'm not sure have stable it is. 
After some thinking and investigating I found out that it was possible to extend the charlieplexing by adding an extra diode for every column. Using 8 diodes instead of 4. See the sketch. The tricks is to pull two lines low at key press instead of one line - except for the diagonal where only one line is pulled low.



If you use normal charlieplexing and have n ports you can use these n ports to manage (n*n)-n keys using n diodes. At my method, the extended charlieplexing, you can with n ports manage n*n keys but it require additional n diodes total of 2*n diodes.
Sample code to test the extended charlieplexing:

Code: [Select]

#define RK_0 B10000100
#define RK_1 B00011000
#define RK_2 B00011100
#define RK_3 B00010110
#define RK_4 B00101001
#define RK_5 B00101100
#define RK_6 B00100100
#define RK_7 B01001001
#define RK_8 B01001000
#define RK_9 B01000010
#define RK_NUM B10000110
#define RK_STAR B10000001
#define RK_A B00010010
#define RK_B B00100001
#define RK_C B01000011
#define RK_D B10000011

const int pinKM[] = {4,5,6,7};  // four pins to Keyboard Matrix

void setup(void)
{
  Serial.begin(9600);
}

void loop(void) {

  char c = ReadKey(); 
  Serial.println(c);
}

// -------------------  ReadKey -------------------
// wait for a key to be pressed
char ReadKey(void) {
  char c;
  byte r;

  unsigned long ti=millis()+2000;              // simple autorepeat
  while (0!=ReadKeyboardRaw() && ti>millis());  // wait for previeus key to be unpressed..

  do {
    while (0==(r=ReadKeyboardRaw()));
    delay(10);
  }
  while( r!=ReadKeyboardRaw() );
  switch(r) {
    case RK_0: c = '0'; break;   
    case RK_1: c = '1'; break;
    case RK_2: c = '2'; break;   
    case RK_3: c = '3'; break;       
    case RK_4: c = '4'; break;       
    case RK_5: c = '5'; break;   
    case RK_6: c = '6'; break;   
    case RK_7: c = '7'; break;   
    case RK_8: c = '8'; break;   
    case RK_9: c = '9'; break;   
    case RK_NUM: c = '#'; break;
    case RK_STAR:c = '*'; break;
    case RK_A: c = 'A'; break;
    case RK_B: c = 'B'; break;
    case RK_C: c = 'C'; break;
    case RK_D: c = 'D'; break;   
    default: c = '?';
  }
  return c;
}

// -------------------  ReadKeyboardRaw -------------------
byte ReadKeyboardRaw(void) {
  byte rawkey=0;
 
  for(byte i=0;i<4;i++) {
// setup ports..   
    for(byte j=0;j<4;j++) {
      if (i==j) {    // output '0'
        pinMode(pinKM[j], OUTPUT);             
        digitalWrite( pinKM[j], LOW);           
      }
      else { // input
        pinMode(pinKM[j], INPUT);                         
        digitalWrite( pinKM[j], HIGH);                                     
      }
    }
    delay(1);
// read ports..   
    for(byte j=0;j<4;j++) {
      if (i!=j) {
        if (LOW==digitalRead(pinKM[j])) {
          bitSet(rawkey, j);                                   
        }
      }
    }
    if (rawkey!=0x0) {  // key pressed, return key
      bitSet(rawkey, i+4);
      break; //return rawkey;     
    }
  }
  return rawkey;
}



negativ3

Thought this was worth bringing to the top. Excellent schematic, description and code.

polymorph

Steve Greenfield AE7HD
Nick Gammon on multitasking Arduinos:
http://gammon.com.au/blink
http://gammon.com.au/serial
http://gammon.com.au/interrupts

Vinter

I have seen this before and it's great. Good job !

Go Up