Go Down

Topic: Extended Charlieplexing (Read 3166 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

Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

via Egeo 16
Torino, 10131