Basic question about returning to original array value

Status
Not open for further replies.

Hitachii

Active member
Hello. I have an array of 3 values (10, 11, 12), that when I press a momentary button advances to (13, 14, 15) advancing each number by 3 with every button press. I would like the limit of my up counter to be (16, 17, 18), then, if momentary button is pressed again, it returns to (10, 11, 12). The values should always be sequential like (10, 11, 12), so it should never be (10, 13, 16) or out of sequence numbers like that, which is happening with my bad code.

If this is confusing, then it's my error for being unclear. It's intended to be a simple 'preset' system on a synth. Each of the three values inside the parentheses represents an EEPROM address to be read, sending the byte value stored in the addresses to 3 potentiometers. Going out on a limb, I want to say that most synths have a preset system that works like this.

I'm having a lot of trouble returning to the original value, and suggestions I've gotten don't seem to work. Here is the relevant section of code, but if it's hard to tell from what's there, I will gladly post the whole code. What should I do differently?

This is from the section of the code where the button is pressed
Code:
addr[i] = addr[i]+3;

This is at the end of the code, where someone suggested I place it. The numbers go all out of order, and even exceed 15 sometimes.
Code:
  for (byte i = 0; i < 3; i++){
  if (addr[i] > 15){ 
    addr[i] = 10 + i;
      }
    }

Thanks!
 
Whoops, just saw the rule about posting complete source code. Here it is:

Code:
#include <EEPROM.h>

const int  buttonPin1 = 2;
const int  buttonPin2 = 3;         

int potPin[] = {A0, A1, A2};
int buttonState[3];         
int lastButtonState[3];
int buttonState2[3];
int lastButtonState2[3];
int addr[] = {10,11,12};

byte initPot[3];
byte lastInitPot[3];
byte potVal[3];
int threshold = 2;

void setup() {
  pinMode(buttonPin1, INPUT_PULLUP);
  pinMode(buttonPin2, INPUT_PULLUP);
  
  Serial.begin(9600);
}


void loop() {

  for (int i = 0; i < 3; i++){
  lastButtonState2[i] = buttonState2[i];// assign last reading value to previous read
  buttonState2[i] = digitalRead(buttonPin2);
  if (buttonState2[i] != lastButtonState2[i]) {
    if (buttonState2[i] == LOW) {
      EEPROM.update(addr[i], potVal[i]);
      Serial.println("~~~~Saved!~~~~");
      }
   }
    initPot[i] = analogRead(potPin[i]);
      if (abs(initPot[i] - lastInitPot[i]) > threshold){
        lastInitPot[i] = initPot[i];
          potVal[i] = initPot[i];
      }else{
lastButtonState[i] = buttonState[i];// assign last reading value to previous read
  buttonState[i] = digitalRead(buttonPin1);
  if (buttonState[i] != lastButtonState[i]) {
    if (buttonState[i] == LOW) {
      potVal[i] = EEPROM.read(addr[i]);
      addr[i] = addr[i]+3;                      //RELEVANT SECTION
    }    
  }             
}
      Serial.print("address");
      Serial.println(addr[i]);
      Serial.print("value");
      Serial.println(potVal[i]);
      delay(500);  
  }
  for (byte i = 0; i < 3; i++){
  if (addr[i] > 15){                      //RELEVANT SECTION
    addr[i] = 10 + i;                     //RELEVANT SECTION
      }
    }
  }
 
Replace this:
Code:
  for (byte i = 0; i < 3; i++){
  if (addr[i] > 15){                      //RELEVANT SECTION
    addr[i] = 10 + i;                     //RELEVANT SECTION
      }
    }

with this:
Code:
  if(addr[0] > 16) {
    for(byte i = 0; i < 3; i++){
      addr[i] = 10 + i;
    }
  }

Pete
 
Incredible. Thank you! I had to move the delay in my code down between the bottom two end curly brackets to make it work. Easy peasy. Still very very new to this :D. Love the people here.
 
Darnit. Stuck again on the final part of this. You'll see from my code that I'm in the ballpark of what I'm trying to achieve (explained below), but the logic has to be a bit different. I will take a crack at it if you can point me to which sort of commands I should be using.

Here's what I'm doing: There are supposed to be 9 "presets" divided evenly into 3 "banks", so each bank contains 3 presets. This would be preset 1: (10, 11, 12), preset 2: (13, 14, 15), preset 3: (16, 17, 18). Together, presets 1-3 comprise bank 1.

With respects to the code, a bank and a preset both just refer to scrolling through EEPROM addresses. the main difference is that they increment differently depending on which one of 2 buttons are pressed. Currently the code does this, but I have one rule that I want to apply to the bank button, and one rule that I want to apply for the preset button. It's these rules that I'm stuck on. Here's the description of the two:

1. I want to start at the first preset of the subsequent bank every time the bank button is pressed, instead of jumping forward by 9 (3 presets x 3 addresses per preset) like the code is now. The specific addresses that the bank button is supposed to bring you to are as follows:
- Bank 1 = (10, 11, 12)
- Bank 2 = (19, 20, 21)
- Bank 3 = (28, 29, 30)

2. The preset button should only cycle through the presets of the current bank, so pressing the preset button while in bank 1 only goes up to addresses (16, 17, 18) before cycling back to (10, 11, 12), so the preset button will never bring me to the next bank.

Right now, it's not working because both buttons affect the same value (bankAddr), so I'm arbitrarily counting up by the amount assigned to each button (but majestically looping around just fine when it's supposed to using your code).

Code:
int bankAddr[] = {10, 11, 12};
int buttonState1[3];
int lastButtonState1[3];
int buttonState2[3];
int lastButtonState2[3];

void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
Serial.begin(9600);
}

void loop() {
  
for(int i = 0; i < 3; i++){
lastButtonState1[i] = buttonState1[i];
  buttonState1[i] = digitalRead(2);
  if (buttonState1[i] != lastButtonState1[i]) {
    if (buttonState1[i] == LOW) {
      bankAddr[i] = bankAddr[i] + 3;                   // This button scrolls through presets
    }
  }else{
lastButtonState2[i] = buttonState2[i];
  buttonState2[i] = digitalRead(3);
  if (buttonState2[i] != lastButtonState2[i]) {
    if (buttonState2[i] == LOW) {
      bankAddr[i] = bankAddr[i]+9;         // The bank button. Not meant to haphazardly jump fwd by 9 like it is here, but to
    }                                                     // jump forward strictly to the first preset of the next bank from any preset in the
  }                                                       // current bank
}
  Serial.println(bankAddr[i]);    
  }                                           // This is the "bank" reset counter
  if(bankAddr[0] > 28) {
    for(byte i = 0; i < 3; i++){
      bankAddr[i] = 10 + i;
    }
  }                                           // This is the "preset" reset counter...
    if(bankAddr[0] > 16) {          // Right off the bat, this is not how it is
    for(byte j = 0; j < 3; j++){   // supposed to work, but it's here to indicate
      bankAddr[j] = 10 + j;         // that presets 'hit the wall' of the next bank
    }
  }
delay(500);      
}

edit: sorry about the wonky "//"s, can't get them to format right.
 
Last edited:
So to be clear there are two buttons, one BankNumber button, scrolling 1 -> 2 -> 3 -> 1 -> 2 ... and one FirstSelectedPresetWithinBank button going through values 1 -> 4 -> 7 -> 1 ...

Since the array values are always in succession you only must keep track of the first of them.

Then the actual bankAddr[0] = PresetNumber1 = BankNumber*9 + FirstSelectedPresetWithinBank
The following two values in your array are bankAddr[1] = PresetNumber2 = bankAddr[0] + 1 and bankAddr[2] = PresetNumber3 = bankAddr[0] + 2
 
This code might do what you want, I had no hooked up buttons so use 1 and 2 in serial monitor to simulate button presses.

Code:
int bankAddr[] = {10, 11, 12};
int buttonState1;
int lastButtonState1;
int buttonState2;
int lastButtonState2;

int BankNumber = 1;
int FirstSelectedPresetWithinBank = 1;

void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
Serial.begin(115200);
}

void loop() {

/* Use serial port to fake button presses */

lastButtonState1 = buttonState1;
lastButtonState2 = buttonState2;

buttonState1 = buttonState2 = HIGH;
if (Serial.available()) {
  byte ch = Serial.read();
  if (ch == '1') buttonState1 = LOW;
  if (ch == '2') buttonState2 = LOW;
}

//  buttonState1[i] = digitalRead(2);  /* FAKED with serial input */
  if (buttonState1 != lastButtonState1) {
    if (buttonState1 == LOW) {
      FirstSelectedPresetWithinBank = FirstSelectedPresetWithinBank + 3;                   // This button scrolls through presets
      if (FirstSelectedPresetWithinBank > 7) FirstSelectedPresetWithinBank = 1;                   // This button scrolls through presets
    }
  }

//  buttonState2[i] = digitalRead(3);  /* FAKED with serial input */
  if (buttonState2 != lastButtonState2) {
    if (buttonState2 == LOW) {
      BankNumber = BankNumber + 1;         // The bank button. Not meant to haphazardly jump fwd by 9 like it is here, but to
      if (BankNumber > 3) BankNumber = 1;
      FirstSelectedPresetWithinBank = 1;
    }                                                     // jump forward strictly to the first preset of the next bank from any preset in the
  }                                                       // current bank

  for(int i = 0; i < 3; i++){
    bankAddr[i] = BankNumber*9 + FirstSelectedPresetWithinBank + i;
    Serial.print(bankAddr[i]);    
    Serial.print( " ");    
  }                                           // This is the "bank" reset counter
  Serial.println();    

delay(2000);      
}
 
This is it! Oh my goodness, how perfect! Thank you thank you.

Being a noob, I was unaware that commands could be entered from the serial monitor. Out of curiosity, what is the utility in the baud rate that you selected? I'm used to defaulting to 9600, and have only used it out of habit without looking further into it. Not that I have any particular affinity for 9600.

Also, since MIDI has a default baud rate of 31250, will these two interfere in any way? Not sure if relevant, but I have been using the MIDI library for previous versions of this project.
 
The baudrate is not really important for Serial over USB, it all runs at full USB speed anyway. On some cards that uses serial to usb converters like Arduino UNO the baudrate affects the speed for serial monitor, and must match the setting in the serial monitor.

If you use serial hardware MIDI then that hardware serial port (often Serial1) must have baudrate set to 31250, but thi does not in any way affect the baudrate for any other serial port or for the USB serial connection.
 
You will also want to look into the debounce libraries, to make a single button press into what you want, a single button press.
 
I've introduced the EEPROM to the code, which works great. However, now that I have the analogRead in there as well, the "potVal" (which will eventually become the MIDI CC value) will 'snap' back to the value located at the EEPROM address when I'm not turning my pot. In the old version of the code above (which doesn't work anymore because i fiddled with it too much), it had the desired behavior of keeping each value located at the EEPROM address in place until the respective pot was turned, and then stayed with the pot until another EEPROM address was read. The difference between the two codes is that in the current version, the action of pressing the button is separate from where the address value is determined, so I'm not sure where to place the 'if' statement, or if that's even something I have to do.

I've been at this for a few hours now trying different things, like trying while statements (nope), placing the analogRead above all of the button actions, trying to do an 'if' statement with things like:

Code:
if(initPotVal != readPotVal[i]){
potVal[i] = initPotVal[i];}

I think the one above did the opposite of the current behavior but worse (only read analogRead, did not read from EEPROM address at all).

Code:
#include <EEPROM.h>

int bankAddr[] = {10, 11, 12};
int buttonState1;
int lastButtonState1;
int buttonState2;
int lastButtonState2;

int BankNumber = 1;
int FirstSelectedPresetWithinBank = 1;

void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
Serial.begin(115200);
}

void loop() {

byte potPin[] = {A0, A1, A2};
byte initPot[3];
byte lastInitPot[3];
byte potVal[3];
byte threshold = 2;

lastButtonState1 = buttonState1;
lastButtonState2 = buttonState2;

buttonState1 = buttonState2 = HIGH;

  buttonState1 = digitalRead(2); 
  if (buttonState1 != lastButtonState1) {
    if (buttonState1 == LOW) {
      FirstSelectedPresetWithinBank = FirstSelectedPresetWithinBank + 3;                  
      if (FirstSelectedPresetWithinBank > 7) FirstSelectedPresetWithinBank = 1;              
    }
  }
  buttonState2 = digitalRead(3);
  if (buttonState2 != lastButtonState2) {
    if (buttonState2 == LOW) {
      BankNumber = BankNumber + 1;         
      if (BankNumber > 3) BankNumber = 1;
      FirstSelectedPresetWithinBank = 1;
    }                                                     
  }
    for(int i = 0; i < 3; i++){                                                      
      initPot[i] = analogRead(potPin[i]);                // here's all of the pot mess
      if (abs(initPot[i] - lastInitPot[i]) > threshold){
        lastInitPot[i] = initPot[i];
          potVal[i] = initPot[i];
      }else{
    bankAddr[i] = BankNumber*9 + FirstSelectedPresetWithinBank + i;
    potVal[i] = EEPROM.read(bankAddr[i]);
      }
    Serial.print("ADDRESS: "); 
    Serial.print(bankAddr[i]);    
    Serial.println( " ");
    Serial.print("potVal: "); 
    Serial.print(potVal[i]);    
    Serial.println( " ");    
  }             
  Serial.println();    
delay(2000);      
}
 
Place the potVal = EEPROM.read(bankAddr); reads in the setup() function, and then create a 'save' function to store them back from a 'magical' user input.
Dont mix up the pot settings and the bank number calculations in the if .... else . The banknumbers does not depend on the fact that the pot has moved or not.

Always make sure the logic of the if' and for loops makes sence and corresponds to the intention before hacking away on the keyboard. White drawing paper and pens are your friend.
 
Found out what was wrong. In order for it to work, the 'load' command had to be triggered by an 'if(buttonPressed != lastButtonPressed)...' On top of that, you're absolutely right, now that I've spent a little more time with it, my if statements and bracket placements were madness.

After getting time to sit down and break it down, cheers again for the 2-button counters. That's incredibly intricate work, don't know how long it would take to figure it out on my own. Thanks both mlu and el Supremo, you made this project possible and taught me a lot.
 
The values should always be sequential like (10, 11, 12), so it should never be (10, 13, 16) or out of sequence numbers like that, which is happening with my bad code.
If these are always in sequence, why do you need them in an array? Why not just add one or two to the first parameter's address for the second and third parameters when you dereference them?
 
Last edited:
Honestly, because I don't know how very many different commands work yet. If the option you're presenting uses less ram than a similar code using the method you've described, I wouldn't be opposed to doing it. Would you mind showing me a brief example of this?
 
My post had some additional stuff in it that was somewhat confused because I forgot you were making a synth and not a controller.

Are you short of memory? I would think keeping it all in an array (with two dimensions - patch and parameter) and reloading it at setup and writing to EEPROM only when patch parameters are 'saved' (do you see having a save patch trigger?).

EEPROM has a limit to how often it can be saved over and if your addresses are static and you save to EEPROM on every parameter change you might wear it out (honestly I'm not expert here... something I recall from way back).

With a variable 'patch' you could use the array easily to recall parameter values as needed.

On patch change the code would just update all the parameters to the stored values in that 'row'

It would also likely be easy to update if the number of parameters changes or the number of patches you want to support increases.

If you do just want a 'pointer' to the EEPROM address you only need 1 value and the row and column of the parameter from the two-dimensional map of parameters.

Example.

Lets say you have 10 parameters and 50 patches and you want to recall the eighth parameter from the 23rd patch

You need an offset from the first EEPROM address equal to:

22*10 + 7 = 227 values over from the first one.

So with zero-based indexes it's

parameter[22][7] = EEPROM.read(baseOffset+227)


...
So a nested loop in the setep to load would look something like this;

Code:
for (j = 0, <numPatches, j++){
   for (i = 0, <numParams, i++){
      parameter[j][i] = EEPROM.read(baseOffset+j*NumParams+i)
   }
}
 
Status
Not open for further replies.
Back
Top