Last active
July 14, 2018 12:07
-
-
Save bruce965/dac9e55f1259b72de3cc364afee742bd to your computer and use it in GitHub Desktop.
Code for my 61-keys USB MIDI keyboard made with 1x STM32F103C8T6 and 8x 74HC165 ICs.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <USBMIDI.h> | |
// we use 74HC165 8-bit shift register ICs | |
#define CLOCK_ENABLE_PIN PB4 | |
#define PARALLEL_LOAD_PIN PB7 | |
#define CLOCK_PIN PB6 | |
#define SERIAL_DATA_PIN PB8 | |
#define FIRST_NOTE (60 - 12*2) // leftmost note of the keyboard (60 is middle C) | |
#define NOTES_COUNT (5 * 12 + 1) // number of notes | |
#define REGISTRIES_COUNT (NOTES_COUNT/8 + 1) | |
#define LAST_REGISTRY_NOTE (NOTES_COUNT - (REGISTRIES_COUNT-1)*8) | |
// how many cycles to wait before actually turning a note off (max 255) | |
#define DEBOUNCING_CYCLES 128 | |
// DEBOUNCING_CYCLES = pressed | |
// > 0 and < DEBOUNCING_CYCLES = not pressed, debouncing | |
// 0 = not pressed, debounce completed | |
byte keyStates[NOTES_COUNT] = {0}; | |
void setup() { | |
pinMode(CLOCK_ENABLE_PIN, OUTPUT); | |
pinMode(PARALLEL_LOAD_PIN, OUTPUT); | |
pinMode(CLOCK_PIN, OUTPUT); | |
pinMode(SERIAL_DATA_PIN, INPUT); | |
digitalWrite(PARALLEL_LOAD_PIN, HIGH); | |
digitalWrite(CLOCK_ENABLE_PIN, HIGH); | |
USBMIDI.begin(); | |
} | |
void loop() { | |
// load key press status on all shift register ICs in parallel | |
digitalWrite(PARALLEL_LOAD_PIN, LOW); | |
delayMicroseconds(5); | |
digitalWrite(PARALLEL_LOAD_PIN, HIGH); | |
delayMicroseconds(5); | |
// for each shift register IC... | |
for (int r = 0; r < REGISTRIES_COUNT; r++) | |
{ | |
// START: read one byte from the daisy-chained shift register ICs | |
digitalWrite(CLOCK_PIN, HIGH); | |
delayMicroseconds(5); | |
digitalWrite(CLOCK_ENABLE_PIN, LOW); | |
delayMicroseconds(5); | |
byte incoming = shiftIn(SERIAL_DATA_PIN, CLOCK_PIN, MSBFIRST); | |
digitalWrite(CLOCK_ENABLE_PIN, HIGH); | |
delayMicroseconds(5); | |
// END | |
// what is the offset of the first note this shift register IC handles? | |
int registryOffset = r * 8; | |
// how many notes does this shift register IC handle? | |
int lastRegistryNote = (r == (REGISTRIES_COUNT - 1)) ? LAST_REGISTRY_NOTE : 8; | |
// for each note handled by this shift register IC... | |
for (int i = 0; i < lastRegistryNote; i++) | |
{ | |
// acquire a pointer to the data relative to this key | |
byte* keyState = &keyStates[registryOffset + i]; | |
// is the key being pressed? was it pressed before? | |
bool isCurrentlyPressed = incoming & (1 << i); | |
bool wasPressedBefore = *keyState; | |
// if the key was not pressed and is pressed now, send a NOTE_ON signal | |
if (!wasPressedBefore && isCurrentlyPressed) | |
{ | |
USBMIDI.sendNoteOn(0, FIRST_NOTE + registryOffset + i, 127); | |
*keyState = DEBOUNCING_CYCLES; // reset debouncing | |
} | |
// if the key was pressed and is not pressed anymore, start debouncing | |
if (wasPressedBefore && !isCurrentlyPressed) | |
{ | |
*keyState = *keyState - 1; // reduce debouncing counter | |
// if debouncing counter is completed, send a NOTE_OFF signal | |
if (*keyState == 0) | |
{ | |
USBMIDI.sendNoteOff(0, FIRST_NOTE + registryOffset + i, 127); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment