Switch matrix input

I have an M-Audio 25 key midi controller that I wanted to use as an input device for my Arduino. The keyboard is actually a 8x8 matrix with each key cosponsoring to 2 switches, so the keyboard actually functions as a 8x4 matrix. After a bit of time with the keyboard and my multimeter, bread board, the midi table at midi.org and the midi out article at ITP I managed to put together the following code to make a simple Arduino based midi controller (complete with ridiculously neat syntax):

[ch65279]//***********************************************************************************************//
//                                                                                               //
//  Name    : Matrix MIDI Keyboard                                                               //
//  Author  : Inky the Hooloovoo                                                                 //
//  Version : 1.1                                                                                //
//  Notes   : Code to use a 8 x 4 switch matrix keyboard as input for an Arduino board           //
//                                                                                               //
//***********************************************************************************************//

//=================================================================================================
                                                                                                 //
int HotPin[8] = {2,3,4,5,6,7,8,9}; //Hot (output) pins                                           //
int GndPin[4] = {10,11,12,13}; //Ground (input) pins                                             //
int OldKeyPress[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};           //
int NewKeyPress[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};           //
int KeyNum = 1; //Identifies the key being read                                                  //
int MidiNote = 60; //The MIDI note to be played (Middle C is 60)                                 //
                                                                                                 //
//=================================================================================================
void setup()                                                                                     //
{                                                                                                //
  Serial.begin(31250); //Start transmiting serial data for MIDI                                  //
  for (int i=0; i <= 3; i++)                                                                     //
  {                                                                                              //
    pinMode(HotPin[i], OUTPUT);   //Set pins 2 through 5 as output pins                          //
    pinMode(HotPin[i+4], OUTPUT); //Set pins 6 through 9 as output pins                          //
    pinMode(GndPin[i], INPUT);    //Set pins 10 through 13 as input pins                         //
  }                                                                                              //
}                                                                                                //
//=================================================================================================
void loop()                                                                                      //
{                                                                                                //
  for (int h=0; h <= 7; h++)                                                                     //
  {                                                                                              //
    digitalWrite(HotPin[h], HIGH);                                                               //
    {                                                                                            //
      for (int g=0; g <=3; g++)                                                                  //
      {                                                                                          //
        KeyNum = (g * 8) + h; //Sets KeyNum to a value from 0 to 31 (C1 is 04)                   //
        NewKeyPress[KeyNum] = digitalRead(GndPin[g]); //Find out if the key if pressed           //
        MidiNote = KeyNum + 56; //Makes C1 on the keyboard middle C                              //
        if (NewKeyPress[KeyNum] == 1 && OldKeyPress[KeyNum] == 0) //If key is pressed            //
        {                                                                                        //
          MidiMessage(0x90, MidiNote, 0x70); //note on, channel 1                                //
        }                                                                                        //
        else if (NewKeyPress[KeyNum] == 0 && OldKeyPress[KeyNum] == 1) //If key is released      //
        {                                                                                        //
          MidiMessage(0x80, MidiNote, 0x70); //note off, channel 1                               //
        }                                                                                        //
        OldKeyPress[KeyNum] = NewKeyPress[KeyNum] //Set state for next check                     //
      }                                                                                          //
    }                                                                                            //
  }                                                                                              //
}                                                                                                //
//=================================================================================================
void MidiMessage(char cmd, char data1, char data2)                                               //
{                                                                                                //
  Serial.print(cmd, BYTE);                                                                       //
  Serial.print(data1, BYTE);                                                                     //
  Serial.print(data2, BYTE);                                                                     //
}                                                                                                //
//=================================================================================================

I'll try to make a schematic when I get the chance. This code also has a major draw back in the fact that it uses up almost all of the digital i/o pins so I'll also be trying to incorporate 74HC595 and/or CD4021BE into the circuit to free up some of the pins for other uses.

You might want to have a look at the chips by E-Lab ( www.elabinc.com ); a couple of them are matrix keyboard encoders - one is for 4x4, the other does up to 8x8, and both chips output serial data (and an "I've got something!" signal :slight_smile: ). Once you code your Arduino and unhook it, the serial I/O frees up to use with the E-Lab chip(s).

Thanks, that would make using a matrix in the future a lot easier, I'll look into it a bit more. Only problem is that they don't appear to work at the 31250 baud rate that midi uses, but its still worth looking into.

Hey all, first post here =]

I'm attempting something very similar to this, with a 6x6 input from an old Casio keyboard.

At the moment I have it correctly identifying when a switch has been pressed, and sending the correct output. However, once a button has been pressed, pressing that button again, or the same position in a different "array" of buttons fails to register an event. I'm using slightly modified code to allow me to read from analogue inputs (as I'm getting some slightly off perfact values, and the board that connects in has pins placed over the Analogue inputs). The code is shown below, I wondered if anyone could help?

int HotPin[6] = {2,3,4,5,6,7}; //Hot (output) pins                                             //
int GndPin[6] = {0,1,2,3,4,5}; //Ground (input) pins                                             //
int OldKeyPress[36] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};           //
int NewKeyPress[36] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};           //
int KeyNum = 1; //Identifies the key being read                                                  //
int MidiNote = 60; //The MIDI note to be played (Middle C is 60)                                 //

void setup()                                                                                     
{                                                                                                
Serial.begin(31250);
    pinMode(2, OUTPUT);  
    pinMode(3, OUTPUT);
    pinMode(4, OUTPUT);
    pinMode(5, OUTPUT);
    pinMode(6, OUTPUT);
    pinMode(7, OUTPUT); 
}                                                                                                

void loop()                                                                                      
{                                                                                                
  for (int h=0; h <= 5; h++)                                                                     
  {                                                                                              
    digitalWrite(HotPin[h], HIGH);                                                               
    {                                                                                            
      for (int g=0; g <=5; g++)                                                                 
      {                                                                                        
        KeyNum = (g * 6) + h; //Sets KeyNum to a value from 0 to 31 (C1 is 04)
        if(analogRead(GndPin[g]) >= 600){
        NewKeyPress[KeyNum] = 1;
        }
        //Find out if the key if pressed           
        MidiNote = KeyNum + 56; //Makes C1 on the keyboard middle C                              
        if (NewKeyPress[KeyNum] == 1 && OldKeyPress[KeyNum] == 0) //If key is pressed           
        {                                                                                       
          MidiMessage(0x90, MidiNote, 0x70); //note on, channel 1                               
        }                                                                                        
        else if (NewKeyPress[KeyNum] == 0 && OldKeyPress[KeyNum] == 1) //If key is released      
        {                                                                                        
          MidiMessage(0x80, MidiNote, 0x70); //note off, channel 1                               
        }                                                                                        
        OldKeyPress[KeyNum] = NewKeyPress[KeyNum]; //Set state for next check                     
      }                                                                                          
    }                                                                                            
  }                                                                                              
}                                                                                                
//=================================================================================================
void MidiMessage(char cmd, char data1, char data2)                                               //
{                                                                                                //
  Serial.print(cmd, BYTE);                                                                       //
  Serial.print(data1, BYTE);                                                                     //
  Serial.print(data2, BYTE);                                                                     //
}                                                                                                //
//=================================================================================================

Any thoughts? Bumping as I edited rather than replied so people might have missed it - Sorry

I think I know the problem. You have the test to see if the key is pressed, but never to see if the key is let go. Add in an "else if" statement to check if the key has been released. Should look like this:

if (analogRead(GndPin[g]) >= 600)
{
  NewKeyPress[KeyNum] = 1;
}
else if (analogRead(GndPin[g]) < 600)
{
  NewKeyPress[KeyNum] = 0;
}

I hope this all works for you, but let me know if you need any more help.

Cheers that got that - I always forget something when I'm modifying code :stuck_out_tongue:

now I have the problem that pressing one button registers the same "horizontal" buttons as being pressed. Any ideas? Or could it just be my horrendous soldering.

You don't need all that:-
else if (analogRead(GndPin[g]) < 600)
you just need
else
Because if the first test is not over 600 then the second test is redundant it IS less than 600.

No worries, I had that problem when I first wrote that program so I knew just where to look. Grumpy_Mike also raises a good point. Here's what the loop() part of the program should look like (changes have been highlighted):

void loop()                                                                                      
{                                                                                                
  for (int h=0; h <= 5; h++)                                                                    
  {                                                                                              
    digitalWrite(HotPin[h], HIGH);                                                              
    {                                                                                            
      for (int g=0; g <=5; g++)                                                                
      {                                                                                        
        KeyNum = (g * 6) + h; //Sets KeyNum to a value from 0 to 31 (C1 is 04)
        if(analogRead(GndPin[g]) >= 600)
       {
          NewKeyPress[KeyNum] = 1;
        }
        [glow]else[/glow]
        {
          NewKeyPress[KeyNum] = 0;
        }
        //Find out if the key if pressed          
        MidiNote = KeyNum + 56; //Makes C1 on the keyboard middle C                              
        if (NewKeyPress[KeyNum] == 1 && OldKeyPress[KeyNum] == 0) //If key is pressed          
        {                                                                                      
          MidiMessage(0x90, MidiNote, 0x70); //note on, channel 1                              
        }                                                                                        
        else if (NewKeyPress[KeyNum] == 0 && OldKeyPress[KeyNum] == 1) //If key is released      
        {                                                                                        
          MidiMessage(0x80, MidiNote, 0x70); //note off, channel 1                              
        }                                                                                        
        OldKeyPress[KeyNum] = NewKeyPress[KeyNum]; //Set state for next check                    
      }                                                                                          
    }
    [glow]digitalWrite(HotPin[h], LOW); [/glow]                                                                                           
  }                                                                                              
}

Excellent! It's working perfectly now, I'll get a youtube video uploaded some time tommorow if anyone's interested.

One small glitch I'm having (thought this might be with the S2MIDI software) is that the computer is not responding to note releases, just presses. If I look at the HEX data it's certainly receiving these fron the arduino, and if I click stop on the S2MIDI program the note is released. Any ideas?

Edit: Just noticed S2MIDI doesn't support note off. I'll try and modify the code for this sometime today.

For anyone who is interested, I've modified the original S2MIDI program so it now registers Note off events. You can download the modified version from:
http://jiminizer.com/S2MIDI.exe

While we're on the subject of expressing if/else conditions simply, these four techniques are identical:

if (analogRead(GndPin[g]) >= 600)
{
    NewKeyPress[KeyNum] = 1;
}
else if (analogRead(GndPin[g]) < 600)
{
    NewKeyPress[KeyNum] = 0;
}
if (analogRead(GndPin[g]) >= 600)
{
    NewKeyPress[KeyNum] = 1;
}
else [glow] [/glow]
{
    NewKeyPress[KeyNum] = 0;
}

The ternary operator, or A?B:C operator works like this: if expression A is true, then use value B otherwise use value C.

NewKeyPress[KeyNum] = [glow](analogRead(GndPin[g]) >= 600)? 1 : 0;[/glow]

The (A>B) expression (and any other relational operator) produces an answer of 1 for true, and 0 for false already. So you don't even need the ternary operator. Just use the true/false answer directly.

NewKeyPress[KeyNum] = [glow](analogRead(GndPin[g]) >= 600)[/glow];