[Solved] Matrix keypad emulation with CD4051BE

Anyways, until that gets sorted out, here is my code so far. I am not sure how to convert the binary number to individual pin outputs (my questions are located in the comments in the "pressKey" function.

#define INH 2

#define A_1 3
#define B_1 4
#define C_1 5

#define A_2 6
#define B_2 7
#define C_2 8

byte keys[34] = {      //0b00A1B1C1A2B2C2
  0b00100000 /* PF  */ , //0
  0b00010000 /* %-  */ , //1
  0b00110000 /* VD  */ , //2
  0b00001000 /* PLU */ , //3
  0b00101000 /* OFF */ , //4
  0b00011000 /* %+  */ , //5
  0b00100100 /* C   */ , //6
  0b00010100 /* PLC */ , //7
  0b00110100 /* PRC */ , //8
  0b00001100 /* STL */ , //9
  0b00101100 /* PY  */ , //10
  0b00011100 /* X   */ , //11
  0b00100010 /* 7   */ , //12
  0b00010010 /* 4   */ , //13
  0b00110010 /* 1   */ , //14
  0b00001010 /* 00  */ , //15
  0b00101010 /* 8   */ , //16
  0b00011010 /* 5   */ , //17
  0b00100110 /* 2   */ , //18
  0b00010110 /* 0   */ , //19
  0b00110110 /* 9   */ , //20
  0b00001110 /* 6   */ , //21
  0b00101110 /* 3   */ , //22
  0b00011110 /* .   */ , //23
  0b00111101 /* ON  */ , //24
  0b00010001 /* DP1 */ , //25
  0b00110001 /* DP2 */ , //26
  0b00001001 /* DP4 */ , //27
  0b00101001 /* TL  */ , //28
  0b00011001 /* DP3 */ , //29
  0b00000001 /* DP5 */ , //30
  0b00000110 /* DP6 */ , //31
  0b00000010 /* DP7 */ , //32
};


void setup() {

  pinMode( INH, INPUT ) ;  // sets inhibit pin to high impedance
  // declaring A B C select pins on the first chip as output here :
  pinMode( A_1, OUTPUT ) ;
  pinMode( B_1, OUTPUT ) ;
  pinMode( C_1, OUTPUT ) ;
  // declaring A B C select pins on the second chip as output here :
  pinMode( A_2, OUTPUT ) ;
  pinMode( B_2, OUTPUT ) ;
  pinMode( C_2, OUTPUT ) ;

  /*
    // PF Key A1B1C1A2B2C2: 100000
    // CD4051 #1
    digitalWrite( A_1 , 0  ) ;
    digitalWrite( B_1 , 0  ) ;
    digitalWrite( C_1 , 0 ) ;

    // CD4051 #2
    digitalWrite( A_2 , 0  ) ;
    digitalWrite( B_2 , 0  ) ;
    digitalWrite( C_2 , 0  ) ;

    pinMode( INH, OUTPUT ) ;  // inhibit
    digitalWrite( INH , LOW  ) ; // enable
    delay(100) ;  // simulate a keypress for 100ms
    pinMode( INH, INPUT ) ;  // sets inhibit to high impedance
  */



}

void loop() {
  pressKey(keys[0], 100); //PF for 100ms, will send "0b00100000" as keyIndex and "100" as pressTime to pressKey()
}

void pressKey(int keyIndex, int pressTime) {
  //in this attempt, the key to press is PF, or 0b00100000
  //how do I convert 0b00100000 to the individual pin outputs?
  //so how do I make it look at the farthest-right digit and set the pin to that and so on (in this case 0)?

  pinMode( INH, OUTPUT ) ;  // inhibit
  digitalWrite( INH , LOW  ) ; // enable
  delay(pressTime) ;  // simulate a keypress for pressTime ms
  pinMode( INH, INPUT ) ;  // sets inhibit to high impedance
}

I have found out about the existence of "bitRead()" to get each digit of my binary number, so I will try writing code using it and I will post here if I have any more questions.

I am still wondering what is up with the behavior mentioned in reply #39, though.

The behaviour does sound odd. How did you come to the conclusion that pin 14 on the connector is GND ? Maybe that has to be checked again.

Here is an example of the code for picking bits out of a byte:

void loop() {
  pressKey(keys[0], 100); //PF for 100ms, will send "0b00100000" as keyIndex and "100" as pressTime to pressKey()
  
  // maybe a long delay here otherwise the key will be continually pressed and released.
}

void pressKey(int keyIndex, int pressTime) {
  //in this attempt, the key to press is PF, or 0b00100000
  //how do I convert 0b00100000 to the individual pin outputs?
  //so how do I make it look at the farthest-right digit and set the pin to that and so on (in this case 0)?

  pinMode( INH, OUTPUT ) ;  // inhibit
  digitalWrite( INH , LOW  ) ; // enable
  
  // bitRead() : bit 7 is far left. bit 0 is far right
  digitalWrite(  A_1 , bitRead( keys[ kexIndex] , 5 )  ) ;
  digitalWrite(  B_1 , bitRead( keys[ kexIndex] , 4 )  ) ;
  . . .
  . . .
  
  
  delay(pressTime) ;  // simulate a keypress for pressTime ms
  pinMode( INH, INPUT ) ;  // sets inhibit to high impedance
}

Thanks.

I came to the conclusion that pin 14 is GND because my multimeter beepd and showed "0" when testing continuity between it and a known ground on the motherboard.

Anyways, this is how I completed my code (which currently works):

#define INH 2

#define A_1 3
#define B_1 4
#define C_1 5

#define A_2 6
#define B_2 7
#define C_2 8

#define afterPress 50

byte keys[34] = {      //0b00A1B1C1A2B2C2
  0b00100000 /* PF  */ , //0
  0b00010000 /* %-  */ , //1
  0b00110000 /* VD  */ , //2
  0b00001000 /* PLU */ , //3
  0b00101000 /* OFF */ , //4
  0b00011000 /* %+  */ , //5
  0b00100100 /* C   */ , //6
  0b00010100 /* PLC */ , //7
  0b00110100 /* PRC */ , //8
  0b00001100 /* STL */ , //9
  0b00101100 /* PY  */ , //10
  0b00011100 /* X   */ , //11
  0b00100010 /* 7   */ , //12
  0b00010010 /* 4   */ , //13
  0b00110010 /* 1   */ , //14
  0b00001010 /* 00  */ , //15
  0b00101010 /* 8   */ , //16
  0b00011010 /* 5   */ , //17
  0b00100110 /* 2   */ , //18
  0b00010110 /* 0   */ , //19
  0b00110110 /* 9   */ , //20
  0b00001110 /* 6   */ , //21
  0b00101110 /* 3   */ , //22
  0b00011110 /* .   */ , //23
  0b00111101 /* ON  */ , //24 WE DON'T TALK ABOUT THIS BUTTON :)
  0b00010001 /* DP1 */ , //25
  0b00110001 /* DP2 */ , //26
  0b00001001 /* DP4 */ , //27
  0b00101001 /* TL  */ , //28
  0b00011001 /* DP3 */ , //29
  0b00000001 /* DP5 */ , //30
  0b00000110 /* DP6 */ , //31
  0b00000010 /* DP7 */ , //32
};


void setup() {

  pinMode( INH, INPUT ) ;  // sets inhibit pin to high impedance
  // declaring A B C select pins on the first chip as output here :
  pinMode( A_1, OUTPUT ) ;
  pinMode( B_1, OUTPUT ) ;
  pinMode( C_1, OUTPUT ) ;
  // declaring A B C select pins on the second chip as output here :
  pinMode( A_2, OUTPUT ) ;
  pinMode( B_2, OUTPUT ) ;
  pinMode( C_2, OUTPUT ) ;

//go into programming menu, enter password "30" and then quit back to main menu
  pressKey(keys[13], 100); //4
  delay(afterPress);
  pressKey(keys[14], 100); //1
  delay(afterPress);
  pressKey(keys[22], 100); //3
  delay(afterPress);
  pressKey(keys[19], 100); //0
  delay(afterPress);
  pressKey(keys[28], 100); //TL (total)
  delay(afterPress);
  pressKey(keys[4], 100); //OFF
}

void loop() {

}

void pressKey(int keyIndex, int pressTime) {
  int bitA_1 = bitRead(keyIndex, 5);
  int bitB_1 = bitRead(keyIndex, 4);
  int bitC_1 = bitRead(keyIndex, 3);

  int bitA_2 = bitRead(keyIndex, 2);
  int bitB_2 = bitRead(keyIndex, 1);
  int bitC_2 = bitRead(keyIndex, 0);

  // CD4051 #1
  digitalWrite( A_1 , bitA_1  ) ;
  digitalWrite( B_1 , bitB_1  ) ;
  digitalWrite( C_1 , bitC_1  ) ;

  // CD4051 #2
  digitalWrite( A_2 , bitA_2  ) ;
  digitalWrite( B_2 , bitB_2  ) ;
  digitalWrite( C_2 , bitC_2  ) ;

  pinMode( INH, OUTPUT ) ;  // inhibit
  digitalWrite( INH , LOW  ) ; // enable
  delay(pressTime) ;  // simulate a keypress for pressTime ms
  pinMode( INH, INPUT ) ;  // sets inhibit to high impedance
}

Again, thanks to everyone who pointed me into the right direction, but major thanks to 6v6gt who helped me complete my project.

EDIT: Disregard, reply #39, the strange behavior was solved by disconnecting the pesky ON button from the CD4051 altogether and now I can manually press buttons again with the Arduino connected. I knew the ON button would be a problem, but it really doesn't matter as I don't need it to be operated by the Arduino.

CrossRoads:
When you have that worked out, then you could perhaps have a solution where one CD4051 connects to up to 8 wires, and another CD4051 connects to up to 8 other wires.

Basically what i was saying in the second paragraph of #4. :grinning:

What is all this talk about connecting pins to ground? :roll_eyes:

This is a stock standard matrix keyboard. Pressing a key (with the apparent exception of the "On" key) connects a "row" connection to a "column" connection - nothing to do with connecting things to ground. The internal keyboard program pulls one row low after another and sees which column is pulled down as a result. Of course it may work the other way round with rows and columns and it may be pulling high, not low.

To emulate a key, you must do as the physical key does, connect one row to one column as illustrated in $19.

Obviously the "on" key is separate and different because it simply switches the power logic.

1 Like