Keyboard Matrix Control?

I am trying to connect my Arduino to a Bluetooth keyboard controller. I would like to use the Arduino to simulate the keypresses. This will allow me to pair the keyboard with my iPhone but send the keystroke from my desktop.

I attached connections to the 8 output and 12 input pins on the controller. With those I was able to map the matrix. Now I know which connection produce which keys.

The inputs are red, yellow and blue. From left to right they are I1-I12. The outputs are black. From left to right they are O1-O8. The A values are the pins I connected to on the Arduino

Keyboard Matrix;
A4
O1
I11 1 A5
I10 2 A6
I9 3 A7
I8 4 A8
I7 5 A9

Whe connecting any input with any output on the keyboard controller I get 3v. So I assume the controller pins default to HIGH and made my program default the pins to HIGH. If I11 and O1 are connected a 1 keystroke is produced. I connected O1 to pin 4 and I11 to pin 5. If I pull both pin A4 and A5 low then back to high again a 1 keystroke is produced. I got real excited and thought it was working. The next key I wanted was 2 which is produced by connecting I10 to O1. So I added a connection for I10 on pin 6 of the Aurdino. Now if I pull pin 4 and 6 low then high I expected the 2 keystroke. Instead I got 21. Pulling pin 4 & 6 or pin 4 & 5 low to high causes both keystrokes to be produced.

I am not sure what I am doing wrong or where the overlap is coming from?

void setup() {
  pinMode(4, OUTPUT);
  
  digitalWrite(4, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  Serial.begin(9600);
}

void loop() {

  if (Serial.available() > 0) {
    String chr = Serial.read();
    
    if (chr == "49"){
        Serial.println("1 keypress");
        togglePins(4,5);
        Serial.println("Pins toggled");
    }
    
    if (chr == "50"){
        Serial.println("2 keypress");
        togglePins(4,6);
        Serial.println("Pins toggled");
    }
    
    if (chr == "51"){
        Serial.println("3 keypress");
        togglePins(4,7);
        Serial.println("Pins toggled");
    }
  }
}

void togglePins(int pin1, int pin2){
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, LOW);
  delay(200);
  digitalWrite(pin1, HIGH);
  digitalWrite(pin2, HIGH);
}

Usually a keyboard matrix is scanned, like an LED matrix. The controller turns on (or off) each 'row' in turn and looks at the 'column' pins to see which one(s) have changed. You have to detect when each of the 'row' lines change and send outputs to the correct 'column' lines.

One way that might work is to put all the rows, except one, through an 'or' gate and use that to trigger an interrupt. Use the other row to trigger a different interrupt. That will give you a signal to reset the row counter and a signal to increment the row counter.

A logic analyzer (or at least a dual-trace oscilloscope) will help in figuring out which lines are the rows and which lines are the columns.

If you only need a few characters you might not need to decode all the rows and columns... You might be able to sit in a loop waiting for the row pin to change and then turn on the correct column pin. Depends on how fast the scanning is done. Hundreds of scans per second should be no problem but THOUSANDS of scans per second might be hard to catch.

EDIT:
Another choice would be multiplexors/selectors. You would have a 1-of-12-selector for the inputs and use four lines to select which row is being connected and send the output of that to a 1-to-8 multiplexer which uses three more data lines to select which output gets connected. When you select valid row and column addresses you will be pressing a key. You may need to use direct port manipulation to write all of the address pins together. If you change each pin one at a time you will likely end up with glitches unless you have an 'enable' pin you can turn off.

I already know which input pins and output pins need to be connected to produce which keys. Pulling 2 pins low produces keystrokes. The problem is that only works with a single input and output connected (like in the picture). If I connect more than 2 of the inputs or outputs any input and output pins pulled low will produce the keystrokes for all pins that are connected instead of just the pins that were pulled low. Changing the state of 1 input and output seems to affect all the keys.

Here is the complete keyboard matrix for alpha/numeric keys. Without a microcontroller if I connect pin 11 and 13 on the keyboard controller it outputs a 1 to the paired device. 10 and 13 output a 2 and so on. Is there are way to connect 2 pins on the Arduino? May read the output from pin1 and write it to pin2. That would make what I am tring to do work. Or a whole lot of switches. I just need to simulate the key on the keyboard connecting the circuits together. Maybe I don't need to connect to the output pins at all but instead emulate the signal on them and send it to the input pins?

The article below explains how a keyboard matrix works.

http://highlyliquid.com/support/library/scanned-matrix-keyboards/

And provides a link to an electronic device that emulates keypresses and sends them to the keyboard controller. Can't the Arduino be programmed to do the same thing?

http://highlyliquid.com/kits/umr/

nemesis43:
Can't the Arduino be programmed to do the same thing?

Yes, it can, and in my first reply I told you several ways you could do it.

You can just pulse the output pins, but you have to do it AT EXACTLY THE RIGHT TIME. The right time depends on when the correct input pin is being pulsed.

Three 4051 chips will do it. They each have three bits of address and a 'inhibit' input.

Connect the first two 4051 chips to the 12 'input' lines and the third to the 8 "output' lines.

Connect the COMMON of the first 4051 to the NO0 pin of the second 4051. Connect the 12 input data lines to any of the remaining 15 NO pins. Connect the COMMON of the second 4051 to the COMMON of the third 4051. Connect the eight NO pins of the third 4051 to the 8 'output' lines. Connect the nine address pins (three from each 4051) to data pins on the Arduino. Connect the INHIBIT line of the second or third 4051 (doesn't matter since they are in series) to another Arduino pin. BECAUSE THEY ARE CMOS CHIPS, CONNECT ANY UNUSED PINS TO GROUND (floating inputs can cause internal short-circuits).

Set the 9 address pins and pull the INHIBIT pin LOW to produce a keystroke.

John,

I can't thank you enough for helping me get the connections made. You have been a great help. I got everything wired up with all unused pins connected to ground. I am not sure if there is a problem with my physical connections or my code. Either way I am having some wierd issues. When I send a 1 or 2 keypress it works perfect. When I send a 3 keypress it acutally prints a single 2 chr. I

Is there something obviously wrong with my code? One thing for sure is pulling the common pin high doesn't disconnect all the input pins. I checked that with the ohm meter. I am not sure why that doesn't work but I had to set the input pin back to an unsed pin on the 4051 just to get it working.

All of the pin connections are documented in the code.

  ///////////////////////////////////////////////////////////////////////////
  //Verbatim Bluetooth Mobile Keyboard Arduino Controller                  //
  //Model     #:FDIK-BT                                                    //
  //Re-order  #:97537    //This number shows up in red on the barcode      //
  ///////////////////////////////////////////////////////////////////////////
  
  ////////4051 Arduino pin map//////////
  // 4051 Chip 1 pins  s0 4   s1 3  s2 2 //
  // 4051 Chip 2 pins  s0 7   s1 6  s2 5 //
  // 4051 Chip 3 pins  s0 10  s1 9  s2 8 //
  /////////////////////////////////////////

  //-Keyboard Map-----------------------------------------------------------
  //----------------------------------Output pins---------------------------							
  //	Pins	13	14	15	16	17	18	19	20
  //    1								
  //	2								
  //	3								
  //	4	0			Enter				
  //	5	9	-				L		P
  //	6	8		N			K		O
  //	7	7	6	B	M	H	J	Y	I
  //	8	4	5		V	G	F	T	U
  //	9	3			C		D		R
  //	10	2			X		S		E
  //	11	1			Z		A		W
  //	12								Q
  //-----------------------------------------------------------------------

  //The first deminsion array item numbers correspond with the keyboard matrix pins
  //The second demninsion array item number correspone with the truth tables state for the pins
  int pins[21][6] =  {
   {0, 0, 0, 0 ,0 ,0},  //leave empty so pin numbers match
   {0, 0, 0, 0 ,0 ,0},  //bt keyboard pin 1  unused        
   {0, 0, 0, 0 ,0 ,0},  //bt keyboard pin 2  unused
   {0, 0, 0, 0 ,0 ,0},  //bt keyboard pin 3  unused
   
   {4, 3, 2, 0 ,0 ,1},  //bt keyboard pin 4  on chip 1 pin y4
   {4, 3, 2, 1 ,0 ,1},  //bt keyboard pin 5  on chip 1 pin y5
   {4, 3, 2, 0 ,1 ,1},  //bt keyboard pin 6  on chip 1 pin y6
   {4, 3, 2, 1 ,1 ,1},  //bt keyboard pin 7  on chip 1 pin y7
   
   {7, 6, 5, 1 ,0 ,0},  //bt keyboard pin 8  on chip 2 pin y1
   {7, 6, 5, 0 ,1 ,0},  //bt keyboard pin 9  on chip 2 pin y2
   {7, 6, 5, 1 ,1 ,0},  //bt keyboard pin 10 on chip 2 pin y3
   {7, 6, 5, 0 ,0 ,1},  //bt keyboard pin 11 on chip 2 pin y4
   
   {0, 0, 0, 0 ,0 ,0},  //bt keyboard pin 12  unused
   
   {10, 9, 8, 0 ,0 ,0}, //bt keyboard pin 13 on chip 3 pin y0
   {10, 9, 8, 0 ,0 ,1}, //bt keyboard pin 14 on chip 3 pin y1
   {10, 9, 8, 0 ,1 ,0}, //bt keyboard pin 15 on chip 3 pin y2
   {10, 9, 8, 0 ,1 ,1}, //bt keyboard pin 16 on chip 3 pin y3
   {10, 9, 8, 1 ,0 ,0}, //bt keyboard pin 17 on chip 3 pin y4
   {10, 9, 8, 1 ,0 ,1}, //bt keyboard pin 18 on chip 3 pin y5
   {10, 9, 8, 1 ,1 ,0}, //bt keyboard pin 19 on chip 3 pin y6
   {10, 9, 8, 1 ,1 ,1}, //bt keyboard pin 20 on chip 3 pin y7
  }; 

  int opins[8] = {2, 3 , 4 , 5 , 6, 8, 9, 10};

  int pinh  = 11; //common input/output pin
  int Delay = 200; //seems to be the scan time for the keyboard controller
  
void setup(){
  Serial.begin(9600);
  
  //not sure if I need these to be outputs
  //change later just to see what happens
  for (int i = 0; i < 8; i++){
    Serial.println(opins[i]);
    pinMode(opins[i], OUTPUT);
    digitalWrite(opins[i], LOW);
  }
  
  //common I/O pin
  pinMode(pinh, OUTPUT);
  digitalWrite(pinh, HIGH);
}

void loop () {
  
    if (Serial.available() > 0) {
      String chr = Serial.read(); 

      if (chr == "48"){
          Serial.println("0"); keyPress(4,13);
      }
      
      if (chr == "49"){
          Serial.println("1"); keyPress(11,13);
      }
      
      if (chr == "50"){
          Serial.println("2"); keyPress(10,13);
      }
      
      if (chr == "51"){
          Serial.println("3"); keyPress(9,13);
      }
      
      if (chr == "52"){
          Serial.println("4"); keyPress(8,13);
      }
      
      if (chr == "53"){
          Serial.println("5"); keyPress(8,14);
      }
      
      if (chr == "54"){
          Serial.println("6"); keyPress(7,14);
      }
      
      if (chr == "55"){
          Serial.println("7"); keyPress(7,13);
      }
      
      if (chr == "56"){
          Serial.println("8"); keyPress(6,13);
      }
    
      if (chr == "57"){
          Serial.println("9"); keyPress(5,13);
      }
  }
}


void keyPress(int inputPin, int outputPin){
  
    Serial.print("Input  Pin: ");
    Serial.print(pins[inputPin][0]);  Serial.print(pins[inputPin][1]); Serial.print(pins[inputPin][2]);
    Serial.print(pins[inputPin][3]);  Serial.print(pins[inputPin][4]); Serial.println(pins[inputPin][5]);
    
    Serial.print("Output Pin: ");
    Serial.print(pins[outputPin][0]); Serial.print(pins[outputPin][1]); Serial.print(pins[outputPin][2]);
    Serial.print(pins[outputPin][3]); Serial.print(pins[outputPin][4]); Serial.println(pins[outputPin][5]);
 
     //set the input pin of the keyboard controller
    digitalWrite(pins[inputPin][0], pins[inputPin][3]);
    digitalWrite(pins[inputPin][1], pins[inputPin][4]);
    digitalWrite(pins[inputPin][2], pins[inputPin][5]);
    
    //set the output pin of the keyboard controller
    digitalWrite(pins[outputPin][0], pins[outputPin][3]);
    digitalWrite(pins[outputPin][1], pins[outputPin][4]);
    digitalWrite(pins[outputPin][2], pins[outputPin][5]);
    
    //pull the common I/O pin low to connect the input and output pins
    digitalWrite(pinh, LOW);
    delay(Delay); //wait for all pins to be scanned
    digitalWrite(pinh, HIGH);
    
    //set the keyboard input pin to y0 on the 4051
    //y0 has to be an unsed grounded input pin on the 4051
    //seems like I shouldn't have to do this but it doesn't work without it
    //setting the common pin high should disconnect all the input pins but it doesn't
    digitalWrite(pins[inputPin][0], 0);
    digitalWrite(pins[inputPin][1], 0);
    digitalWrite(pins[inputPin][2], 0);
}

Got it working!!! Thanks a million johnwasser :grin:

I missed setting the 7 pin as on output and was using the common as the INHIBIT. I fixed those then it started working. Just had to fix a few issue with the keyboard map that I had wrong and everything is right with my project now. Updated code is below.

  ///////////////////////////////////////////////////////////////////////////
  //Verbatim Bluetooth Mobile Keyboard Arduino Controller                  //
  //Model     #:FDIK-BT                                                    //
  //Re-order  #:97537    //This number shows up in red on the barcode      //
  ///////////////////////////////////////////////////////////////////////////
  
  ////////4051 Arduino pin map//////////
  // 4051 Chip 1 pins  s0 4   s1 3  s2 2 //
  // 4051 Chip 2 pins  s0 7   s1 6  s2 5 //
  // 4051 Chip 3 pins  s0 10  s1 9  s2 8 //
  /////////////////////////////////////////

  //-Keyboard Map-----------------------------------------------------------
  //----------------------------------Output pins---------------------------							
  //	Pins	13	14	15	16	17	18	19	20
  //    1								
  //	2								
  //	3								
  //	4	0	-		Enter				p
  //	5	9		\		 	L		o
  //	6	8		/		'	K		i
  //	7	7	6	n	M	h	J	Y	u
  //	8	4	5	b	V	g	F	T	r
  //	9	3			C		D		e
  //	10	2			X		S		w
  //	11	1			Z		A		q
  //	12								
  //-----------------------------------------------------------------------

  //The first deminsion array item numbers correspond with the keyboard matrix pins
  //The second demninsion array item number correspond with the truth tables state for the pins
  int pins[21][6] =  {
   {0, 0, 0, 0 ,0 ,0},  //leave empty so pin numbers match
   {0, 0, 0, 0 ,0 ,0},  //bt keyboard pin 1  unused        
   {0, 0, 0, 0 ,0 ,0},  //bt keyboard pin 2  unused
   {0, 0, 0, 0 ,0 ,0},  //bt keyboard pin 3  unused

   {4, 3, 2, 0 ,0 ,1},  //bt keyboard pin 4  on chip 1 pin y4
   {4, 3, 2, 1 ,0 ,1},  //bt keyboard pin 5  on chip 1 pin y5
   {4, 3, 2, 0 ,1 ,1},  //bt keyboard pin 6  on chip 1 pin y6
   {4, 3, 2, 1 ,1 ,1},  //bt keyboard pin 7  on chip 1 pin y7

   {7, 6, 5, 0 ,1 ,0},  //bt keyboard pin 8  on chip 2 pin y2
   {7, 6, 5, 1 ,1 ,0},  //bt keyboard pin 9  on chip 2 pin y3
   {7, 6, 5, 0 ,0 ,1},  //bt keyboard pin 10 on chip 2 pin y4
   {7, 6, 5, 1 ,0 ,1},  //bt keyboard pin 11 on chip 2 pin y5
   
   {0, 0, 0, 0 ,0 ,0},  //bt keyboard pin 12  unused
   
   {10, 9, 8, 0 ,0 ,0}, //bt keyboard pin 13 on chip 3 pin y0
   {10, 9, 8, 1 ,0 ,0}, //bt keyboard pin 14 on chip 3 pin y1
   {10, 9, 8, 0 ,1 ,0}, //bt keyboard pin 15 on chip 3 pin y2
   {10, 9, 8, 1 ,1 ,0}, //bt keyboard pin 16 on chip 3 pin y3
   {10, 9, 8, 0 ,0 ,1}, //bt keyboard pin 17 on chip 3 pin y4
   {10, 9, 8, 1 ,0 ,1}, //bt keyboard pin 18 on chip 3 pin y5
   {10, 9, 8, 0 ,1 ,1}, //bt keyboard pin 19 on chip 3 pin y6
   {10, 9, 8, 1 ,1 ,1}, //bt keyboard pin 20 on chip 3 pin y7
  }; 

  int opins[10] = {2, 3 , 4 , 5 , 6, 7, 8, 9, 10,11};

  int pinh  = 11; //common input/output pin
  int Delay = 35; //seems to be the scan time for the keyboard controller
  
void setup(){
  Serial.begin(9600);
  
  for (int i = 0; i < 10; i++){
    pinMode(opins[i], OUTPUT);
  }
  
  digitalWrite(pinh, HIGH);
}

void loop () {

    if (Serial.available() > 0) {
      String chr = Serial.read(); 
      
      //Enter and Dash key press
      if (chr == "69"){Serial.println("E"); keyPress(4,16);}
      if (chr == "45"){Serial.println("-"); keyPress(4,14);}
      
      //0-9 key press
      if (chr == "48"){Serial.println("0"); keyPress(4,13);}
      if (chr == "49"){Serial.println("1"); keyPress(11,13);}
      if (chr == "50"){Serial.println("2"); keyPress(10,13);}
      if (chr == "51"){Serial.println("3"); keyPress(9,13);}
      if (chr == "52"){Serial.println("4"); keyPress(8,13);}
      if (chr == "53"){Serial.println("5"); keyPress(8,14);}
      if (chr == "54"){Serial.println("6"); keyPress(7,14);}
      if (chr == "55"){Serial.println("7"); keyPress(7,13);}
      if (chr == "56"){Serial.println("8"); keyPress(6,13);}
      if (chr == "57"){Serial.println("9"); keyPress(5,13);}
      
      //a-z key press
      if (chr == "97"){Serial.println("a"); keyPress(11,18);}
      if (chr == "98"){Serial.println("b"); keyPress(8,15);}
      if (chr == "99"){Serial.println("c"); keyPress(9,16);}
      if (chr == "100"){Serial.println("d"); keyPress(9,18);}
      if (chr == "101"){Serial.println("e"); keyPress(9,20);}
      if (chr == "102"){Serial.println("f"); keyPress(8,18);}
      if (chr == "103"){Serial.println("g"); keyPress(8,17);}
      if (chr == "104"){Serial.println("h"); keyPress(7,17);}
      if (chr == "105"){Serial.println("i"); keyPress(6,20);}
      if (chr == "106"){Serial.println("j"); keyPress(7,18);}
      if (chr == "107"){Serial.println("k"); keyPress(6,18);}
      if (chr == "108"){Serial.println("l"); keyPress(5,18);}
      if (chr == "109"){Serial.println("m"); keyPress(7,16);}
      if (chr == "110"){Serial.println("n"); keyPress(7,15);}
      if (chr == "111"){Serial.println("o"); keyPress(5,20);}
      if (chr == "112"){Serial.println("p"); keyPress(4,20);}
      if (chr == "113"){Serial.println("q"); keyPress(11,20);}
      if (chr == "114"){Serial.println("r"); keyPress(8,20);}
      if (chr == "115"){Serial.println("s"); keyPress(10,18);}
      if (chr == "116"){Serial.println("t"); keyPress(8,19);}
      if (chr == "117"){Serial.println("u"); keyPress(7,20);}
      if (chr == "118"){Serial.println("v"); keyPress(8,16);}
      if (chr == "119"){Serial.println("w"); keyPress(10,20);}
      if (chr == "120"){Serial.println("x"); keyPress(10,16);}
      if (chr == "121"){Serial.println("y"); keyPress(7,19);}
      if (chr == "122"){Serial.println("z"); keyPress(11,16);}
  }
}


void keyPress(int inputPin, int outputPin){
  
//    //enable for debugging~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//    Serial.print("Input  Pin: ");
//    Serial.print(pins[inputPin][0]);  Serial.print(pins[inputPin][1]); Serial.print(pins[inputPin][2]);
//    Serial.print(pins[inputPin][3]);  Serial.print(pins[inputPin][4]); Serial.println(pins[inputPin][5]);
//    
//    Serial.print("Output Pin: ");
//    Serial.print(pins[outputPin][0]); Serial.print(pins[outputPin][1]); Serial.print(pins[outputPin][2]);
//    Serial.print(pins[outputPin][3]); Serial.print(pins[outputPin][4]); Serial.println(pins[outputPin][5]);
//    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //set the output pin of the keyboard controller
    digitalWrite(pins[outputPin][0], pins[outputPin][3]);
    digitalWrite(pins[outputPin][1], pins[outputPin][4]);
    digitalWrite(pins[outputPin][2], pins[outputPin][5]);
    
    //Serial.println("");
    
     //set the input pin of the keyboard controller
    digitalWrite(pins[inputPin][0], pins[inputPin][3]);
    digitalWrite(pins[inputPin][1], pins[inputPin][4]);
    digitalWrite(pins[inputPin][2], pins[inputPin][5]);
    
    //Chip 1 common connects to chip 2 y0
    //to use chip 1 chip 2 has to be set to pin y0
    //probably a better way to manage this but it works for now
    if(inputPin >=4 && inputPin <=7){
      //Serial.println("Chip 1 keypress");
      //Serial.println("Setting Chip2 to y0");
      digitalWrite(7,0);
      digitalWrite(6,0);
      digitalWrite(5,0);
    }
    
//    //enable for debugging~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//    int val = 0;
//    Serial.print("Input Pins: ");
//    val = digitalRead(pins[inputPin][0]); Serial.print(val);
//    val = digitalRead(pins[inputPin][1]); Serial.print(val);
//    val = digitalRead(pins[inputPin][2]); Serial.println(val);
//    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //pull the common I/O pin low to connect the input and output pins
    digitalWrite(pinh, LOW);
    delay(Delay); 
    digitalWrite(pinh, HIGH);
    
//    //enable for debugging~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//    Serial.print("Input Pins: ");
//    val = digitalRead(pins[inputPin][0]); Serial.print(val);
//    val = digitalRead(pins[inputPin][1]); Serial.print(val);
//    val = digitalRead(pins[inputPin][2]); Serial.println(val);
//    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}

Hi Guys, i'm working on a very similar project where I am getting the arduino to simulate keypresses on the casio synth.

http://createrevolutionaryart.net/sa-10-teardown/

The SA-10 uses the same matrix scanning to get input. Would you be able to post a photo or a rough schematic of how you made use of the 4051 chips? My plan is to make a MIDI interface so a sequencer or computer can be used to play this synth.

Very interesting reading your posts so far.

Rob