Blynk Button unusable after running function once

After much research and searching both here at BC and abroad, I have been able to accomplish my goal of running a stepper motor using Blynk - yay!

My next objective (and issue) is rather simple - to be able to click a Blynk button (assigned to V1 in this case) to enable the stepper motor to rotate CW 90 degrees and stop. Then, through the use of another button (assigned V2), enable the motor to rotate CCW 90 degrees. I have been able to code in these operations and they are functional, but only allow this action to occur once per direction (aka per button).

With the current code below, when I push the (V1) Button in Blynk to “ON”, the stepper motor rotates CW 90 degrees and stops, and the Blynk app Button is switched back to “OFF” (via “Blynk.virtualWrite”). However, the Blynk button is not able to switch to “ON” after this first rotation has been executed, almost like I am locked out of using the button to repeat the motor action. Likewise, the identical situation occurs with the (V2) Button that is for CCW (makes sense, as the code for CCW is the same structure).

I have a feeling it is something wrong with the FlagState, but not sure as I am not too savvy yet with coding. Any help or guidance would be greatly appreciated! Let me know if there are any questions or additional info that would help or clarify. I did put comments to help explain what I believe is going on.

EDIT: rearranged the functions so they are more organized…

Hardware: NodeMCU + WiFi (via built in ESP)

Below is my code in its entirety:


#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
BlynkTimer timer;
#include <AccelStepper.h>
#define HALFSTEP 8

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "xxxxxxxxxxxx";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "xxxxxxxx";
char pass[] = "xxxxxxxx";

// Motor pin definitions
#define motorPin1  14     // IN1 on the ULN2003 driver 1
#define motorPin2  12     // IN2 on the ULN2003 driver 1
#define motorPin3  13     // IN3 on the ULN2003 driver 1
#define motorPin4  15     // IN4 on the ULN2003 driver 1

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
AccelStepper stepperCW(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
AccelStepper stepperCCW(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);


// Global variables
int CWFlagState = 0;      // used to lock out subsequent button presses
int CCWFlagState = 0;     // used to lock out subsequent button presses

void setup() {
  Serial.begin(115200);
  Blynk.begin(auth, ssid, pass);
  // *** ClockWise motor parameters used by AccelStepper ***
    stepperCW.setMaxSpeed(5000);          // Maximum speed setting
    stepperCW.setAcceleration(100);       // Acceleration setting
    stepperCW.setSpeed(5000);             // Normal speed setting
    stepperCW.move(1024);                 // value in steps (+/-); 4096 steps is 360 degrees
  // *** ClockWise motor parameters used by AccelStepper ***
    stepperCCW.setMaxSpeed(5000);         // Maximum speed setting
    stepperCCW.setAcceleration(100);      // Acceleration setting
    stepperCCW.setSpeed(5000);            // Normal speed setting
    stepperCCW.move(-1024);               // value in steps (+/-); 4096 steps is 360 degrees
}

BLYNK_WRITE(V1) {
  int pinValue = param.asInt();
  if(pinValue == 1 && CWFlagState == 0) {     // if V1 button is pushed to "ON" & CWFlagState=0...
    CWFlagState = 1;                          // sets CWFlagState=1 - lock out subsequent button pushes...
    timer.setTimer(1L, runStepperCW, 20000);  // ...and then rotate Stepper motor CW
  }
}

void runStepperCW() {                     // This function runs when V1=1 and CWFlagState=0
    stepperCW.run();                      // Runs the AccelStepper for Clockwise rotation
    if(stepperCW.distanceToGo() == 0) {   // If Stepper reaches its target...
      stepperCW.stop();                   // Stepper is set to stop
      CWFlagState = 0;                    // Set the CWFlagState to 0
      Blynk.virtualWrite(V1, 0);          // Sets V1 to 0 (resets the button to "OFF")
    }
  }

BLYNK_WRITE(V2) {
  int pinValue = param.asInt();
  if(pinValue == 1 && CWFlagState == 0) {     // if V2 button is pushed to "ON" & CCWFlagState=0...
    CCWFlagState = 1;                         // sets CCWFlagState=1 - lock out subsequent button pushes...
    timer.setTimer(1L, runStepperCCW, 20000); // ...and then rotate Stepper motor CCW
  }
}

void runStepperCCW() {                    // This function runs when V2=1 and CCWFlagState=0
    stepperCCW.run();                     // Runs the AccelStepper for CounterClockwise rotation
    if(stepperCCW.distanceToGo() == 0) {  // If Stepper reaches its target...
      stepperCCW.stop();                  // Stepper is set to stop
      CCWFlagState = 0;                   // Set the CCWFlagState to 0
      Blynk.virtualWrite(V2, 0);          // Sets V2 to 0 (resets the button to "OFF")
    }
  }

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

I don’t use Blynk timer, so I don’t have any firsthand experience to call on, but your timers look a bit odd to me.

There’s no timer declaration in void.setup (not sure if that’s an issue or not) but this bit seems very strange…

You’re calling the runStepperCWfunction once every millisecond for 20,000 repetitions - See this documentation:
https://playground.arduino.cc/Code/SimpleTimer#Functions

runStepperCW will take more than 1ms to execute, but if it were able to do that you’d be trying yo execute a Blynk.virtualWrite(V2, 0); command 20,000 times in short succession.

Maybe you actually meant to have a 20,000 milliseconds (20 second) timer that runs once? If so then maybe a setTimeout timer would be the better choice?

Apologies if I’m misunderstanding how the timer works, but I think that’s where you should be concentrating your debugging efforts.

Pete.

Thanks for the speedy response @PeteKnight.

I can see what you are talking about, having a short interval and high repetitions is not graceful, and I’m actually surprised the motor works with this setup. Although I don’t believe virtualWrite gets called 20k times, as the “if” condition that determines its execution has not been met until the motor’s “distanceToGo” = 0, which does occur once the motor makes its 90 degree movement.

The stepperCW.run(); works flawlessly when put in the void loop of an arduino uno (no blynk used). I believe the AccelStepper needs to be called very often while in movement, and I don’t know how to loop things while using Blynk, although I have tried to research how to no avail. The Timer is a way to keep returning to the stepping function 20,000 times to complete all its steps - otherwise, without using a timer, when I push the Blynk widget button using BLYNK_WRITE, it only moves the motor by one step per click of the button.

The fact that the button is not able to be pressed again makes me think that the FlagState could be coded wrong, locking me out of the button, but I’m open to trying an alternative way. maybe I’ll try without flags first. I will look into the link you posted, and perhaps declare the timer in void setup (), and will also tinker with using different timer setups and values.

I’ll post back here when I get some results to share. Any other ideas, feel free to post in the meantime.

1 Like

Well he did declare the timer (line 4) but it will lock Blynk as when the “pinValue” goes HIGH it’ll run (well, call the function) every millisecond for 20000 times…
I think that you dont even need the timer as you just call the function ( runStepperCW(); ) and instead of using stepperCW.run(); try stepperCW.moveTo(1024); this way it will stop when it reaches its final position.

1 Like

https://community.blynk.cc/search?q=AccelStepper.h

Maybe one of these posts will help.

One of my favorite places to start when looking for help with BLYNK is their search function.

4 Likes

Sorry for the delay, I’ve been busy reworking coding and rethinking the core schematics of what I am trying to accomplish. I read a post from Costas about the demands of steppers, and realized that utilizing my Arduino Mega as a dedicated stepper slave would be much less taxing on my main MCU that is connected to Blynk.

My solution: On push of button widget, I send a “HIGH” signal from a digital pin on the NodeMCU to a digital input on the Mega to begin the stepper function. I can then have the various stepper.run(); commands stay in the loop as suggested in the AccelStepper documentation. Less headaches, and it runs like a champ.

Thanks for the replies and support! Learning a lot from the community forum posts too :slight_smile: