I'm developing a midi keyboard with an old dynamic keyboard and arduino uno. I created 2 different sketch:
The first one, using digitalRead and digitalWrite, works but I can't get accurate key short-long stroke timing intervals because the sketch loop is too slow.
In the second I try to use direct register access to speed up pin reading and writing, but I receive to the serial monitor unaspetted bytes and not my attended debug messages. I can't find what is wrong in the sketch.
This is the fast not working version:
#define INPINS 8
#define OUTPINS 4
#define KEYS 64
#define NSTATE 16
#define BUFFER_NOTEON 128
#define MIDINOTE_C2 36
unsigned long shortStroke[KEYS];//millis of short pressure
unsigned long keyboardON[KEYS];//-1 if keyoff, 0.127 pressure if key on
unsigned long keyboardPrev[KEYS];
unsigned long last_millis;
byte channel = 2; //channel 3
byte i = 0;
byte k = 0; //variable for reading input
byte base = 0; //octave base
byte state = 15;
byte nota = 0;
int pin_in[INPINS] = {2, 3, 4, 5, 6, 7, 8, 9}; //KD0,KD1,KD2,KD3,KD4,KD5,KD6,KD7
int pin_out[OUTPINS] = {10, 11, 12, 13}; //KA0, KA1, KA2, KA3
void setup() {
// put your setup code here, to run once:
state = 0;
for (i = 0; i < KEYS; i++) {
keyboardON[i] = (unsigned long)0; //set to zero all keybord keys state
keyboardPrev[i] = (unsigned long)0;
shortStroke[i] = (unsigned long)0;
}
//for (i=0;i<INPINS;i++){pinMode(pin_in[i],INPUT_PULLUP);}
//for(i=0;i<OUTPINS;i++){pinMode(pin_out[i],OUTPUT); }
DDRD = DDRD & B00000011; //set pin D0 and D1 for output and D2..D7 as input
DDRB = DDRB | B00111100; //set pin D8 and D9 as input and D10-D13 as output
//pinMode(A0,OUTPUT);//link the disble-enable decoders pin to A0 autput
//digitalWrite(A0,LOW);//enable decoders
DDRC = DDRC | B00000001; //set A0 for Output
PINC = PINC | B00000001; //disable decoders A0=low and leave other pins as they are
//for (i=0;i<OUTPINS;i++){digitalWrite(pin_out[i],HIGH*((state>>i)&1));}
PINB = (PINB & B11000011) | (state << 2); //leave pin D8 and D9 as they are and set PIN D10-D13 like bynary state value
PINC = PINC & B11111110; //enable decoders A0=low and leave other pins as they are
Serial.begin(31250);
last_millis = millis();
Serial.print("PINB="); Serial.println(PINB);
Serial.print("PINC="); Serial.println(PINC);
}
void readPins() {
k = (PIND & B11111100) >> 2;
k = k + ((PINB & B00000011) << 6); //statodei 8 primi switch
//k=state/2*8+i;//indice del tasto sulla tastiera da 0 a 60
base = state / 2 * 8; //activated 8 switch
for (i = 0; i < INPINS; i++)
{ nota = base + i;
if ((k & (1 << i)) == LOW) //key pressed
{ if (keyboardPrev[nota] == (unsigned long)0)
{
if ((state % 2) == 0) //short stroke
{
if (shortStroke[nota] == (unsigned long)0L) {
shortStroke[nota] = last_millis;
}
}
else //long stroke
{
if (shortStroke[nota] > 0) {
keyboardON[nota] = min(max((last_millis - shortStroke[nota]) >> 3, (unsigned long)1), 100);
shortStroke[nota] = (unsigned long)0;
}
}
}
}
else //key released
{ if (keyboardPrev[nota] > (unsigned long)0) {
keyboardON[nota] = (unsigned long)0; // (((state%2)==1)||((state%2)==0))
}
}
}
}
void MidiSend(byte cmd, byte data1, byte data2)
{
Serial.write(cmd | channel) ;
Serial.write(data1) ;
Serial.write(data2) ;
}
//
// MIDI note ON message
//
void MidiNoteOn(byte note, byte velocity)
{
MidiSend(0x90, MIDINOTE_C2 + note, velocity);
}
//
// MIDI note OFF message
//
void MidiNoteOff(byte note)
{
MidiSend(0x80, MIDINOTE_C2 + note, 0) ;
//MidiSend(0x90, MIDINOTE_C2+note, 0) ;
}
void sendMidiUpdate()
{ for (i = 0; i < INPINS; i++)
{ k = state / 2 * 8 + i; //indice del tasto sulla tastiera da 0 a 60
if (keyboardON[k] != keyboardPrev[k])
{ if (keyboardON[k] == (unsigned long)0) {
MidiNoteOff(k);
keyboardPrev[k] = (unsigned long)0;
}
else {
MidiNoteOn(k, 127 - keyboardON[k]);
keyboardPrev[k] = keyboardON[k];
}
}
}
}
void nextState() {
//digitalWrite(A0,HIGH);//disable decoders//all output are HIGH
PINC = PINC | B00000001; //set HIGH A0
state = (state + 1) % NSTATE; //scan 8 notes * 2 stroke (short-long)
/*for (i=0;i<OUTPINS;i++)
{digitalWrite(pin_out[i],HIGH*((state>>i)&1));} //activate decoder input
*/
PINB = (PINB & B11000011) | (state << 2);
//digitalWrite(A0,LOW);//enable decoders ALL OUTPUT LOW, BUT ONE HIGH
PINC = PINC & B11111110; //set LOW A0
Serial.print("PINB="); Serial.println(PINB);
Serial.print("PINC="); Serial.println(PINC);
}
void loop() {
readPins();
sendMidiUpdate();
nextState();
if (state == 0) {
last_millis = millis();
}
}
This is the slow working version:
#define INPINS 8
#define OUTPINS 4
#define KEYS 64
#define NSTATE 16
#define BUFFER_NOTEON 128
#define MIDINOTE_C2 36
unsigned long shortStroke[KEYS];//millis of short pressure
unsigned long keyboardON[KEYS];//-1 if keyoff, 0.127 pressure if key on
unsigned long keyboardPrev[KEYS];
unsigned long last_millis;
byte channel = 2; //channel 3
byte i = 0;
byte k = 0;
byte state = 15;
int pin_in[INPINS] = {2, 3, 4, 5, 6, 7, 8, 9}; //KD0,KD1,KD2,KD3,KD4,KD5,KD6,KD7
int pin_out[OUTPINS] = {10, 11, 12, 13}; //KA0, KA1, KA2, KA3
void setup() {
// put your setup code here, to run once:
state = 0;
for (i = 0; i < KEYS; i++) {
keyboardON[i] = (unsigned long)0; //set to zero all keybord keys state
keyboardPrev[i] = (unsigned long)0;
shortStroke[i] = (unsigned long)0;
}
for (i = 0; i < INPINS; i++) {
pinMode(pin_in[i], INPUT_PULLUP);
}
for (i = 0; i < OUTPINS; i++) {
pinMode(pin_out[i], OUTPUT);
}
//DDRD= B00000010;//set pin D0 and D1 for output and D2..D7 as input
//DDRB= B00111100;//set pin D8 and D9 as input and D10-D13 as output
pinMode(A0, OUTPUT); //link the disble-enable decoders pin to A0 autput
digitalWrite(A0, LOW); //abilita denoders
//DDRC=B00000001; //set A0 for Output
//PORTC=PORTC & B11111110;enable decoders A0=low and leave other pins as they are
for (i = 0; i < OUTPINS; i++) {
digitalWrite(pin_out[i], HIGH * ((state >> i) & 1));
}
//PORTB=(PORTB & B00000011)|(state*4);//leave pin D8 and D9 as they are and set PIN D10-D13 like bynary state value
Serial.begin(31250);
last_millis = millis();
}
void readPins() {
for (i = 0; i < INPINS; i++)
{ k = state / 2 * 8 + i; //indice del tasto sulla tastiera da 0 a 60
if (digitalRead(pin_in[i]) == LOW) //key pressed
{ if (keyboardPrev[k] == (unsigned long)0)
{
if ((state % 2) == 0) //short stroke
{
if (shortStroke[k] == (unsigned long)0L) {
shortStroke[k] = last_millis;
}
}
else //long stroke
{
if (shortStroke[k] > 0) {
keyboardON[k] = min(max((last_millis - shortStroke[k]) >> 3, (unsigned long)1), 100);
shortStroke[k] = (unsigned long)0;
}
}
}
}
else //key released
{ if (keyboardPrev[k] > (unsigned long)0) {
keyboardON[k] = (unsigned long)0; // (((state%2)==1)||((state%2)==0))
}
}
}
}
void MidiSend(byte cmd, byte data1, byte data2)
{
Serial.write(cmd | channel) ;
Serial.write(data1) ;
Serial.write(data2) ;
}
//
// MIDI note ON message
//
void MidiNoteOn(byte note, byte velocity)
{
MidiSend(0x90, MIDINOTE_C2 + note, velocity);
}
//
// MIDI note OFF message
//
void MidiNoteOff(byte note)
{
MidiSend(0x80, MIDINOTE_C2 + note, 0) ;
//MidiSend(0x90, MIDINOTE_C2+note, 0) ;
}
void sendMidiUpdate()
{ for (i = 0; i < INPINS; i++)
{ k = state / 2 * 8 + i; //indice del tasto sulla tastiera da 0 a 60
if (keyboardON[k] != keyboardPrev[k])
{ if (keyboardON[k] == (unsigned long)0) {
MidiNoteOff(k);
keyboardPrev[k] = (unsigned long)0;
}
else {
MidiNoteOn(k, 127 - keyboardON[k]);
keyboardPrev[k] = keyboardON[k];
}
}
}
}
void nextState() {
digitalWrite(A0, HIGH); //disable decoders//all output are HIGH
state = (state + 1) % NSTATE; //scan 8 notes * 2 stroke (short-long)
for (i = 0; i < OUTPINS; i++)
{
digitalWrite(pin_out[i], HIGH * ((state >> i) & 1)); //activate decoder input
}
//PORTB=(PORTB & B00000011) |(state*4);
digitalWrite(A0, LOW); //enable decoders ALL OUTPUT LOW, BUT ONE HIGH
}
void loop() {
readPins();
sendMidiUpdate();
nextState();
if (state == 0) {
last_millis = millis();
}
}
