Scanning Piano Keyboard Matrix Questions

Hi new forum member here! =)

I have an old and broken 61-keys Yamaha (PSR-300) keyboard. I am planning to revive this keyboard and use it as a serial MIDI controller. I separated the circuits leaving only the actual key "board" matrix that has 12 rows (select) and 11 columns (data). What I planned to do to know which keys are pressed is to use serial-to-parallel shift registers to scan the 12 rows (by "interrogating" each rows) and detect the resulting data of the 11 columns by using parallel-to-serial shift registers. For each key, it has 2 switches to determine its velocity that's why it is a 12x11 matrix instead of 11x6 (or whatever xD).

I already have my untested code (with velocity functionality in mind) and I can't test it now because I'm waiting for myself to have the effort to buy (no near electronics store in our place) the shift registers.

Do you think Arduino can detect all of those keys in time, no sweat? Do you have any suggestions, comments?

Also, is is worth the effort to add note off velocity?

Oh sorry for my poor grammar. Not my native language. I would also be happy if you correct my grammar mistakes. =)

this sounds like a fun project! a few comments:

  1. the arduino can probably do the task, but won't have time to do anything else, especially once you put the midi code in.

  2. you might want to use a "4 to 16 decoder" (or 2 x "3 to 8 decoder") instead of shift registers. these will be fastser, and give better timing information. the fastest way to do it is to use the decoder chip to pull one of the columns high, and then connect all 12 of the row pins back to indivdual inputs on the microcontroller, and read them back in. here is an example of it:

  1. doing note-off velocity won't take that much more time, so its probably worth doing.

if you want to learn more about matrix scanning, here is a writeup:

I already have 4-to-16 decoder but never thought it's okay to use it instead. Hahahaha! But this will use 4 pins but i think that's okay. If I will ever need to reclaim a pin then maybe I will use a 4 bit shift register (yeah I'm addicted to shift registers) to control the decoder. That would be much faster than controlling two 8-bit shift registers!!! Now I'm thinking like an engineer thanks to you!

But I don't like the idea of having 11 column pins connected to Arduino because I am also planning to use additional pins for let's say base key adjustment or split key settings (for example, first octave to midi channel 1 and remaining keys to channel 2) and some wheel modulation and pitch bend control (just like a real MIDI controller) or it's just my uncontrollable urge to use as less pins as possible and driving the arduino to its fullest potential (yeah -_-).

I tried to search Google for the "opposite" of the 4-to-16 decoder but failed. Is there really any opposite of that or similar chip? If none, I will just use input shift registers.

Adding simple synthesizer into it is in my features list too! So it would be great if all the analog pins are to be conserved. (again my uncontrollable urge to save pins)

I have so many dreams eh?

Thank you so much for your help and I promise I will give knowledge back to the community!

I tried to search Google for the "opposite" of the 4-to-16 decoder but failed. Is there really any opposite of that or similar chip? If none, I will just use input shift registers.

Try looking for an encoder or multiplexer, or demultiplexer.they are common although you might have to use several to get the number of inputs and outputs you want.

Is demultiplexer is the same as multiplexer? I can't really find something like "4-to-16 multiplexer". I have a demultiplexer one but I'm not sure if it can be used as an input.

Oh I saw one, but it's called priority encoder.

Looks like this IC is primarily used for keyboards (piano or not).

But is it advisable to use this instead of input shift registers?

Is demultiplexer is the same as multiplexer?

No that is why the names are different, however a multiplexer is the same as a data selector.
There are many inputs and one output. Like a 74LS152.

In a demultiplexer there are many outputs and one input, like a 74LS138.

I can't really find something like "4-to-16 multiplexer"

You will not find a single chip that does that function you have to make it up from other multiplexers.

but it's called priority encoder.

That has lots of inputs and the output bits are the binary representation of the highest active input. Not, I would have thought, what you wanted.

A part like DG406 can be used as a 16 to 1 multipexer.
4:16 usually indicates 4 address lines to select 1 of 16 connections.
http://www.digikey.com/product-detail/en/DG406DJZ/DG406DJZ-ND/821393

Digital options are 74xx150 series parts
http://www.digikey.com/product-detail/en/SN74150N/296-26368-5-ND/1575162
They are not very common anymore tho.
8:1 are much more readily available

there are 22 pins available on the arduino. doing the direct approach uses up 16 of them, and the usb/serial line takes up another 2, so you have only 4 pins left. if this is not enough, then your original idea of shift registers is probably best. it will most likely be fast enough, but be sure to give a small delay after you clock out the row data before you clock in the column data. it takes a small bit of time for the levels to settle.

if i understand your question about demultiplexers correctly, i dont think that will work well. there are 12 column lines, each of which can be at any state, so that is 2^12 combinations of states. you need all 12 lines to preserve that information. you could use a demultiplexer to serialize the data - look at one line at a time. but, this is slower than the shift registers.

putting a small synth inside along with all the other knob and switch scanning might slow down your scanning rate, so that the keyboard is not as responsive.

Only 20 pins - 2 are committed elsewhere.

You could make it interrupt based and all shift register based.
Columns are normally low from shift out registers.
Rows are normally high from shift in registers with pullup resistors on the inputs.
Rows have a diode each, cathode connected to row pin, anodes connected in parallel to an interrupt pin.
When a button is pressed, the row pin is connected to a low column pin and creates an interrupt.
The code then makes all columns but 1 high and reads in the rows, cycle thru all columns quickly and see which row reads back as low.
The combination of known low column and discovered low row tells you which button was pressed.
If multiple keys were pressed, they will be all be discovered.
Use SPI.transfer to shift out the column drives and to shift in the row data for best responsiveness.

So 2 bytes out for column, 2 bytes in for read.
Repeat for all columns.
Do it without loops and with direct port manilupation of the latch signals for faster response time:

PORTD = PORTD & B11111011; // port2 B2 used for shift out latch for example
SPI.transfer(columnArray[0]);
SPI.transfer(columnArray[1]);
PORTD = PORTD | B00000100;

PORTD = PORTD & B11110111; // portD B3 used for shift in latch
PORTD = PORTD & B00001000; // assume low to high for latch
rowArray[0] = SPI.transfer[0];
rowArray[1] = SPI.transfer[0];

repeat for remaining columns.

That's a great idea! But how will it know if a key is lifted and how fast the key is lifted so that i can have a midi note off velocity? I'm still confused on how the scanning system you suggested works. Please simplify the explanation for me. =) Would be better if it is a step by step explanation.

Currently this is my algorithm to scan the keyboard:

  1. Drive each rows HIGH one by one
  2. For each row that is driven HIGH, scan the whole columns one by one.
  3. Then the current row number, current column number and the state of the column number will be passed to a function that process the data. (Like calculating the delay and sending midi signals)

For example:
(1,1,HIGH)
(1,2,LOW)
(1,3,HIGH)
etc...

What do you will be the problem of this algorithm?
Will it be too slow?
How will I know if a previous pressed key is lifted? How will I do that with interrupts?

So for velocity, you have to read two contacts per switch? so its really a 22x12 matrix (or 11x24, whatever).
I guess you would interpret the time from 1 to the other and determine velocity from there.
The interrupt was just to tell that something, anything, had been pressed and to perform a scan.
Maybe use one interrupt for first closure, another for the second, keep track of when both occurred so you know what to do when they occur in opposite order.

It has two contacts per "key" and it's a 61-key keyboard so its 12x11. If its a non velocity (one contact per key) 61-key keyboard, it will be 6x11. So I guess I have to learn how to use interrupts. Hahaha. Thanks for all the help.