Exiting a "WHILE" loop from a Blynk Button Push

Hello Forum,

I am trying to drive a vibrator motor in an “infinite” loop when “BUTTON #1” is pressed. And then I want to stop the vibrator motor when “BUTTON #2” is pressed.

I am trying to run the vibrator motor in a pattern like “buzz-buzz-buzz…pause…buzz-buzz-buzz…pause…buzz-buzz-buzz…pause,” etc…

I have looked at many examples on the forum, but every answer looks like it “sideskirts” this question of how to exit the “WHILE” loop with another button press. I am just not sure how to use a timer to do this.

Please see my code below. I have left out the preprocessor directives and other stuff just to focus on what I think is the central problem…I just don’t know/understand the proper resources and/or syntax to do this.

I am using an Arduino Pro Mini 3.3V with an HC-06 Bluetooth module.

TIA,
–Neal

void loop()
{
   Blynk.run();
}

BLYNK_WRITE(V0)
{
   int pinValue = param.asInt();            //get pin value from button press
   if(pinValue == 1)runMotor();             //RUN motor forever until other button is pressed
}

BLYNK_WRITE(V1)
{
   int pinValue = param.asInt();           //get pin value from button press
   if(pinValue == 1)stopMotor();          //STOP motor forever until other button is pressed
}

void runMotor(void)
{
   //pseudocode   
   //run motor code here
   //while(1) buzz-buzz-buzz...pause
}

void stopMotor(void)
{
   //stop motor code here
}

while loops can be very useful, but are generally best avoided when using Blynk. The reason for this is that code execution is limited to that while loop until the condition you specify becomes true, and this (a) prevents the void loop from executing and (b) prevents the BLYNK_WRITE callbacks from executing.

You can overcome the effect of (a) by adding Blynk.run to your while loop, but that isn’t the real solution.

Personally, I’d have a for loop that did the “buzz-buzz-buzz” bit by repeating a HIGH/LOW pulse three times.
I’d call that ‘for` loop using a timer, probably every 4 seconds or so, which will generate the gap between one set of triple buzzes and the next.

There are a number of approaches you could use, such as starting this 4 second timer when you want the buzzing to start and stopping or deleting the timer when you want it to end.
However, the simplest approach (but the one that will annoy the purist coders the most) is simply to have the timer running all the time. The function that the timer calls would begin by checking if a global ‘trigger-the-buzzer’ variable is true or not. If it is then the for loop executes, if it’s not then nothing happens.
You’d set the ‘trigger-the-buzzer’ variable to true or false with your BLYNK_WRITE callbacks.

Pete.

Dear Pete,

Thank you for your prompt reply. I am now in the process of creating a global variable for trigger-the-buzzer.

My requirements are even a bit more complicated as I have several other “buzz” patterns, so I might have big buzz-big buzz-big buzz-pause-small buzz and other different patterns. I am working at 2 tiered functions with counters that won’t allow the second set of buzzes until the first set of buzzes has been executed. I then reset the counters when finished and then start the pattern over again if the state has not changed.

I will post some code once I have this fully figured out.

Thank you.
–Neal

Dear Pete,

I still really haven’t figured out how to get 3 different patterns like:

buzz-buzz-buzz-pause, buzz-buzz-buzz-pause, buzz-buzz-buzz-pause, etc.

long buzz-long buzz-long buzz-short pause-buzz, long buzz-long buzz-long buzz-short pause-buzz, etc.

…and a couple of other patterns.

I have created a state variable that changes based upon which SEGMENTED BUTTON is pressed. When I return to loop(), I have some conditionals that call the “buzzing” functions to vibrate each of the patterns. As long as the state variables don’t change, the “buzzing” functions should continue to repeat themselves.

When I press another SEGMENTED BUTTON, the pattern should change to whatever pattern is associated with the new button.

I am avoiding execution-halting delays and only using non-blocking delays.

void loop()
{
   Blynk.run();
   timer.run();
   if(state == 1)program1();  //off
   if(state == 2)program2();  //manual mode with duty cycle slider adjustment
   if(state == 3)program3();  //program 1 - buzz-buzz-buzz-buzz-buzz....
   if(state == 4)program4();  //program 2 - long buzz-long buzz-long buzz-pause
   if(state == 5)program5();  //program 3 - short buzz-long buzz-short-buzz-pause
}

When I apply the “buzz”, I ramp up and then ramp down using the code. I basically use y=mx+b equation of a line. On the Y-axis, I used Ymax (=255) and Ymin (equal to let’s say 100). The period is anywhere from 50-500 ms depending on how fast I want the “buzz” pulses. This is a pseudo sine wave (linear approximation for simplification). I basically get a sawtooth pattern in the time domain. I might convert to a sine wave in the future, but this is good for now.

int vibrateMotor(void)
{
  long m, b;
  long x, y;
  m = (Ymax-Ymin)/(period/2.0);
  b = Ymin;
  
  for(x=0; x<period/2.0; x++)
  {
     analogWrite(VIB, m * x + b);              //increase pwm
     Blynk.virtualWrite(V3, m * x + b);       //sending to Blynk gauge
  }
  
  b = Ymax + m * period/2.0;                   //new y-intercept  for decreasing pwm
  for(x=period/2.0; x<period; x++)
  {
     analogWrite(VIB, -m * x + b);             //decrease pwm
     Blynk.virtualWrite(V3, -m * x + b);      //sending to Blynk gauge
  }
}

My simplest program is just a sawtooth pattern with no pause inbetween. The period seems corrupted. I tried 500ms, but this went extremely slow. So I kept decreasing until I got this to repeatedly vibrate. It works much better with a period of 50ms rather than 500ms.

int program3(void)                                //state=3, buzz-buzz-buzz-buzz-buzz-buzz,...
{
  digitalWrite(LED_BUILTIN,HIGH);
  period = 50.0;                                     //this is 50L
  timer.setInterval(period, vibrateMotor);
}

I then tried to make varying buzz periods back to back and tried a few things like this:

int program4(void)                                //state=4 buzz-buzz-buzz-pause, buzz-buzz-buzz-pause,...
{
   if(x<3)
   {
      program4a();       //3 buzz cycles
      x++;
   }
   if(x==3 && y<1)       //1 pause cycle
   {
      program4b();
      y++;
   }
   if(x==3 && y==1)      //reset x and y
   {
      x=0;
      y=0;
   }
}

int program4a(void)            //3 buzzes of this
{
  period = 150;
  magnitude = 255;
  timer.setInterval(period, vibrateMotor);
}

int program4b(void)           //...and one pause of this
{
  period = 100;
  magnitude = 0;
  timer.setInterval(period, vibrateMotor);  
}

I cannot seem to “break” out of the buzz-buzz-buzz functions. I am not really sure how to structure this.

Any suggestions would be greatly appreciated. Thank you.

–Neal

Having these if statements in your void loop are the wrong approach. They will cause problems with Blynk in the long term.

As I said before, your BLYNK_WRITE command(s) associated with your switch widget(s) (you were originally talking about two, one for on and one for off, but now appear to be using a single segmented switch) should be setting a global flag variable, which is checked either at the start of the buzz function, ort before each buzz is generated.

Pete.

Have you considered using an existing library that is designed for tone generation?

Pete.

Dear Peter,

This is a GREAT idea!!!

I have tried several different tone generation libraries and they all conflict with the other timers being used by Blynk and AltSoftwareSerial.

I tried the integrated tone() function in the Arduino IDE. The PWM duty cycle is limited to 50%, and this does not work well with my application as I am trying to generate stronger vibration/buzzing.

I have also tried the Volume libraries and these also conflict.

My program just started resetting after about 6 seconds. I do not know what changed to make my code reset.

TIA,
–Neal

Dear Pete and Forum,

I solved the resetting issue. I got lazy with my solderless breadboard circuit and failed to put a capacitor and flyback diode in the circuit. I just placed these compoents into my circuit and this has solved the resetting issue.

Now I just need to focus on the non-blocking delays for motor pulse patterns (buzzing patterns of the vibrator motor).

–Neal