Hi all;
This is code I’m working on which should read a 3x3 button matrix and output various midi notes based on which buttons were pressed:
// Required libraries
#include <MIDI.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Constants and variables
const byte arLength = 9;
byte notesOnOld[arLength] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // Arrays which track the state of the current and previous button presses
byte notesOnNew[arLength] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
byte arIndex = 0;
const byte noteShift = 60;
const byte noteVel = 90;
const byte numRows = 3;
const byte numCols = 3;
const byte rowPins[numRows] = {2, 3, 4};
const byte colPins[numCols] = {5, 6, 7};
// Pre-setup initialization for MIDI and lcd display will go here
MIDI_CREATE_DEFAULT_INSTANCE();
void setup() {
// Activate row pins as INPUT (later toggled to LOW OUTPUT). unsure if initial LOW declaration works like this
for (byte i = 0; i < numRows; i++) {
pinMode(rowPins[i], INPUT);
digitalWrite(rowPins[i], LOW);
}
// Activate column pins as INPUT_PULLUP
for (byte j = 0; j < numCols; j++) {
pinMode(colPins[j], INPUT_PULLUP);
}
// Setup initialization MIDI and lcd display will go here
MIDI.begin(MIDI_CHANNEL_OMNI);
}
void loop() {
// Outside loop goes through rows and sets them to LOW OUTPUT one-by-one
for (byte i = 0; i < numRows; i++) {
pinMode(rowPins[i], OUTPUT);
// Inside loop goes through cols and reads their state (saved as byte to save space)
for (byte j = 0; j < numCols; j++) {
notesOnNew[arIndex] = (byte) digitalRead(colPins[j]);
arIndex++;
}
pinMode(rowPins[i], INPUT);
}
arIndex = 0;
// Second loop: output button press changes as either noteOn or noteOff and write notesOnOld array
for (byte i = 0; i < arLength; i++) {
if (notesOnNew[i] < notesOnOld[i]) {
// Since we're using pullup, a 0 means the switch is pressed, and 1 means it's open
MIDI.sendNoteOn(i+noteShift, noteVel, 1);
} else if (notesOnNew[i] > notesOnOld[i]) {
MIDI.sendNoteOff(i+noteShift, 0, 1);
}
notesOnOld[i] = notesOnNew[i];
}
}
I have 2 questions. The first is: where do you see any areas within which I could optimize, either via reducing the number of loops required or saving dynamic memory? My plan is to expand this same code to a 9x15 matrix for 135 keys which will require substantially more resources, thankfully I’m using an Arduino Mega. Also, I’m not even sure if the code works persay, but I think it’s close to what it needs to do. I noticed that as soon as I included the initialization for the midi library, my dynamic variable usage jumped from 10% to 25%, so maybe I can write the same functionality by hand and save some space.
Secondly: I am using diodes in my scan matrix in order to prevent ghosting and allow for multikey. However, I still want to ensure that the row pins which I’m each setting to GND don’t jump to OUTPUT HIGH before going to OUTPUT LOW. Is my code for this operation valid? For reference, here’s what I’m doing:
// in setup:
pinMode(rowPins, INPUT);
digitalWrite(rowPins, LOW);
// Then, before loop
pinMode(rowPins, OUTPUT);
// after loop
pinMode(rowPins, INPUT);