(28BYJ-48) Blocking to Non-Blocking Code w/Accelstepper

I'm somewhat of a newbie and I have been trying to convert my code from a sketch using blocking code with the Arduino stepper library to the accelstepper library. So far I have been unsuccessful and have tried many different iterations with different results most of the time.

My devices are as follows:

  • Arduino Mega 2560 w/ built-in ESP8266
  • 8BYJ-48 Stepper Motor w/ ULN2003 Motor Driver
  • 2.4" TFT LCD Screen

I am making a wirelessly controlled watch winder that has a preset function, and a custom function that controls the number of rotations and delay between them. These functions can be controlled via the touch screen or a custom Blynk Android application.

Code using Arduino stepper library (blocking):

This code has been tested and the motor functions correctly from the testing I have done on it so far. The menu is slightly more complex as well.

//LCD Touch Screen 
//Include the LCD Screen Libraries
#include "SPFD5408_Adafruit_GFX.h"    // Core graphics library
#include "SPFD5408_Adafruit_TFTLCD.h" // Hardware-specific library
#include "SPFD5408_TouchScreen.h"

//Pin Assignments
#define YP A3 
#define XM A2  
#define YM 9  
#define XP 8   

//Calibrated Touch Values
#define TS_MINX 87
#define TS_MINY 108
#define TS_MAXX 956
#define TS_MAXY 964

//Touch Screen Initialization
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_RD    A0
#define LCD_WR    A1
#define LCD_CD    A2
#define LCD_CS    A3
#define LCD_RESET A4
 #define BOXSIZE   40  
 #define PENRADIUS  3  
 #define MINPRESSURE 10  
 #define MAXPRESSURE 1000  
 #define LED_PIN   13  
 
//Initialize TFT Object
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// Assign human-readable names to some common 16-bit color values:
#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

//Touch Screen Variables
int currentPage = 0; //variable to keep track of which menu page is to be displayed

bool touchLatch1 = false; //latch for default function loop
bool touchLatch2 = false; //latch for custom function loop


//Include the Blynk Library
#define BLYNK_PRINT Serial
#include <ESP8266_Lib.h> 
#include <BlynkSimpleShieldEsp8266.h>

//Blynk Initialization
char auth[] = "khKRhoan-PFv7ZoQRdRf48DRb-HxAriL";
char ssid[] = "BELL300";
char pass[] = "4FA9F4A7";
#define EspSerial Serial3
#define ESP8266_BAUD 115200
ESP8266 wifi(&EspSerial);

//Blynk Variables
int switchStatus1; //start button for default function
bool latch1 = false; //latch for default function loop

int switchStatus2; //start button for custom function
bool latch2 = false; //latch for custom function loop
unsigned long rotationInput; //variable for custom function # of rotations
unsigned long pauseDelay; //variable for custom function, determines the pause duration at the end of the rotation cycle before repeating the cycle again

BlynkTimer timer; //define timer for function delays

//Include the Arduino Stepper Library
#include <Stepper.h>

//Motor Variables
// Number of steps per internal motor revolution 
const float STEPS_PER_REV = 32; 

int StepsRequired; // number of Steps Required

// The pins used are 22,23,24,25 
// Connected to ULN2003 Motor Driver In1, In2, In3, In4 
// Pins entered in sequence 1-3-2-4 for proper step sequencing
Stepper steppermotor(STEPS_PER_REV, 22, 24, 23, 25);


void setup()
{
  Serial.begin(115200);
  delay(10);
  EspSerial.begin(ESP8266_BAUD); //serial initialization and default baud rate for ESP module
  delay(10);

Blynk.begin(auth, wifi, ssid, pass);                          //Reguler server
//Blynk.begin(auth, wifi, ssid, pass,"blynk-cloud.com", 8080);    //Local server
//Blynk.begin(auth, ssid, pass, IPAddress(45,55,96,146), 8080);
 
  tft.reset(); 
  tft.begin(0x9341); //start LCD screen 
  tft.setRotation(2); // set rotation to portrait 
  drawHome();                                   
}

//Blynk Functions

  //Default Function
  // write data from blynk on virtual 1 (start default function)
  BLYNK_WRITE(V1) {
  switchStatus1 = param.asInt();
  if (switchStatus1 == 1){ //if switch is on set latch and begin function loop
  latch1 = true;
  defaultRun();
  }
  if(switchStatus1 == 0){ //if switch is off unlatch 
    latch1 = false;
    
    //turn off all power to stepper motor phases to conserve power.
    digitalWrite(22,LOW);
    digitalWrite(23,LOW);
    digitalWrite(24,LOW);
    digitalWrite(25,LOW);   
  }
}

//Custom Function  
 // write data from blynk on virtual 2 (start custom function)
  BLYNK_WRITE(V2) {
  switchStatus2 = param.asInt();
  if (switchStatus2 == 1){ //if switch is on set latch and begin function loop 
  latch2 = true;
  customRun();
  }
  if(switchStatus2 == 0){ //if switch is off unlatch
    latch2 = false;

    //update slider values on app to 0
    Blynk.virtualWrite(V3, 0);
    Blynk.virtualWrite(V4, 0);

    //turn off all power to stepper motor phases to conserve power.
    digitalWrite(22,LOW);
    digitalWrite(23,LOW);
    digitalWrite(24,LOW);
    digitalWrite(25,LOW);
  }
}
 
 // write data from blynk on virtual 3 (rotation input)
  BLYNK_WRITE(V3) {
  rotationInput = map(param.asInt(), 0, 30, 0, 61500); //change slider value from 0-30 on app, to 0-61500 (61500 = # steps per single rotation X 30 = 2050 X 30)
  }

   // write data from blynk on virtual 4 (delay input slider)
  BLYNK_WRITE(V4) {
  pauseDelay = map(param.asInt(), 0, 10, 0, 36000000); //change slider value from 0-30 on app, to 0-36000000 (36000000 = 10 hours)
  }

void loop(){
  
  timer.run(); //call timer 
  Serial.println(touchLatch1);
  Blynk.run(); //begin blynk

   // Get the touch points  
  TSPoint p = ts.getPoint();  
  // Restore the mode  
  pinMode(XM, OUTPUT);  
  pinMode(YP, OUTPUT); 
   
  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {  
    p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());  
    p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
    
    // when at home page, if button is clicked set the appropriate page variable and draw the menu for the selected function
    if(currentPage == 0){ 
      if (p.x > 20 && p.x < 200){//defaultRun function button
        if(p.y > 100 && p.y < 140){
           timer.setTimeout(1000L, [](){ //wait 1 second before drawing next menu
          
          tft.setRotation(2); // set rotation to portrait
          
          tft.fillRoundRect(20, 100, 200, 40, 8, GREEN);
          tft.drawRoundRect(20, 100, 200, 40, 8, WHITE);  

          tft.fillRoundRect(20, 180, 200, 40, 8, RED);
          tft.drawRoundRect(20, 180, 200, 40, 8, WHITE);

          tft.setCursor(55, 20);
          tft.setTextSize(2);
          tft.setTextColor(WHITE);
          tft.print("PRESET WIND");

          tft.setTextSize(2);
          tft.setTextColor(WHITE);
          tft.setCursor(90, 113);
          tft.print("START");
  
          tft.setTextSize(2);
          tft.setTextColor(WHITE);
          tft.setCursor(95, 193);
          tft.print("STOP");

          currentPage = 1;
         });
        }
       }
    if (p.x > 20 && p.x < 200){ //customRun function button
        if(p.y > 180 && p.y < 220){
          timer.setTimeout(1000L, [](){ //wait 1 second before drawing next menu
         
          tft.setRotation(2); // set rotation to portrait

          tft.fillRoundRect(20, 50, 200, 40, 8, GREEN);
          tft.drawRoundRect(20, 50, 200, 40, 8, WHITE);  

          tft.fillRoundRect(20, 110, 200, 40, 8, RED);
          tft.drawRoundRect(20, 110, 200, 40, 8, WHITE);

          tft.fillTriangle(180, 197, 180, 217, 200, 207, BLUE);
          tft.drawTriangle(180, 197, 180, 217, 200, 207, WHITE);
          tft.fillRect(105, 197, 24, 20, WHITE);
          tft.fillTriangle(55, 197, 55, 217, 37, 207, BLUE);
          tft.drawTriangle(55, 197, 55, 217, 37, 207, WHITE);
          tft.fillRect(105, 197, 24, 20, WHITE);

          tft.fillTriangle(180, 264, 180, 284, 200, 274, BLUE);
          tft.drawTriangle(180, 264, 180, 284, 200, 274, WHITE);
          tft.fillRect(105, 264, 24, 20, WHITE);
          tft.fillTriangle(55, 264, 55, 284, 37, 274, BLUE);
          tft.drawTriangle(55, 264, 55, 284, 37, 274, WHITE);
          tft.fillRect(105, 264, 24, 20, WHITE);
  
          tft.setCursor(30, 20);
          tft.setTextSize(2);
          tft.setTextColor(WHITE);
          tft.print("CUSTOM FUNCTION");

          tft.setTextSize(2);
          tft.setTextColor(WHITE);
          tft.setCursor(90, 63);
          tft.print("START");
  
          tft.setTextSize(2);
          tft.setTextColor(WHITE);
          tft.setCursor(95, 123);
          tft.print("STOP");

          tft.setTextSize(2);
          tft.setTextColor(WHITE);
          tft.setCursor(36, 173);
          tft.print("# OF ROTATIONS");
          tft.setTextSize(2);
          tft.setTextColor(BLACK);
          tft.setCursor(106, 200);
          tft.print(rotationInput);

          tft.setTextSize(2);
          tft.setTextColor(WHITE);
          tft.setCursor(45, 240);
          tft.print("DELAY (HOURS)");
          tft.setTextSize(2);
          tft.setTextColor(BLACK);
          tft.setCursor(106, 267);
          tft.print(pauseDelay);

          currentPage = 2;
      });
     }
    }
  }
    if(currentPage == 1){
      if (p.x > 0 && p.x < 120) { // Touch area for box 1   
        if (p.y > 0 && p.y < 120) {  
        touchLatch1 = true;
        defaultRun(); 
      }  
     }  
      // Touch area for box 2  
      if (p.x > 120 && p.x < 240) {  
        if (p.y > 0 && p.y < 120) {  
        touchLatch1 = false;
        //turn off all power to stepper motor pins
        digitalWrite(22,LOW);
        digitalWrite(23,LOW);
        digitalWrite(24,LOW);
        
        digitalWrite(25,LOW); 
    }
   }  
  } 
    if(currentPage == 2){
      if (p.x > 0 && p.x < 120) { // Touch area for box 1   
        if (p.y > 0 && p.y < 120) {  
        touchLatch2 = true;
        customRun(); 
      }  
     }  
      // Touch area for box 2  
      if (p.x > 120 && p.x < 240) {  
        if (p.y > 0 && p.y < 120) {  
        touchLatch2 = false;
        //turn off all power to stepper motor pins
        digitalWrite(22,LOW);
        digitalWrite(23,LOW);
        digitalWrite(24,LOW);
        digitalWrite(25,LOW); 
    }
   }  
  }  
 }  
}
void drawHome(){ //display home screen at startup
  if(currentPage == 0){
  tft.fillScreen(BLACK);
  tft.drawRoundRect(0, 0, 240, 320, 8, WHITE);     //Page border

  tft.fillRoundRect(20, 100, 200, 40, 8, RED);
  tft.drawRoundRect(20, 100, 200, 40, 8, WHITE);  //default function button 

  tft.fillRoundRect(20, 180, 200, 40, 8, RED);
  tft.drawRoundRect(20, 180, 200, 40, 8, WHITE); //custom function button


  tft.setCursor(23, 20);
  tft.setTextSize(2);
  tft.setTextColor(WHITE);
  tft.print("SELECT AN OPTION");
  
  tft.setTextSize(2);
  tft.setTextColor(WHITE);
  tft.setCursor(55, 113);
  tft.print("PRESET WIND");
  
  tft.setTextSize(2);
  tft.setTextColor(WHITE);
  tft.setCursor(55, 193);
  tft.print("CUSTOM WIND");
 }
}

//Default Function
/*================================================*/
void defaultRun(){ 
  
  if(latch1 == true || touchLatch1 == true){ //only run if latch is true
    steppermotor.setSpeed(1000);//define speed of motor rotation    
    StepsRequired  =  2050; //one rotation = 2050 steps aprox.      
    steppermotor.step(StepsRequired);
    
    timer.setTimeout(2000L, defaultRun_Reverse);  //wait 2 seconds, then run reverse code
  }
} 
void defaultRun_Reverse(){
  
  if(latch1 == true || touchLatch1 == true){ //only run if latch is true
     steppermotor.setSpeed(1000);    
     StepsRequired  =  - 2050; //rotate in opposite direction
     steppermotor.step(StepsRequired);
        
     //turn off all power to stepper motor phases to conserve power.
     digitalWrite(22,LOW);
     digitalWrite(23,LOW);
     digitalWrite(24,LOW);
     digitalWrite(25,LOW);
        
     timer.setTimeout(5000L, defaultRun); //wait 5 seconds before calling defaultRun function and repeating loop
   }     
  }
/*================================================*/

//Custom Function
/*================================================*/
void customRun(){
  if(latch2 == true || touchLatch2 == true){
    steppermotor.setSpeed(1000);    
    StepsRequired  =  rotationInput; //read rotation value from app slider widget     
    steppermotor.step(StepsRequired); //read delay value from app slider widget
    
    timer.setTimeout(2000L, customRun_Reverse);  
  }
}

void customRun_Reverse(){   
      if(latch2 == true || touchLatch2 == true){
        steppermotor.setSpeed(1000);    
        StepsRequired  =  -rotationInput; //rotate in opposite direction
        steppermotor.step(StepsRequired);

        //turn off all power to stepper motor phases to conserve power.
        digitalWrite(22,LOW);
        digitalWrite(23,LOW);
        digitalWrite(24,LOW);
        digitalWrite(25,LOW);
        
        timer.setTimeout(pauseDelay, customRun); //wait 5 seconds before calling defaultRun function and repeating loop
    }
   }  
/*================================================*/

Code using Accelstepper (non-blocking):

I have so far only coded the default preset function. This code runs the motor for one rotation CW but then when it is to rotate CCW it begins to stop and stutter, and I am unsure why.

It also runs at a 1/3 of the speed that the blocking code does. I believe that this is because the Blynk connection along with the stepper motor running at the same time is possibly too much for the Mega board. Not sure if someone could confirm this. If this is the case, what would be my options?

//Include the Stepper Library
#include <AccelStepper.h>

//Motor Variables
#define FULLSTEP 4

AccelStepper stepper(FULLSTEP, 22, 24, 23, 25);  

//Include the LCD Screen Libraries
#include "SPFD5408_Adafruit_GFX.h"    // Core graphics library
#include "SPFD5408_Adafruit_TFTLCD.h" // Hardware-specific library
#include "SPFD5408_TouchScreen.h"

//Pin Assignments
#define YP A3  
#define XM A2  
#define YM 9  
#define XP 8   

//Calibrated Touch Values
#define TS_MINX 87
#define TS_MINY 108
#define TS_MAXX 956
#define TS_MAXY 964

//Touch Screen Initialization
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_RD    A0
#define LCD_WR    A1
#define LCD_CD    A2
#define LCD_CS    A3
#define LCD_RESET A4

#define BOXSIZE   40  
#define PENRADIUS  3  
#define MINPRESSURE 10  
#define MAXPRESSURE 1000    
 
//Initialize TFT Object
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// Assign human-readable names to some common 16-bit color values:
#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

//Touch Screen Variables
bool touchLatch1 = false;
bool touchLatch2 = false;


//Include the Blynk Library
#define BLYNK_PRINT Serial
#include <ESP8266_Lib.h> 
#include <BlynkSimpleShieldEsp8266.h>

//Blynk Initialization
char auth[] = "khKRhoan-PFv7ZoQRdRf48DRb-HxAriL";
char ssid[] = "BELL300";
char pass[] = "4FA9F4A7";
#define EspSerial Serial3
#define ESP8266_BAUD 115200
ESP8266 wifi(&EspSerial);

//Blynk Variables
int switchStatus1; //start button for default function
bool latch1 = false; //latch for default function loop

int switchStatus2; //start button for custom function
bool latch2 = false; //latch for custom function loop
unsigned long rotationInput; //variable for custom function # of rotations
unsigned long pauseDelay; //variable for custom function, determines the pause duration at the end of the rotation cycle before repeating the cycle again

BlynkTimer timer; //define timer for function delays


void setup(){
  Serial.begin(115200);
  delay(10);
  EspSerial.begin(ESP8266_BAUD); //serial initialization and default baud rate for ESP module
  delay(10);

Blynk.begin(auth, wifi, ssid, pass);                          //Reguler server
//Blynk.begin(auth, wifi, ssid, pass,"blynk-cloud.com", 8080);    //Local server
//Blynk.begin(auth, ssid, pass, IPAddress(45,55,96,146), 8080);
  
  tft.reset();  
  tft.begin(0x9341);  
  tft.setRotation(2); // set rotation to portrait
  tft.setTextColor(WHITE);  
  tft.setTextSize(2);  
  tft.fillScreen(BLACK);  
  tft.fillRect(0, 0, 120, 120, GREEN);  
  tft.fillRect(120, 0, 120, 120, RED);  
  tft.setCursor(15, 45);  
  tft.println("ON");  
  tft.setCursor(128, 45);  
  tft.println("OFF");  
  tft.setTextColor(WHITE, BLACK);  
  tft.setTextSize(8);   

  stepper.setMaxSpeed(1000.0);
  stepper.setAcceleration(200.0);
  stepper.setSpeed(1000);
}

//Blynk Functions

  //Default Function
  // write data from blynk on virtual 1 (start default function)
  BLYNK_WRITE(V1) {
  switchStatus1 = param.asInt();
  if (switchStatus1 == 1){ //if switch is on set latch and begin function loop
  latch1 = true;
  }
  if(switchStatus1 == 0){ //if switch is off unlatch 
    latch1 = false;
    stepper.stop();

    //turn off all power to stepper motor phases to conserve power.
    digitalWrite(22,LOW);
    digitalWrite(23,LOW);
    digitalWrite(24,LOW);
    digitalWrite(25,LOW);
  }
}

//Custom Function  
 // write data from blynk on virtual 2 (start custom function)
  BLYNK_WRITE(V2) {
  switchStatus2 = param.asInt();
  if (switchStatus2 == 1){ //if switch is on set latch and begin function loop 
  latch2 = true;
  }
  if(switchStatus2 == 0){ //if switch is off unlatch
    latch2 = false;

    //turn off all power to stepper motor phases to conserve power.
    digitalWrite(22,LOW);
    digitalWrite(23,LOW);
    digitalWrite(24,LOW);
    digitalWrite(25,LOW);

    //update slider values on app to 0
    Blynk.virtualWrite(V3, 0);
    Blynk.virtualWrite(V4, 0);

    stepper.stop();
  }
}
 
 // write data from blynk on virtual 3 (rotation input)
  BLYNK_WRITE(V3) {
  rotationInput = map(param.asInt(), 0, 30, 0, 122880); //change slider value from 0-30 on app, to 0-122880 (# steps per single rotation X 30 = 4096 X 30 = 122880)
  }

   // write data from blynk on virtual 4 (delay input slider)
  BLYNK_WRITE(V4) {
  pauseDelay = map(param.asInt(), 0, 10, 0, 36000000); //change slider value from 0-30 on app, to 0-36000000 (36000000 = 10 hours)
  }

void loop(){
  timer.run(); //call timer 
  
  Blynk.run(); //begin blynk and maintain connection

   // Get the touch points  
  TSPoint p = ts.getPoint();  
  // Restore the mode  
  pinMode(XM, OUTPUT);  
  pinMode(YP, OUTPUT);  
  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {  
   p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());  
   p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());  
   // Touch area for box 1  
   if (p.x > 0 && p.x < 120) {  
    if (p.y > 0 && p.y < 120) {  
     touchLatch1 = true;
    }  
   }
   // Touch area for box 2  
   if (p.x > 120 && p.x < 240) {  
    if (p.y > 0 && p.y < 120) {  
     touchLatch1 = false;
     stepper.stop(); 

    //turn off all power to stepper motor phases to conserve power.
    digitalWrite(22,LOW);
    digitalWrite(23,LOW);
    digitalWrite(24,LOW);
    digitalWrite(25,LOW);
    }  
   }  
  }
  
 //Default Function
/*================================================*/ 
  if(latch1 == true || touchLatch1 == true){ //only run if latch is true
    
    stepper.moveTo(2048); 
    
      if (stepper.distanceToGo() == 0) {
    stepper.moveTo(-stepper.currentPosition());
  }
}
  
   stepper.run(); 
/*================================================*/

//Custom Function
/*================================================
  if(latch2 == true || touchLatch2 == true){      
    stepper.moveTo(rotationInput); //read # of rotations from app slider widget 
    
    if (stepper.distanceToGo() == 0){
    timer.setTimeout(2000L, [](){
         
        stepper.moveTo(rotationInput);; //rotate in opposite direction
        
        timer.setTimeout(pauseDelay, [](){ //read delay value from app slider widget and wait before reapting loop
     });
   });
  }
 }*/
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.