sequential counting with buttons?

Hello.

I have been working on a 1 - 8 counting device. It has a button to control when the count increments. Whenever this button is pressed it increments the count by 1 and toggles through 8 leds one by one. It also has 8 other push buttons. Each one of these represent a count position. So if button 3 is pressed the count is 3 and led 3 lights up, if button 6 is pressed, the count is 6 and led 6 lights up etc.

At the moment if i press multiple buttons it just picks one and random based on which one was hit last i guess. What i would now like to do is press multiple buttons and have the main count button increment through the buttons i have held down. For example. If i am holding buttons 3 ,6 and 7. It counts 3, 6, and 7 over and over and If i am holding buttons 1 and 2 it counts 1 and 2 over and over. With the corresponding leds lighting up of course.

Thanks to anybody who takes time to read and help.

const byte leds[8] = {22, 23, 24, 25, 26, 27, 28, 29}; // Led Outputs
const int Forwards = 52; // Forwards input. 
int ForwardState; // Current Forwards State
int LastForwardState; // Last Forwards State
const byte buttons[8] = {40, 41, 42, 43, 44, 45, 46, 47}; //Button Inputs
byte buttonstate[8]; // current button state
byte last_buttonstate[8]; // last button state
int Counter = 0;   // counter


void setup() {

  for (int i = 0; i < 8; i++) //Set all the INPUTS and OUTPUTS.
  {
    pinMode (buttons[i], INPUT_PULLUP);
    pinMode(leds[i], OUTPUT);
  }
  pinMode (Forwards, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {

  //FORWARDS

  ForwardState = digitalRead(Forwards); // Reads forwards pin

  if (ForwardState != LastForwardState) { // Indicates state change of forwards
    if (ForwardState == LOW) { //Forwards is on.
      Counter++; // increments Counter.
    } else {
      (ForwardState == HIGH); // forwards is off.
    }
    delay(50);// Delay a little bit to avoid bouncing
  }
  LastForwardState = ForwardState; // save the current state as the last state,

  if (Counter > 8) { // Count Amount (1-8)
    Counter = 1;
  }

  // BUTTONS

  for (int setWhichButton = 0; setWhichButton < 8; setWhichButton++)
  {
    buttonstate[setWhichButton] = digitalRead(buttons[setWhichButton]);  //reads buttonstate of buttons.
  }

  for (int whichButtonPressed = 0; whichButtonPressed < 8; whichButtonPressed++)
  {
    if (buttonstate[whichButtonPressed] != last_buttonstate[whichButtonPressed]) {
      if (buttonstate[whichButtonPressed] == LOW) { // What button is pressed
        Counter = whichButtonPressed + 1; // Counter is the same as the button pressed... +1 to work with switch.
      } else {
        (buttonstate[whichButtonPressed] == HIGH); // No button pressed
      }
      last_buttonstate[whichButtonPressed] = buttonstate[whichButtonPressed];
    }
  }
  Serial.println(Counter);

  switch (Counter)    //What happens with leds
  {
    case 1:
      digitalWrite(leds[0], HIGH);
      digitalWrite(leds[1], LOW);
      digitalWrite(leds[2], LOW);
      digitalWrite(leds[3], LOW);
      digitalWrite(leds[4], LOW);
      digitalWrite(leds[5], LOW);
      digitalWrite(leds[6], LOW);
      digitalWrite(leds[7], LOW);
      break;
    case 2:
      digitalWrite(leds[0], LOW);
      digitalWrite(leds[1], HIGH);
      digitalWrite(leds[2], LOW);
      digitalWrite(leds[3], LOW);
      digitalWrite(leds[4], LOW);
      digitalWrite(leds[5], LOW);
      digitalWrite(leds[6], LOW);
      digitalWrite(leds[7], LOW);
      break;
    case 3:
      digitalWrite(leds[0], LOW);
      digitalWrite(leds[1], LOW);
      digitalWrite(leds[2], HIGH);
      digitalWrite(leds[3], LOW);
      digitalWrite(leds[4], LOW);
      digitalWrite(leds[5], LOW);
      digitalWrite(leds[6], LOW);
      digitalWrite(leds[7], LOW);
      break;

    case 4:
      digitalWrite(leds[0], LOW);
      digitalWrite(leds[1], LOW);
      digitalWrite(leds[2], LOW);
      digitalWrite(leds[3], HIGH);
      digitalWrite(leds[4], LOW);
      digitalWrite(leds[5], LOW);
      digitalWrite(leds[6], LOW);
      digitalWrite(leds[7], LOW);
      break;
    case 5:
      digitalWrite(leds[0], LOW);
      digitalWrite(leds[1], LOW);
      digitalWrite(leds[2], LOW);
      digitalWrite(leds[3], LOW);
      digitalWrite(leds[4], HIGH);
      digitalWrite(leds[5], LOW);
      digitalWrite(leds[6], LOW);
      digitalWrite(leds[7], LOW);
      break;
    case 6:
      digitalWrite(leds[0], LOW);
      digitalWrite(leds[1], LOW);
      digitalWrite(leds[2], LOW);
      digitalWrite(leds[3], LOW);
      digitalWrite(leds[4], LOW);
      digitalWrite(leds[5], HIGH);
      digitalWrite(leds[6], LOW);
      digitalWrite(leds[7], LOW);
      break;
    case 7:
      digitalWrite(leds[0], LOW);
      digitalWrite(leds[1], LOW);
      digitalWrite(leds[2], LOW);
      digitalWrite(leds[3], LOW);
      digitalWrite(leds[4], LOW);
      digitalWrite(leds[5], LOW);
      digitalWrite(leds[6], HIGH);
      digitalWrite(leds[7], LOW);
      break;
    case 8:
      digitalWrite(leds[0], LOW);
      digitalWrite(leds[1], LOW);
      digitalWrite(leds[2], LOW);
      digitalWrite(leds[3], LOW);
      digitalWrite(leds[4], LOW);
      digitalWrite(leds[5], LOW);
      digitalWrite(leds[6], LOW);
      digitalWrite(leds[7], HIGH);
      break;
  }
}
1 Like

I would help if I could but (and I hate to say this) I have literally no idea what you're trying to explain.

Sorry what is it you do not understand so i can help explain.

basically. i have a main count up button. when i press this, it starts counting from from 1 - 8. As it counts up it turns on an led 1 - 8 which represents the count number.

i then have 8 other buttons in a sort of group. when these buttons are pressed it changes the count relative to which button was pressed. so if button 3 was pressed it changes the current count position to 3 and lights up led 3. then continues counting from that position on to the next count with each press of the count up button.

if i press multiple buttons at the same time. like if i press buttons 1, 3 and 5 for example. it chooses a random led to light up depending on which button was technically hit last. It then continues counting from that point on each press of the count button.

What i want to do is hold buttons, for example, 1, 3 and 5. Then press the main count button and count through those chosen numbers only. lighting up leds 1, 3 and 5 one by one with every press of the count button.

From what you describe, I think that the whichButtonPressed loop may need to be revised.

In particular, I believe you have two different events that can lead to a LED transition: a release (rising edge detect) event on the forward input or a periodic timed event for the button sequence. I would probably create a separate flag ‚Äúadvance‚ÄĚ that is triggered by either of these two events.

It looks like you are trying to detect an edge of the buttonstate[whichButtonPressed] but from your description I believe you wanted the LED sequence to proceed while multiple buttons are pressed. Therefore, you probably just want to sample the current state and not worry about the last_buttonstate.

A couple suggestions for one way to approach your problem:

  • The case statement of 8 LEDs can be replaced by a simple for loop (set LED to LOW unless loop index matches Counter, in which case the LED is set to HIGH).
  • I would suggest separating out the button detection / edge detection from the LED sequence generator.
  • The detection function can look for falling edge (transition from HIGH to LOW) on the forward input and asserts an advance flag if detected.
  • This detection function would also maintain the current status (not edge detected) of the 8 other buttons. Capture the current value into buttonstate (don‚Äôt check for last_buttonstate). From this you‚Äôll have the currrent state of all 8 buttons. No update to the advance flag.
  • A separate check could then be periodically made to see if more than X milliseconds have elapsed since the last time advance was handled. If so, the advance flag is asserted. This causes the LED sequence to proceed if you are holding down multiple buttons.
  • Your main loop then checks the advance flag. If asserted, it would enter a while loop to increment (with wrap at 8 ) to find the next LED in the sequence. If the buttonstate[Counter] is not asserted, then it continues to increment Counter. Inside this while loop, no LED updates are made, as we are simply looking for the next LED in the sequence.
  • The while loop will exit once you have identified the next asserted buttonstate. You‚Äôll need to handle the no-button-pressed scenario too.
  • After leaving the while loop (when the next pressed button in the sequence has been found and Counter updated to equal this index), we can update the LED state and the advance flag can be deasserted.
  • This will lead back to the detection function and timer process.

Hope that helps

Impulsive. Thanks for your reply. I may need a while to figure out exactly what you are saying and how to respond to this. I have never used a flag yet. I am still a beginner. I will start on the for loop for the LEDs. I tried not comparing against last button state and just reading if low. But I had multiple LEDs light up at same time. I tried lots of different things like hardcoding each Individual button. I did if else statements. I tried a while loop but I must have not implemented properly. everything but what I tried had differences in how buttons reacted. Like multiple LEDs lighting at same time, flashing lights and nothing visible etc.

Do you know of any links or any documents that may help?

Give me some time to go over your post and try some things and i will return if you don't mind.

Thanks again.

I have never used a flag yet.

A flag is simply a variable that is set at some point in the code in order to control what code does in a later stage in the code.

Most of the time you use Boolean variables, they can be either true or false. So you might set a flag when you read a message from the serial port and then later look to see if you have a new message by checking the state of the flag.

If you want to do multiple things with a flag then they can be standard variables set to a number.

Grumpy Mike. Is a flag a function? I looked for some references on Arduino website but not much there. I tried Boolean instead of byte for all the buttons. But the buttons especially the forwards clock. It toggled through the LEDs very quickly instead of each time the button was pressed. The button group was fine but they held whatever led they where on and blocked the forwards count. I basically spent a week trying to o we come this fault.

No, a flag is not normally a function (you could embed the functionality of a flag in a class, with multiple functions, but that would normally be overkill).

A flag is simply a variable; if it is zero, it indicates the absence of something and if non-zero it indicates the presence of something.

You need to decide what absence or presence means in the context of your software.

Have you addressed the issues pointed out to you in reply#4?

If you have then post your code of how you think you addressed these. Also please post a schematic of how things are wired up.

The concept of a flag is not unique to an Arduino, nor any specific programming language. It is universal to the whole of programming.

Impulsive. Got to say I've been working at your post for last couple of days and the more I read the more confused I am. What do you mean by flag advance?

I defined a variable called button detection. It detects a state change from the forwards pin. It also reads the button state of the buttons. I don't know what to do with that information tho? Is flag advance just incrementing the counter?

You also say the main loop checks the advance flag. Does that mean I do all the button detection in the setup section?

What do you mean by flag advance?

It is a Boolean variable called "advance", it is used as a flag or a signal to another part of the program. You should be calling it "an advance flag"

You also say the main loop checks the advance flag. Does that mean I do all the button detection in the setup section?

No.

I defined a variable called button detection. It detects a state change from the forwards pin. It also reads the button state of the buttons.

A variable can not detect anything, do you mean a function?

See that very ugly switch statement in your code, it can be replaced by:-

void displayCount(byte count){
  for(int i = 0; i<8; i++){
    digitalWrite(leds[i], LOW);
  }
    digitalWrite(leds[count], HIGH);
}

This simply turns off all the LEDs and then turns on the LED number you pass to the function.
However your counter should be counting 0 to 7 and NOT 1 to 8, because the first element in an array is numbered 0.
So:-

if (Counter > 7) { // Count Amount (0-7)
    Counter = 0;
  }

What part of

Grumpy_Mike:
..... then post your code of how you think you addressed these. Also please post a schematic of how things are wired up.

Are you having problems with?

I have taken your code from the first post and written it in a better way. The logic of the code has not changed but it is split up into functions to make changing it simpler. I have also used a variable called "advance" as a flag. It gets set when the forward button is pressed and cleared when the forward button is released. When it is set your LEDs count, when it is cleared they do not. If this is not what you want to do then say so. You might want a press of the forward button to start counting and then a second press to stop it then that is easily changed.

I have not changed the logic in the "checkButtons" function because I still have no clear idea what you want to do there.

const byte leds[8] = {22, 23, 24, 25, 26, 27, 28, 29}; // Led Outputs
const int Forwards = 52; // Forwards input.
int advanceState; // Current State of counting button
int lastAdvanceState; // Last State of counting button
const byte buttons[8] = {40, 41, 42, 43, 44, 45, 46, 47}; //Button Inputs
byte buttonstate[8]; // current button state
byte last_buttonstate[8]; // last button state
int Counter = 0;   // counter
bool advance = false; // this is a flag to be used to indicate if we are counting or not

void setup() {

  for (int i = 0; i < 8; i++) //Set all the INPUTS and OUTPUTS.
  {
    pinMode (buttons[i], INPUT_PULLUP);
    pinMode(leds[i], OUTPUT);
  }
  pinMode (Forwards, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  checkForwardButton();
  checkButtons();
  if( advance == true){ // if we need to count then do so
    count();
    Serial.println(Counter);
    displayCount(Counter);
   delay(500); // to slow the count down so you can see it
  }
}

void checkForwardButton(){   //FORWARDS
  advanceState = digitalRead(Forwards); // Reads forwards pin
  if (lastAdvanceState != advanceState) { // Indicates state change of forwards
    if (advanceState == LOW) { //forwards button has become on - so set flag
      advance = true;
    } else {
      advance = false; // forwards button has become off - so clear the flag
    }
    delay(50);// Delay a little bit to avoid bouncing
  }
  lastAdvanceState = advanceState; // save the current state as the last state,
}

void count(){
  if (Counter > 7) { // Count Amount (1-8)
    Counter = 0;
  }
}

void checkButtons() {
  // BUTTONS

  for (int setWhichButton = 0; setWhichButton < 8; setWhichButton++)
  {
    buttonstate[setWhichButton] = digitalRead(buttons[setWhichButton]);  //reads buttonstate of buttons.
  }

  for (int whichButtonPressed = 0; whichButtonPressed < 8; whichButtonPressed++)
  {
    if (buttonstate[whichButtonPressed] != last_buttonstate[whichButtonPressed]) {
      if (buttonstate[whichButtonPressed] == LOW) { // What button is pressed
        Counter = whichButtonPressed + 1; // Counter is the same as the button pressed... +1 to work with switch.
      } else {
        (buttonstate[whichButtonPressed] == HIGH); // No button pressed
      }
      last_buttonstate[whichButtonPressed] = buttonstate[whichButtonPressed];
    }
  }
}

void displayCount(byte count){
  for(int i = 0; i<8; i++){
    digitalWrite(leds[i], LOW);
  }
    digitalWrite(leds[count], HIGH);
}

This compiles but I have not run it.

Thank you very much Grumpy Mike for your updated code. I will load it up asap and try to understand what is going on.

With regards to not posting my previous code. I did do the for loop for the leds. but then i got stuck and couldn't go any further. Didn't think it was worth posting to be honest. But here it is just to show that i did it and i am trying.

const byte leds[8] = {22, 23, 24, 25, 26, 27, 28, 29}; // Led Outputs
const int Forwards = 52; // Forwards input.
int ForwardState; // Current Forwards State
int LastForwardState; // Last Forwards State
int buttonDetection;
int LastbuttonDetection;
const byte buttons[8] = {40, 41, 42, 43, 44, 45, 46, 47}; //Button Inputs
byte buttonstate[8]; // current button state

int Counter = 0;   // counter


void setup() {

  for (int i = 0; i < 8; i++) //Set all the INPUTS and OUTPUTS.
  {
    pinMode (buttons[i], INPUT_PULLUP);
    pinMode(leds[i], OUTPUT);
  }
  pinMode (Forwards, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {

  //Forwards

  ForwardState = digitalRead(Forwards); // Reads forwards pin

  if (ForwardState != LastForwardState) { // Indicates state change of forwards
    if (ForwardState == LOW) { //Forwards is on.
      Counter++;  
    } else {
      (ForwardState == HIGH); // forwards is off.
    }
    delay(50);// Delay a little bit to avoid bouncing
  }
  LastForwardState = ForwardState; // save the current state as the last state,

  if (Counter > 7) { // Count Amount (1-8)
    Counter = 0;
  }

  //Leds

  for (int setLed = 0; setLed < 8; setLed++)
    if (setLed == Counter) {
      digitalWrite(leds[setLed], HIGH);
    } else {
      digitalWrite(leds[setLed], LOW);
    }

  //Button Detection

  buttonDetection = digitalRead(Forwards); // Reads forwards pi

  if (buttonDetection != LastbuttonDetection) { // Indicates state change of forwards
    if (buttonDetection == LOW) { //Forwards is on.
      Serial.println("flag advance"); //Not sure what this means just wanted to know if it did something.
    } else {
      (buttonDetection == HIGH); // forwards is off.
    }
    LastbuttonDetection = buttonDetection; // save the current state as the last state,
  }
  
     for(int i = 0; i < 8; i++)
{
    buttonstate[i] = digitalRead(buttons[i]); }    // read the state of the pushbutton value:
      for(int i = 0; i < 8; i++)
{
    if (buttonstate[i] == LOW) {                 // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
     Serial.println("buttonstate");
  }
}
}

Thanks for your help again Grumpy Mike. I can understand why your so grumpy. haha.

I loaded up your code mike. Thanks very much. I really appreciate it. Feel like i may have learned a new way to code. I think i understand.

It didn’t quite work the way i wanted it to…So i made a few adjustments to get me back to original functionality. Just wanted to run it past you and ask if it was correct way of doing it?

const byte leds[8] = {22, 23, 24, 25, 26, 27, 28, 29}; // Led Outputs
const int Forwards = 52; // Forwards input.
int advanceState; // Current State of counting button
int lastAdvanceState; // Last State of counting button
const byte buttons[8] = {40, 41, 42, 43, 44, 45, 46, 47}; //Button Inputs
byte buttonstate[8]; // current button state
byte last_buttonstate[8]; // last button state
int Counter = 0;   // counter
bool advance = false; // this is a flag to be used to indicate if we are counting or not

void setup() {

  for (int i = 0; i < 8; i++) //Set all the INPUTS and OUTPUTS.
  {
    pinMode (buttons[i], INPUT_PULLUP);
    pinMode(leds[i], OUTPUT);
  }
  pinMode (Forwards, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  checkForwardButton();
  checkButtons();
  if( advance == true){ // if we need to count then do so
    count();
    Serial.println(Counter);
    displayCount(Counter);
  
  }
}

void checkForwardButton(){   //FORWARDS
  
  advanceState = digitalRead(Forwards); // Reads forwards pin
  if (lastAdvanceState != advanceState) { // Indicates state change of forwards
    if (advanceState == LOW) { //forwards button has become on - so set flag
      advance = true;
      Counter++;
    } else {
      advance = false; // forwards button has become off - so clear the flag
    }
    delay(50);// Delay a little bit to avoid bouncing
  }
  lastAdvanceState = advanceState; // save the current state as the last state,
}

void count(){ // Counter
  if (Counter > 7) { // Count Amount (1-8)
    Counter = 0;
  }
}

void checkButtons() {  // BUTTONS

 for (int setWhichButton = 0; setWhichButton < 8; setWhichButton++)
  {
    buttonstate[setWhichButton] = digitalRead(buttons[setWhichButton]);  //reads buttonstate of buttons.
  }

  for (int whichButtonPressed = 0; whichButtonPressed < 8; whichButtonPressed++)
  {
    if (buttonstate[whichButtonPressed] != last_buttonstate[whichButtonPressed]) {
      if (buttonstate[whichButtonPressed] == LOW) { // What button is pressed
        advance = true;
        Counter = whichButtonPressed; // Counter is the same as the button pressed... +1 to work with switch.
      } else {
        (buttonstate[whichButtonPressed] == HIGH); // No button pressed
        advance = false;
      }
      last_buttonstate[whichButtonPressed] = buttonstate[whichButtonPressed];
    }
  }
}


void displayCount(byte count){
  for(int i = 0; i<8; i++){
    digitalWrite(leds[i], LOW);
  }
    digitalWrite(leds[count], HIGH);
}

As you can see i got rid of the count delay and added a Counter++ to the advance state function and and advance == true in the buttons. As it was. i held the the forwards button and was able to advance to a button from the group. Now the leds advance on every forwards press and pressing a button from the group.

Now i am back where i started, but with a more elegant code.

Could i ask my original question again but in a language i understand. Sorry for breaking rules of forum. Grumpy Mike, my understanding is that you know about musical instrument design. I am making an 8 step sequencer. Bare bones at the moment.

The forwards Pin…Will be an external +5v pulse generated from a sequencer or clock source etc.
It will then step through 8 leds sequentially from 0-7. Then if a button or group of buttons is pressed from the button group. it will arpeggiate through those pressed buttons only. e.g.: if buttons 2, ,5 and 6 are pressed. it steps through led 2, 5 and 6 everytime it receives a pulse from the forwards pin. I am just using a button to minimise other equipment. Like a clock source.

I am grateful for all the help you’ve given me so far mike and i hope you can help a little more.
I don't necessarily need code written. Even though i do understand more when its written i front of me. Some the language used on this forum is out of my comfort zone. I would just like some guidance. Such paths to take and things to research.

Thanks for your time.

Just wanted to run it past you and ask if it was correct way of doing it?

Thing about programming is there are lots of ways of doing it right. What you have put looks fine.

Some the language used on this forum is out of my comfort zone.

If you find yourself not understanding what some one said then please ask them to explain the bits you understand. We are more than willing to do that. Sometimes we don’t realise we are using jargon and we need reminding.

I am making an 8 step sequencer.

Ah, that would have been good to know earlier it would have put your request in context for us.

my understanding is that you know about musical instrument design.

A bit.
Here is a link to my book

and i hope you can help a little more.

Yes no problem. Is this a MIDI project?

No Mike this is not a midi project. I do not use midi in my system. It is a eurorack modular synth that uses -5/+5v control voltage. Otherwise, I would have bought your book ages ago. I guess this is why I am finding it so difficult to find documentation on the subject. I looked into building an arpeggiator but they were all midi based. Was seeing if it could be done without before before going down the midi route.

Yes it could be done but CV synths were old hat 30 years ago which is why there is little information on them.

The main problem in this digital age is the need for a split power supply, that is both positive and negative voltages. This makes the output tricky. For the output you first need a real D/A converter followed by an op amp with a times two gain and a level shift.

They use one volt per octave so the full +/-5V range would cover ten octaves which I think is more than you need. Normally there is a tuning pot to give the overall control over tuning. Without doing the sums I think a 10 bit D/A would do it unless you are into micro intervals. Using only voltages 0 to 5V would be a piece of cake but to get the extra requires a bit more work.

Assuming you only need one control output, is this right?

Yes I am fully aware of this. But I only need +5v for this particular prject. I will get to what you have just spoke about in good time. But at the moment I have built a prototype that works without dac. I have pots on each output to vary the amount of voltage sent to the synth. It needs to be able to sweep through full 5v. Crude but I have been using it for a few months now and it's very useful. I stripped it back to bare bones to add a sequencer section. Because at the moment it just uses a button group press or a CV input to control the which Step is playing. So no sequencer.

I just want to consentrate on getting the sequencer and the buttons to work he I want before moving on.

Just to add the buttons are not necessarily notes played on a keyboard. They are just stored voltages just to change stuff in the system.