Hi all,
I am attempting to create an Arduino that turns relays on and off in response to either momentary switch input or MIDI control change messages. I have got that bit working (although, please do tell me if this can be improved!). To prevent sharing hundreds of lines of codes, I will only share the code for one switch and one output as it is just duplicated and assigned different pins and control change values.
As the Arduino will be for switching audio signal paths I need a mute system to prevent the pops from the relays being heard. I have created a mute function (void mute ()) that needs to run when any control change occurs. This function enables an energized relay that grounds the signal to be grounded by setting the digital pin 9 on the other end of its coil to LOW (ground, which energies the relay and thus mutes the signal).
I started by trying the delay function inside the control change mechanism, but as this is a "blocking" function it simply enables the mute, turns it off, and then carries out the control change... which completely defeats the purpose. Some google searches lead me to believe the millis function is the solution I need. A friend mentioned a while loop but didn't elaborate further. I have tried the former, but to no avail. I am using 1000ms currently as I can see visually on my prototype whether it is working as intended as I am using LEDs in place of relays. In practice, the mute relay needs to turn on for ca. 40ms, then 5ms later the control change happens. After 40ms has elapsed, the mute self disables. Therefore these two events need to happen independently. When I toggle the control change I can see the mute LED flash for an instant, but definitely not the intended 1000ms. I cannot tell whether it is occurring before or after the control change. As a beginner I have probably made a stupid mistake - but I think what I am trying to do is quite simple and I'm hoping there is an obvious fix! Please also let me know if there are other ways in which my code can be improved and made more efficient.
#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>
#include <EEPROM.h>
//timer bits
unsigned long ms_from_start = 0;
unsigned long ms_previous_read_mute = 0;
unsigned long mute_interval = 1000;
int MUTE_state = 0;
//define MIDI CC constants
const int CC_RESET = 102;
const int CC_STORE = 104;
const int CC_MUTE = 105;
const int CC_MIDI_CHANNEL = 103; //for changing MIDI channel
const int CC_CH1 = 85; //channels
const int CC_CH2 = 86;
const int CC_CH3 = 87;
const int CC_CH4 = 88;
const int CC_FN1 = 89; //functions (e.g. loop)
const int CC_FN2 = 90;
const int CC_FN3 = 91;
const int CC_FN4 = 92;
//define switch and relay pins
const int SW_CH1 = 5; //channels
const int SW_CH2 = 6;
const int SW_CH3 = 7;
const int SW_CH4 = 8;
const int SW_FN1 = 4; //functions
const int SW_FN2 = 3;
const int SW_FN3 = 2;
const int SW_FN4 = 1;
const int RLY_CH1 = 19; //channels
const int RLY_CH2 = 18;
const int RLY_CH3 = 17;
const int RLY_CH4 = 16;
const int RLY_FN1 = 12; //functions
const int RLY_FN2 = 13;
const int RLY_FN3 = 14;
const int RLY_FN4 = 15;
//define misc. pins
const int MUTE = 9;
const int STORE = 10;
const int storeControlPin = 11;
int swPush = 0;
boolean swState = LOW;
boolean swStateLast = LOW;
uint8_t midi_channel = 0;
MIDI_CREATE_DEFAULT_INSTANCE();
void handleError(int8_t err) {
digitalWrite(LED_BUILTIN, (err == 0) ? LOW : HIGH);
}
//Poorly Implemented Mute function
void mute () {
ms_from_start = millis();
digitalWrite(MUTE, LOW);
if (ms_from_start - ms_previous_read_mute > mute_interval) {
ms_previous_read_mute = ms_from_start;
digitalWrite(MUTE, HIGH);
}
}
// CC functions
void midiCtrlChange(byte c, byte v) {
MIDI.sendControlChange(c, v, 0xB0 | midi_channel);
if (c == CC_CH1 && v > 64) { //cc, switch and relay set for channel 1
mute (); //I have only put the mute function in once place here as an example, rather than copying it to each CC given it is probably wrong!
delay(5);
digitalWrite(RLY_CH1, HIGH);
}
if (c == CC_CH1 && v <= 64) {
mute ();
delay(5);
digitalWrite(RLY_CH1, LOW);
}
if (c == CC_CH2 && v > 64) { //cc, switch and relay set for channel 2
digitalWrite(RLY_CH2, HIGH);
}
if (c == CC_CH2 && v <= 64) {
digitalWrite(RLY_CH2, LOW);
}
if (c == CC_CH1 && v > 64) { //cc, switch and relay set for channel 3
digitalWrite(RLY_CH1, HIGH);
}
if (c == CC_CH3 && v <= 64) {
digitalWrite(RLY_CH3, LOW);
}
if (c == CC_CH4 && v > 64) { //cc, switch and relay set for channel 4
digitalWrite(RLY_CH4, HIGH);
}
if (c == CC_CH4 && v <= 64) {
digitalWrite(RLY_CH4, LOW);
}
if (c == CC_FN1 && v > 64) { //cc, switch and relay set for function 1
digitalWrite(RLY_FN1, HIGH);
}
if (c == CC_FN1 && v <= 64) {
digitalWrite(RLY_FN1, LOW);
}
if (c == CC_FN2 && v > 64) { //cc, switch and relay set for function 2
digitalWrite(RLY_FN2, HIGH);
}
if (c == CC_FN2 && v <= 64) {
digitalWrite(RLY_FN2, LOW);
}
if (c == CC_FN3 && v > 64) { //cc, switch and relay set for function 3
digitalWrite(RLY_FN3, HIGH);
}
if (c == CC_FN3 && v <= 64) {
digitalWrite(RLY_FN3, LOW);
}
if (c == CC_FN4 && v > 64) { //cc, switch and relay set for function 4
digitalWrite(RLY_FN4, HIGH);
}
if (c == CC_FN4 && v <= 64) {
digitalWrite(RLY_FN4, LOW);
}
}
void setup() {
//Configure SW and RLY pins
pinMode(SW_CH1, INPUT_PULLUP);
pinMode(SW_CH2, INPUT_PULLUP);
pinMode(SW_CH3, INPUT_PULLUP);
pinMode(SW_CH4, INPUT_PULLUP);
pinMode(SW_FN1, INPUT_PULLUP);
pinMode(SW_FN2, INPUT_PULLUP);
pinMode(SW_FN3, INPUT_PULLUP);
pinMode(SW_FN4, INPUT_PULLUP);
pinMode(RLY_CH1, OUTPUT);
pinMode(RLY_CH2, OUTPUT);
pinMode(RLY_CH3, OUTPUT);
pinMode(RLY_CH4, OUTPUT);
pinMode(RLY_FN1, OUTPUT);
pinMode(RLY_FN2, OUTPUT);
pinMode(RLY_FN3, OUTPUT);
pinMode(RLY_FN4, OUTPUT);
pinMode(MUTE, OUTPUT);
// Initiate MIDI
Serial.begin(9600);
MIDI.setHandleError(handleError);
MIDI.begin(MIDI_CHANNEL_OMNI);
// Initiate CH1 on startup (will be removed once feature to remember last selected channel can be recalled after power off)
digitalWrite(RLY_CH1, HIGH);
//Disable mute on startup
digitalWrite(MUTE, HIGH);
}
void loop() { //this needs tidying up, different behaviour required for channel switching
MIDI.read();
//SWITCH 1 FUNCTIONS
swState = digitalRead(SW_CH1);
if (swState != swStateLast)
{
if (swState == LOW)
{
swPush++;
if (swPush > 1)
{
swPush = 0;
}
switch (swPush)
{
case 1:
midiCtrlChange(CC_CH1, 127);
break;
case 0:
midiCtrlChange(CC_CH1, 0);
break;
}
}
swStateLast = swState;
delay(10);
while (digitalRead(SW_CH1) == LOW)
{
delay(5);
}
}
}




