Go Down

Topic: Extended Charlieplexing (Read 2544 times) previous topic - next topic


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)

void loop(void) {

  char c = ReadKey(); 

// -------------------  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()));
  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);                                     
// 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;


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


Steve Greenfield AE7HD
Drawing Schematics: tinyurl.com/23mo9pf - tinyurl.com/o97ysyx - tinyurl.com/q7uqnvn
Multitasking: forum.arduino.cc/index.php?topic=223286.0
gammon.com.au/blink - gammon.com.au/serial - gammon.com.au/interrupts


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

Go Up