• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Building a MIDI keytar

Thread starter #123
There are a lot of DIN plug types that look similar to the MIDI socket.
So it's easy to make that mistake. :)

Those particular DIN sockets have the extra pins removed. It threw me off at first, but once I took a meter to them,
I realized that only the important pins were there.
Thread starter #124
Here's the keybed decoder / scan logic.

The taped down bundles are the data and strobe lines coming from the PIC. The rectangular copper foil patch is the ground plane for the PIC.

Over the next few days, I'll be wiring up the CPU. I'm going to get the basic device communicating with the ICD3 and write a simple test program
to clock a port with pulses. Then, on to register setup and programming. :)
Last edited:


Active Member
I've searched a little bit about keybeds and some roland types readout the highest notes with the lowest matrix.
Because there was some space there, but not in the highest matrix.
When scan logic works You can create MiDi Strings with the USART and test it out with an PC e.g. with MiDi OX.


Active Member
Hi MJ what sound box / synth are you feeding with the Keytar ? I have just added a slave Alesis Q49 keyboard to my Yamaha , think i may need a MiDi sniffer,, so another project looms ...
Thread starter #128
wkrug: As soon as I get a test program set up, I'll be able to take a look at the keybed and test it.
I'd also like to pick up a 49 key bed from doepfer.de I have those mating connectors, so I can retrofit the key action.

granddad: I have a few synths that I could use.

I have a Virus C, Roland XV-5050 and a JP-8080, and both an Alesis S4-Quadra and the QSR.
As wkrug said, I can feed it into the midi interface and use MIDI-OX to see what's coming out.

That sounds like a neat project. :)
Thread starter #129
Here's the schematic for the ICSP interface.
Remove the jumper to program it, replace it to run stand-alone.

Thread starter #130
So I've gone through the documentation for the PIC24F32KA304 (44 pin TQFN)

Here's all of the Data ports with their corresponding shared pins.

PORT PIN# Shared With DESC
RA0 19
RA1 20
RA2 30 OSCI Main Oscillator Input
RA3 31 OSCO Main Oscillator Output
RA4 34
RA5 18 MCLR Master Clear Input
RA6 7
RA7 6
RA8 32
RA9 35
RA10 12
RA11 13

RB0 21 PGEC1 ICSP Clock 1
RB1 22 PGED1 ICSP Data 1
RB2 23
RB3 24
RB4 33
RB5 41
RB6 42
RB7 43
RB8 44
RB9 1
RB10 8 SDI1 SPI1 Serial Data Input
RB11 9 SCK1 SPI1 Serial Input/Output Clock
RB12 10
RB13 11 SDO1 SPI1 Serial Data Output
RB14 14
RB15 15 SS1 SPI1 Slave Select

RC0 25 AN6 A/D Analog Input #6
RC1 26 AN7 A/D Analog Input #7
RC2 27 AN8 A/D Analog Input #8
RC3 36
RC4 37
RC5 38
RC6 2 U1RX
RC7 3 U1TX
RC8 4
RC9 5
Here's what I came up for the keytar port assignments.

RA0 19
RA1 20
RA4 34
RA6 7
RA7 6
RA8 32
RA9 35
RA10 12
RA11 13

RB2 23 Scan 0
RB3 24 Scan 1
RB4 33 Scan 2
RB5 41 Scan 3
RB6 42 Scan 4
RB7 43 Scan 5
RB8 44 Scan 6
RB9 1 Scan 7
RB12 10 OE1
RB14 14 OE2

RC3 36 Address A
RC4 37 Address B
RC5 38 Address C
RC8 4 LE1
RC9 5 LE2
As soon as I get everything wired up and tested, I'll post pics and a schematic. :)
Thread starter #132
granddad: Young player? I'm still a toddler. :D
I have so much to learn...

Thanks. :)

I've started writing the initialization code. First, I have to shut off everything I'm not using.

Then, the UART and Timer1.
Luckily for me, 31250 Baud is an exact register value.

As soon I get the basic stuff working, I'll post the new source code.
Thread starter #133
Here it is. Not my best work. If I had my druthers I'd redo it and do a better layout.
Who knows...I may just do that.

The top of the Keytar board, in its' entirety. As you can see, I stashed the crystal inside the empty space of the socket.

This was supposed to be better detail, but the shot got blurry. :(

Oh, well...

Here's the CPU wiring.

Here's a close up of the A/D convertor inputs. I hope the twisted pairs keep the noise down.
I didn't do a separate Analog / Digital ground. Perhaps in the next prototype, I'll plan that in.

There are two sections which I must complete:

1) The buttons. I have enough pins and space to poll another key matrix using some of the original hardware. The AC238 can poll the rows and
an AC244 can be used to scan for columns.

2) The Display controller. I have a chunk of room where I can fit just about everything I need.
I still have to design that part of the system.

I'll publish a schematic in a few days. First, I want to get the PIC functioning and make sure that no hardware changes are needed.

More to come...
Last edited:


Well-Known Member
Most Helpful Member
Hitting all notes of a keyboard can be a challenge because the difference between the higher pitch notes becomes a small fraction of the processor crystal speed.

There are tricks to overcome the issues by selecting the "perfect" crystal speed that allows the 12-note "octave" to align with the integer scaling factors that can be easily done with a chip.

The long-form datasheet for the old AY- series sound generators (General Instruments/Microchip) from the 1980s (Atari and Apple sound cards), gives an excellent example of hitting all musical note frequencies with a relatively low frequency crystal - simply by picking the right starting crystal frequency.
Thread starter #135
gophert: Thanks for replying. :)

This project is only going to be generating MIDI events to feed to a synthesizer, which is a "walk in the park"
in comparison to actual waveform generation.

But I've always wanted to build a DIY synth. :)

Sad that those ICs are difficult to get these days.


Well-Known Member
Most Helpful Member
gophert: Thanks for replying. :)

This project is only going to be generating MIDI events to feed to a synthesizer, which is a "walk in the park"
in comparison to actual waveform generation.

But I've always wanted to build a DIY synth. :)

Sad that those ICs are difficult to get these days.
Let me know if you want a few, I have a drawer full of them and I doubt I'll ever get a project started. AY-3-8913.

Each chip can play three tones at a time plus a noise channel. Weird but cool effects possible. Not a full-on synth but it would be great for playing an 8-bit audio concert.
Thread starter #138
gophert: Thank you for your kind offer. Perhaps we can collaborate on a project. :)

granddad: I'm still thinking that one out... :)

Please bear with me, as I'm a complete n00b with the PIC. The changeover of tools with Microchip has made it even more difficult.

Here's my data segment (so far)

Transpose:        .byte    0
Octave:            .byte    0
VelCounters:    .space    49, 0
LastRawScanData:    .space    16, 0
RawScanData:    .space    16, 0
I'm thinking something like this. I wrote it in C, but I'll code it up in PIC assembler when I'm ready to implement it.
for(i = 0;i < 16;i++)
     LastRawScanData[i] = RawScanData[i];
for(i = index = 0;i < 8;i++)
    Set the AC238 address to the lower 3 bits of 'i'.
    1 or 2 tick delay...not sure. Will check the timing when the code is running.

    Set the latch enables on the AC573 to low.
    1 or 2 tick delay (Same as above)

    Set the latch enables on the AC573 to High.
    1 or 2 tick delay (Same as above)

    Set the latch enable #1 on the AC573 to Low.
    1 or 2 tick delay (Same as above)
    RawScanData[index++] = <Port byte>;

    Set the latch enable #1 on the AC573 to High.
    1 or 2 tick delay (Same as above)

    Set the latch enable #2 on the AC573 to Low.
    1 or 2 tick delay (Same as above)
    RawScanData[index++] = <Port byte>;

    Set the latch enable #2 on the AC573 to High.
    1 or 2 tick delay (Same as above)
// We now have the previous keyboard scan data as well as the current scan data.
// We can start comparing the bits and acting accordingly

// 7 bits used and only 7 out of 8 raw data registers used...
for(i = KeyIndex = 0;i < 7;i++)
BYTE KeyPress1 = RawScanData[i << 1],KeyPress2 = RawScanData[(i << 1) + 1];
BYTE LastKeyPress1 = LastRawScanData[i << 1],LastKeyPress2 = LastRawScanData[(i << 1) + 1];

    for(j = 0;j < 7;j++)
// I'm going to do a bit by bit comparison. The notation I'm using here is not correct, but it illustrates the bit comparison...
          if (LastKeyPress1<j> != KeyPress1<j>)
                if (KeyPress1<j> != 0)
                    if (KeyPress2<j> == 0)
                            VelCounters[KeyIndex] = 0;
                          // The key has been released...
          else if (KeyPress1<j> != 0 && KeyPress2<j> == 0)
          else if (KeyPress1<j> != 0 && KeyPress2<j> != 0)
// Send a Note on to the UART buffer...
If a key hasn't been pressed, the velocity will be 0.

Of course, this is just a rough skeleton. I have to implement the UART code and the transpose / octave code.

The variable "Transpose" will hold a value which is summed to the Note number.
The range of this value will be -11 to 11.

The variable "Octave" will hold a value which will sum 12 (the number of notes per octave) to the key address.

The important thing to remember is that a MIDI note can only be between the range of 0 and 127.
So it will have to be clipped to that range.


Active Member
MJ I think you will find the MPLABX [watch] option useful in conjunction with a break point. ( watch does not always tell the truth ! ) I run MPLAB on linux , PC it seems a lot less buggy . When I did my KB scanner I used the PIC EEprom to hold the table of note values , and from the row/column counts just produced an address of the note , (2x66 note manuals so different counts) was easy to transpose that way also... I also could send a second MiDi channel with the same note value ..
Edit , I don't think the 10000's of EEprom reads is a problem , although the uSec to do so may, as you are scanning so fast ...
Last edited:
Thread starter #140
granddad: I suspect that the note octave positions were fixed in your design.
Moving the 49 note key array up and down across the entire 128 note range was not needed?

Correct me if I'm wrong. If you needed to do that, you'd simply set a starting offset into the EEROM key table.

In this case, I need to provide two functions (well... 3 if you include layering.):

1 ) the user needs to be able to transpose notes played.

2 ) The user also needs to move the controller through the octave positions.

The 3rd function is to allow the keyboard to be split. (i.e. the lower range plays notes on the first MIDI channel, and the upper range needs
to play notes on a different MIDI channel.)

Layering is another nice effect; When a key is struck, it produces two separate MIDI events on different channels.

That means Transposing and Key range need to be stored for each of the MIDI channels involved in the Split / layering.

Another issue that needs to be handled is MIDI congestion. You don't want too many note on events going out for the same key number
without a corresponding note off being sent first. That needs to be handled in the code as well.

So, you only have about 80% of the info when the timer tick is completed.

Then there's system event handling, as well as MIDI clock.

I should be done with the schematic in a few hours.
I'll post it as soon as it's complete. :)

Latest threads

EE World Online Articles