0

I'm trying to use a cheap keyboard with 37 keys as a MIDI controller by reading the multiplexed keys with an Arduino nano. The keys are grouped in six groups with a max of 8 keys per group. Which results in my setup of 8 digital INPUTS which are pulled HIGH, and 6 OUTPUTS, which are pulled LOW, when reading that group of keys. This works great when I only have 3 groups in my loop. However whenever I add another group it does not work anymore. It doesn't matter which groups are activated.

One group reading looks like this:

digitalWrite(A0, LOW);
for (byte j = 12; j > 4; j--)
{
  uint8_t note = offset + 20 + (12-j);
  uint8_t key_state = digitalRead(j);

if ( (key_state == 0) && (notes_pressed[note] == 1) ) { notes_pressed[note] = 0; Serial.write(note + 100); } else if ( (key_state == 1) && (notes_pressed[note] == 0) ) { notes_pressed[note] = 1; Serial.write(note); } } digitalWrite(A0, HIGH);

With A0 being the group pin.

I think this has to do with the pins not being able to be pulled low as quickly because of weak output drivers or something similar. Unfortunately I don't have an oscilloscope to check the levels. I have added delays to ensure the levels have settled when the reading occurs but to no avail.

Edit: Schematic is pretty much just this. The diodes in the keyboard I left out, but they are there as necessary: schematic

#include "HardwareSerial.h"

#define offset 48

void midi_note_off(byte channel, byte key, byte velocity); void midi_note_on(byte channel, byte key, byte velocity); void midi_command(byte command, byte channel, byte param1, byte param2);

byte notes_pressed[37]; void setup() { Serial.begin(115200); pinMode(12, INPUT_PULLUP); pinMode(11, INPUT_PULLUP); pinMode(10, INPUT_PULLUP); pinMode(9, INPUT_PULLUP); pinMode(8, INPUT_PULLUP); pinMode(7, INPUT_PULLUP); pinMode(6, INPUT_PULLUP); pinMode(5, INPUT_PULLUP); pinMode(4, OUTPUT); pinMode(3, OUTPUT); pinMode(2, OUTPUT); pinMode(A2, OUTPUT); pinMode(A1, OUTPUT); pinMode(A0, OUTPUT);

digitalWrite(4, HIGH); digitalWrite(3, HIGH); digitalWrite(2, HIGH); digitalWrite(A0, HIGH); digitalWrite(A1, HIGH); digitalWrite(A2, HIGH); }

void loop() { digitalWrite(4, LOW); for (byte j = 8; j > 4; j--) { uint8_t note = offset + (8-j); uint8_t key_state = digitalRead(j);

if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
  notes_pressed[note] = 0;
  Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
  notes_pressed[note] = 1;
  Serial.write(note);
}

} digitalWrite(4, HIGH);

digitalWrite(3, LOW); for (byte j = 12; j > 4; j--) { uint8_t note = offset + 4 + (12 - j); uint8_t key_state = digitalRead(j);

if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
  notes_pressed[note] = 0;
  Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
  notes_pressed[note] = 1;
  Serial.write(note);
}

} digitalWrite(3, HIGH);

digitalWrite(2, LOW); for (byte j = 12; j > 4; j--) { uint8_t note = offset + 12 + (12-j); uint8_t key_state = digitalRead(j);

if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
  notes_pressed[note] = 0;
  Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
  notes_pressed[note] = 1;
  Serial.write(note);
}

} digitalWrite(2, HIGH);

digitalWrite(A0, LOW); for (byte j = 12; j > 4; j--) { uint8_t note = offset + 20 + (12-j); uint8_t key_state = digitalRead(j);

if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
  notes_pressed[note] = 0;
  Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
  notes_pressed[note] = 1;
  Serial.write(note);
}

} digitalWrite(A0, HIGH);

digitalWrite(A1, LOW); for (byte j = 12; j > 4; j--) { uint8_t note = offset + 28 + (12-j); uint8_t key_state = digitalRead(j);

if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
  notes_pressed[note] = 0;
  Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
  notes_pressed[note] = 1;
  Serial.write(note);
}

} digitalWrite(A1, HIGH);

digitalWrite(A2, LOW); for (byte j = 5; j > 4; j--) { uint8_t note = offset + 36 + (5-j); uint8_t key_state = digitalRead(j);

if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
  notes_pressed[note] = 0;
  Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
  notes_pressed[note] = 1;
  Serial.write(note);
}

} digitalWrite(A2, HIGH); }

I know the last part looping over a single value is unnessecary but it should still work.

multikeys
  • 11
  • 2

2 Answers2

1

A few excerpts from the program:

#define offset 48
//...
byte notes_pressed[37];  // valid indices: 0 – 36
//...
uint8_t note = offset + (8-j);  // j ≤ 8, thus note ≥ 48
//...
notes_pressed[note] = 0;

That last line writes past the end of the notes_pressed array, and overwrites who knows what in memory. This could be the source of the issue you are facing.

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81
0

There are several issues to be considered when designing a switch matrix for an embedded processor regardless if it is a musical or computer keyboard:

  1. Contact bounce: This is more important for a computer keyboard then a musical keyboard. However if the switch are particularly bad, it may audible. Software may be used to mitigate the problem but will also add delay between the key press and the beginning of the note's sound.
  2. Pull Ups: Any logic input should not be left unconnected or floating. This can lead to unexpected results. Use Pull Up resistors (or Pull Down depending on your design) to mitigate this problem. The Arduino Uno's embedded processor (the ATmega328P) comes with built in Pull Up resistors. The Arduino IDE abstracts this feature by including a parameter it the pinMode() function call to invoke this feature.
  3. Rollover: In a switch matrix 1 or 2 simultaneous switch closure can be uniquely detected. However, if 3 switch closures connect 2 rows and 2 columns together, they can not be uniquely detected. This is because current can flow through the 3 closed switches activating both rows and both columns nullifying the ability for the embedded processor to scan individual rows or columns. To mitigate this problem a diode is added to all switches in the switch matrix such that there is no current path between rows or columns.

From the Rollover wikipedia page:

Most music keyboards use isolation diodes in their keyboard matrix to implement full n-key rollover, making them immune to both key ghosting and key jamming

This image if from this stack exchange question: This image is from this stack exchange question.

st2000
  • 7,513
  • 2
  • 13
  • 19