Midi relay state change help

Hi All,

I have here a some code that lets you select 3 relay states (on or off) by 3 seperate pushbuttons, another button to save the states of the selected relay states to an eeprom address.Then another button to read that address with the relay states and turn on or off the selected relays. its does this quite well.
it also reads the memory address and turns on/off the relays from program change via a midi footswitch.

now that i want to do and cant figure out is to read the incoming program change, change the relay states and save that state back to the corresponding eeprom address.
(so if program 3 is selected, and i make a change to the relay states it saves the state change to eeprom address 3.

any help would be greatfull.

//Midi Relay
#include <EEPROM.h>;



#include <MIDI.h>;  // Add Midi Library
int buttonState; //this variable tracks the state of the button, low if not pressed, high if pressed
int ledsState = HIGH; //this variable tracks the state of the LED, negative if off, positive if on
#define ledcount 3
byte g_button_pins[ledcount] = { 
  2,3,4 };
bool g_button_state[ledcount];
bool g_last_button_state[ledcount];
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 100;    // the debounce time; increase if the output flickers
int Storebutton = 5;
int Leds[ledcount] = {7, 9, 11};
int Buttons[] = {2, 3, 4};
int stled = 13;  
int buttonPushCounter = 0;
int addr = 0;
int Readled = 12;
int ReadButton = 6;
int memoryaddress = 0;
int x=0;
int laststoreState = LOW;
int bState;
int lastrState = HIGH;
byte state = EEPROM.read(memoryaddress);
MIDI_CREATE_DEFAULT_INSTANCE();


void setup() {
  Serial.begin(9600);
  MIDI.begin(MIDI_CHANNEL_OMNI);
 MIDI.setHandleProgramChange(MidiProgramChange);
  //set the mode of the pins...
  for( int i=0; i<ledcount; i++ )
  {
    pinMode( g_button_pins[i], INPUT_PULLUP );
    pinMode( Leds[i], OUTPUT );
    //pinMode( Leds[i], LOW );
    g_button_state[i] = true;
    g_last_button_state[i] = true;
  }
  pinMode(Storebutton,INPUT_PULLUP);
          pinMode(ReadButton,INPUT_PULLUP);
      pinMode(stled, OUTPUT);
         pinMode(Readled, OUTPUT);  
}
//close void setup
void saveLedsState(int address) {  
  byte currentLedsState = 0;
  //loop through the leds
  for(int i = 0; i < ledcount; i++) {
    //get the current led pin
    int currentLed = Leds[i];
    //get the state of the current led - returns 0 or 1 (LOW or HIGH)
    int ledState = digitalRead(currentLed); 
    bitWrite(currentLedsState, i, ledState);   
  }
  EEPROM.write(address, currentLedsState);
}
void setLedsFromState(byte ledsState) {
  //loop through the leds
  for(int i = 0; i < ledcount; i++) {
    //get the corresponding led pin
    int currentLed = Leds[i];
    
    //using the bitRead function, get the saved state for corresponding led
    int ledState = bitRead(ledsState, i);
    
    //set the current led to the state read
    digitalWrite(currentLed, ledState);  
  }
}

void MidiProgramChange(byte channel, byte number) {  
 int  statem = EEPROM.read(number);
      setLedsFromState(statem);      
}

void turnAlloff() {
  for(int i = 0; i < ledcount; i++) {
    digitalWrite(Leds[i], HIGH);
  }
}

void loop() {
  
  MIDI.read(); //Listen for midi in
  
  /////////Buttons to select leds/////////////////////   
   for( int i=0; i<ledcount; i++ )
  {
    g_button_state[i] = digitalRead( g_button_pins[i] );

    // see if state changed, and new state is LOW
    if( g_button_state[i] != g_last_button_state[i] && g_button_state[i] == HIGH)
      {
      digitalWrite( Leds[i], ! digitalRead (Leds[i]));  // <--- toggle pin
      delay (30);  // debounce
      }  // end of if state changed
    g_last_button_state[i] = g_button_state[i];
  }  
  //Storage/////////////////////////////////////
  int StoreState;
  StoreState = digitalRead(Storebutton);
  if (StoreState != laststoreState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  //filter out any noise by setting a time buffer
  if ( (millis() - lastDebounceTime) > debounceDelay) {
if (StoreState != bState) {
      bState = StoreState;
    //if the button has been pressed, lets toggle the LED from "off to on" or "on to off"
    if  (StoreState == LOW){
     // ledsState = !ledsState;   
      saveLedsState(memoryaddress);
      Serial.print("memoryaddress        ");
      Serial.println(memoryaddress, DEC);
     // Serial.print("state        "      );
      Serial.print("\t" ); 
      digitalWrite(stled, HIGH); //turn LED on
      delay(1000);
      digitalWrite(stled, LOW);
      delay(500);
      digitalWrite(stled, HIGH);
          delay(1000);
      digitalWrite(stled, LOW);
          turnAlloff();
      
    }
}
  } 
    laststoreState = StoreState;
  //close if(time buffer)
  
  
  
  /////////////////ReadState//////////////////////////////
  
  /////////Reading leds from eeprom 
  
  
  
  //sample the state of the button - is it pressed or not?
  
 
int  ReadState = digitalRead(ReadButton);
  if (ReadState != lastrState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  //filter out any noise by setting a time buffer
  if ( (millis() - lastDebounceTime) > debounceDelay) {
     if (ReadState != buttonState) {
      buttonState = ReadState;
    //if the button has been pressed, lets toggle the LED from "off to on" or "on to off"
    if (ReadState == LOW) {
      ledsState = !ledsState;
      EEPROM.read(memoryaddress);
      memoryaddress++;
      if(memoryaddress  > 3){ 
        memoryaddress  = 0;
      }
       state = EEPROM.read(memoryaddress);
      setLedsFromState(state);
     
      Serial.print("memoryaddress        ");
      Serial.println(memoryaddress, DEC);
      Serial.print("state        "      );
      Serial.print("\t" );
      Serial.println(      state, BIN);
      digitalWrite(Readled, ledsState); //turn LED on
    } 
    }   
  }  
    //close if/else
    lastrState = ReadState;
}
//close void loop

Please use a flow chart to show the logic of the intended code. Lots of words and home brewed expressions takes way more time to get things right.

delete all empty lines in your sketch and post again.

not sure i fully understand your code but have some comments.

  • i'm surprised this works. would be better practice to do in setup()
  • the button scanning is more complicated than needed. debouncing just needs a 10 msec delay

how about

    int StoreState = digitalRead(Storebutton);
    if (StoreState != bState) {
        bState = StoreState;
        delay (10);

        if  (StoreState == LOW){

presumably in MidiProgramChange(), simply update the EEPROM. or keep an image of the EEPROM in RAM (instead of always reading from EEPROM) and whenever it changes update the EEPROM

whenever it changes update the EEPROM>
yes read what program change number via midi and if there is a change to the relay buttons save the new state to the same address as the selected program number when the store button is pressed.

i have tried making the program change function the same as the store state.

void MidiProgramChange(byte channel, byte memoryaddress) {
  
 //int  statem = EEPROM.read(memoryaddress);
  
      setLedsFromState(memoryaddress);
     
```but that didnt work either.
the read button functions the way i want the midi incoming programchange function.

So when any external midi button is pressed its just saving the new state to memory address1.

how do i get it to the midi button pressed to corrispond to the selected memoryaddress so that the new state can be saved.

ie. if midi button 2 is pressed it selects memoryaddress 2 and save the new state to memory address 2.

any help would be great.

still confused.

why are there multiple EEPROM locations storing state and "the state" simply stored in the one address? what state are you trying to save? shouldn't a single byte be able to represent all your relays?

are you saving the state in EEPROM so that the unit comes up in the same state it was in when shutoff?

why are there multiple EEPROM locations storing state and "the state" simply stored in the one address? what state are you trying to save? shouldn't a single byte be able to represent all your relays?<

Im sorry, im not explaining this very well.

so the state = relays on or off,
midi program number 1 reads the eeprom address 1 which has the the realy state relay1 off, and realy 2 on for example.
midi program number 2 reads eeprom address2 which has the relay state relay 2 off and relay 1 on.

it does the above.

but what im trying to do if i am on midi program number 3 for example, i want to able to change the relay states and save the edited state back to the corresponding EEPROM address.ie EEPROM address3

addr 1 has relay-1 Off and relay-2 On
addr 2 has relay-1 On and relay-2 Off

????

is the state simply which relay is On?

when do you read the EEPROM and what do you do with it?

is the state simply which relay is On?
Yes

when do you read the EEPROM and what do you do with it?
in the programchange function you read the eeprom and on the read button.

still ??
why can't the relay state be represented by separate bits in the state variable and there is only byte to maintain?

what determines the state? the button that selects the program?

do you need to remember that state the program was last in to avoid pressing a button ??

what do the relays control?

why can't the relay state be represented by separate bits in the state variable and there is only byte to maintain?

No it is its using a function called saveledstate which uses bit write to save each relay state as a bit then saved to the a memory address as a byte.

what determines the state? the button that selects the program?
yes.

what do the relays control?
Audio loops

looks like just 3 bits in each EEPROM byte are used.

why not use the upper 4bits for one case and the lower 4 bits as the other case?

The plan eventually is to use 8 relays, but for testing purposes just trying 3 relays at the moment.

i think i',m getting lost with what the problem is.
what needs to be known from EEPROM and what determines what "that" "known" is.

it is trivial to store stuff in EEPROM. if there is an EEPROM image in ram, read at startup up, the EEPROM is updated whenever the image is changed.

can you describe when things get "changed"?

//Storage/////////////////////////////////////
  int StoreState;
  StoreState = digitalRead(Storebutton);
  if (StoreState != laststoreState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  //filter out any noise by setting a time buffer
  if ( (millis() - lastDebounceTime) > debounceDelay) {
if (StoreState != bState) {
      bState = StoreState;
    //if the button has been pressed, lets toggle the LED from "off to on" or "on to off"
    if  (StoreState == LOW){
     // ledsState = !ledsState;   
      saveLedsState(memoryaddress);
      Serial.print("memoryaddress        ");
      Serial.println(memoryaddress, DEC);
     // Serial.print("state        "      );
      Serial.print("\t" ); 
      digitalWrite(stled, HIGH); //turn LED on
      delay(1000);
      digitalWrite(stled, LOW);
      delay(500);
      digitalWrite(stled, HIGH);
          delay(1000);
      digitalWrite(stled, LOW);
          turnAlloff();
      
    }
}
  } 
    laststoreState = StoreState;
  //close if(time buffer)
  
  
  
  /////////////////ReadState//////////////////////////////
  
  /////////Reading leds from eeprom 
  
  
  
  //sample the state of the button - is it pressed or not?
  
 
int  ReadState = digitalRead(ReadButton);
  if (ReadState != lastrState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  //filter out any noise by setting a time buffer
  if ( (millis() - lastDebounceTime) > debounceDelay) {
     if (ReadState != buttonState) {
      buttonState = ReadState;
    //if the button has been pressed, lets toggle the LED from "off to on" or "on to off"
    if (ReadState == LOW) {
      ledsState = !ledsState;
      EEPROM.read(memoryaddress);
      memoryaddress++;
      if(memoryaddress  > 3){ 
        memoryaddress  = 0;
      }
       state = EEPROM.read(memoryaddress);
      setLedsFromState(state);
     
      Serial.print("memoryaddress        ");
      Serial.println(memoryaddress, DEC);
      Serial.print("state        "      );
      Serial.print("\t" );
      Serial.println(      state, BIN);
      digitalWrite(Readled, ledsState); //turn LED on
    } 
    }   
  }  
    //close if/else
    lastrState = ReadState;
}

In the reading leds from eeprom part of the code, the button here uses a counter and scrolls through each eeprom address one at a time. so say 4 button presses would select eeprom address 4. so if i make a change to any of the relays, when i press the store button it saves the new change or state to the eeprom at the same address eeprom 4 and this works fine.

The problem is i have a midi foot controler with 4 buttons on it.
when i press midi button 1 it calls up eeprom memory address 1
when i presss midi button 2 it calls up eeprom memory address 2 ect
but when i go to change any of the relay states and press the store button it wont save the new state back to the revelent eeprom address.

when the Read button is pressed, the code sequences through the EEPROM. i guess you stop reading when the appropriate memoryaddress is read.

when the Store button is read, it simply writes the current state to the current memoryaddress.

does memoryaddress need to be set depending on the midi button pressed?

Yes

yes

yes

When any of the midi buttons are pressed and you change the relay state and press the store button to save the new state it saves it to the eeprom at memory address 0.