Need to wait until end of Function?

Hi

Following my work on trying to understand the 4051 Multiplexer (also discussed - and MUCH helped - in this thread: Understanding the 4051Multiplexer code - Programming Questions - Arduino Forum) my next step is to have 8 buttons on a 4051 Multiplexer lighting 8 LEDs on a 74HC595 Shift Register.

I found a nice library (Shifter - http://bildr.org/2011/08/74hc595-breakout-arduino/) that greatly simplifies the process of using the shift register.

What am i trying to achieve?
When i press a button, i would like for the corresponding led to blink 3 times. So if i press button1 led1 should blink 3 times, if i press button4 led4 should blink 3 times,...

At the moment my code is like this:

#include <ClickButton.h>
#include <Shifter.h>

const int buttonPin = A0;
int buttonValue[8] = {0,0,0,0,0,0,0,0};
int lastButtonValue[8] = {0,0,0,0,0,0,0,0};
int b0 = 0;
int b1 = 0;
int b2 = 0;

#define SER_Pin 7       // SER_IN
#define RCLK_Pin 6      // L_CLOCK
#define SRCLK_Pin 5     // CLOCK
#define NUM_REGISTERS 1 //how many shift registers are in the chain

// Initialize Shifter using the Shifter library
Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS);

void setup() {
  pinMode(10,OUTPUT); // S0
  pinMode(9, OUTPUT); // S1
  pinMode(8, OUTPUT); // S2
  
  Serial.begin(115200);
} // end void setup

void loop() {
  for (int buttonCount = 0; buttonCount < 8; buttonCount++){
    b0 = bitRead(buttonCount,0);
    b1 = bitRead(buttonCount,1);
    b2 = bitRead(buttonCount,2);
    
    digitalWrite(10,b0);
    digitalWrite(9,b1);
    digitalWrite(8,b2);
    
    buttonValue[buttonCount] = digitalRead(buttonPin);
    if (buttonValue[buttonCount] == CLICK_SINGLECLICK && buttonValue[buttonCount] != lastButtonValue[buttonCount]) {
      Serial.println(buttonCount);
      ledBlinkSlow(buttonCount); 
    }
    lastButtonValue[buttonCount] = buttonValue[buttonCount];
  } // end buttonCount
} // end void loop

void ledBlinkSlow (int led2light) {
  shifter.setPin(led2light,HIGH);
  shifter.write();
  delay(200);
  shifter.clear();
  shifter.write();
  delay(200);
  shifter.setPin(led2light,HIGH);
  shifter.write();
  delay(200);
  shifter.clear();
  shifter.write();
  delay(200);
  shifter.setPin(led2light,HIGH);
  shifter.write();
  delay(200);
  shifter.clear();
  shifter.write();
}

The code is more or less working as i wanted.
When i press a button the corresponding LED blinks.

But the problem is that while that LEDS is blinking nothing else can happen. It needs to wait until the ledBlinkSlow Function is over before it can go on...
Is there a way to make it so that each "button+led" can be independent of the others? That i can press a button while another is already blinking?
(i will probably use this on a midi foot controller, so i wouldn't want to have to wait a second between button pushes!)

I hope you understand what i mean...
Thanks!

Take a look at the "Blink Without Delay" example in the IDE's File->Examples menu.

You'll see that it has replaced the delay() calls with comparisons of the millis() function.

i tried doing the same and using also a comparison between millis()
like this:

void ledBlinkSlow (int led2light) {
   shifter.clear();
   shifter.write();
   while (blinks[led2light] < 6) {
      unsigned long currentMillis = millis();

      if(currentMillis - previousMillis > interval) {
         previousMillis = currentMillis;

         if (ledState[led2light] == LOW) 
            ledState[led2light] = HIGH;
         else
            ledState[led2light] = LOW;

         shifter.setPin(led2light,ledState[led2light]);
         shifter.write();
         blinks[led2light]++;
      }
   }
   blinks[led2light] = 0;
}

i used the code inside WHILE conditional because i want it to blink only three times.

But now still the same is happening.
When i press a button the corresponding LED blinks, but until it finishes blinking i can't do anything else

boguz:
i tried doing the same and using also a comparison between millis()
like this:

void ledBlinkSlow (int led2light) {

shifter.clear();
  shifter.write();
  while (blinks[led2light] < 6) {
     unsigned long currentMillis = millis();

if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis;

if (ledState[led2light] == LOW)
           ledState[led2light] = HIGH;
        else
           ledState[led2light] = LOW;

shifter.setPin(led2light,ledState[led2light]);
        shifter.write();
        blinks[led2light]++;
     }
  }
  blinks[led2light] = 0;
}



i used the code inside WHILE conditional because i want it to blink only three times.

But now still the same is happening.
When i press a button the corresponding LED blinks, but until it finishes blinking i can't do anything else

You can't use while, or for statements as they are still blocking. What you need to do is separate the blinking logic from the control logic. Say you start with the simple Blink Without Delay:

if (millis() - lastMillis >= interval)
{
  lastMillis = millis();
  digitalWrite(ledPin, !digitalRead(ledPin));
}

That would sit in your loop() body. In this case it would run uninhibited. Let's say you wanted it to blink a certain amount of times using a variable:

static int numBlinks = 0;

if ( (numBlinks > 0) && (millis() - lastMillis >= interval) )
{
  lastMillis = millis();
  digitalWrite(ledPin, !digitalRead(ledPin));
  numBlinks--;
}

Now, when some condition occurs elsewhere in your loop, you can set the numBlinks variable for the appropriate amount of blinks:

if (someCondition)
{
  numBlink = 5 * 2; // blink it 5 times
}

Of course the same is happening. What you have done there is basically recreate the delay() function.

You need to stop thinking of the blinking as an event in its own right, and instead start thinking about the transitions between off and on, and when they should occur.

I would suggest your main loop keeps a counter for each LED (in an array) of the number of blinks left for that LED. Then you have a "blink" variable that toggles at the blinking frequency, driven by millis(). When blink toggles you turn on (or off, depending on the value of blink) any LEDs that have a blink count greater than 0, then decrement those blink counts by 1.

When you press a button all you do is set the blink count for the associated LED to 3.

All the LEDs that need to blink will then blink together, nice and synchronised.

If you want them to have their own time bases, then you will need to replicate the blink toggling code for each LED, so as well as a blink counter for each LED you will need a blink time for each LED (also an array), which you then compare with millis() as per BlinkWithoutDelay.

ah, i think i understand it. THANKS!

Let me see what i can get... :wink:

Well, i am sure this is not the best or most elegant code, but i'm still trying to learn and this was what i could come up with.

void loop() {
  for (int buttonCount = 0; buttonCount < 8; buttonCount++){
    b0 = bitRead(buttonCount,0);
    b1 = bitRead(buttonCount,1);
    b2 = bitRead(buttonCount,2);
    
    digitalWrite(10,b0);
    digitalWrite(9,b1);
    digitalWrite(8,b2);
    
    buttonValue[buttonCount] = digitalRead(buttonPin);
    if (buttonValue[buttonCount] == CLICK_SINGLECLICK && buttonValue[buttonCount] != lastButtonValue[buttonCount]) {
      Serial.println(buttonCount);
      ledBlinks[buttonCount] = 6; //number of blinks time 2
    }
    lastButtonValue[buttonCount] = buttonValue[buttonCount];
    
    currentMillis[buttonCount] = millis();
    if (ledBlinks[buttonCount] > 0) {
      if(currentMillis[buttonCount] - previousMillis[buttonCount] > interval) {
        previousMillis[buttonCount] = currentMillis[buttonCount];
        if (ledBlinksStates[buttonCount] == LOW) {
          shifter.setPin(buttonCount, HIGH);
          shifter.write();
          ledBlinksStates[buttonCount] = HIGH;
        } else if (ledBlinksStates[buttonCount] == HIGH) {
          shifter.setPin(buttonCount, LOW);
          shifter.write();
          ledBlinksStates[buttonCount] = LOW;
        }
        ledBlinks[buttonCount]--;
      }
    }
  } // end buttonCount
  
} // end void loop

What do you say about it?

There is still something i think i will change.
When a button is blinking, if i press it again during a HIGH state (while the LED is on) then the blink counting will restart, which mean it will end also with a HIGH state and at the end of the blinking it will leave the LED on.

To fix it, instead of

      ledBlinks[buttonCount] = 6; //number of blinks time 2

could i do

if (ledBlinks[buttonCount] % 2 == 0) {
   ledBlinks[buttonCount] = 6; //number of blinks times 2
} else if (ledBlinks[buttonCount] % 2 == 1) {
   ledBlinks[buttonCount] = 7; //number of blinks times 2 + 1
}

Would something like this work?
Any other ideas?

Thanks!

You have the LEDs and the buttons so you know if it works.

The code structure for the millis-timer part looks right, (I dont know what "shifter" does, and the hardware outputdigitalWrite(b0..b2) does, so I am ignoring those for the moment) but you keep doing the code structure (I have replaced LOW and HIGH with right/left to make the point clearer)

if ( test-for-left ) 
 {  code  }
else if ( test-for-right ) 
 { code }

Well, it is either "right" or "left", it can not be anything else, so the second
** **if** **
is redundant you can have just the
** **else** **
. (As we have just testet it is left, and we only get to to else if it is "not-left", ie "right".)

The second question I leave to you experiment, and it really depends on your defenition of what it is supposed to do. Is a button push ignored until the blinks have finished, or another 3 blinks are added or whatever. If you do want to "start a fresh sequence" I suggest

if ( ledBlinksStates[buttonCount] == HIGH ) ledBlinks[buttonCount] = 7 ; else ledBlinks[buttonCount] = 6 ;

Msquare:
You have the LEDs and the buttons so you know if it works.

Sorry, i wasn't at home and was just "thinking loud"...

i tried now the code and it is working as i wanted. When i click the button it blinks 3 times, even if i click it already when it is blinking.

Ah, the shifter part, well, that is the code for the library i am using to control the LEDs on the shift register.
THANKS!
=)