Problem with numbers bigger than 32767 [Solved]

Hey there!
I wrote a program on Arduino to control stepper motors using the EasyDriver library and serial communication. It is all working, but I have an issue when I try to send more than 32767 steps to the motors. When I do that, the motors will turn in the opposite direction of the one it should, and if the number is too big, it doesn't move all the steps either. I understand that this is a problem of the type of variable that I'm using. I was using the type float at the beginning, and then I tried to change it to int, and then to long int. But the result was the same.

My set up:

  • Win11
  • Arduino IDE 2.0.5
  • Arduino UNO

Here is the code with the last modification (try to use long int):

//libraries for drivers and serial communication (sc)
#include <AH_EasyDriver.h>
#include <SoftwareSerial.h>

#include <stdio.h>
#include <stdlib.h>
 
 
//sending the characters via sc
const byte numChars = 32;    //number of characters per piece of info
char receivedChars[numChars];
char tempChars[numChars];   //temporary array for use when parsing

long m1steps = 0.0;
long m2steps = 0.0;
long m3steps = 0.0; 
long m4steps = 0.0;

float speedrpm = 170;

boolean newdata = false;


//AH_EasyDriver(int RES, int DIR, int STEP, int MS1, int MS2, int SLP, int ENABLE, int RST);
AH_EasyDriver m1stepper(200,6,7,3,4,2);   //initialize with the basics functions 
                                          //MS1, MS2 and SLP control microstepping 
                                          //RES are steps per revolution*
AH_EasyDriver m2stepper(200,8,9,3,4,2); 
AH_EasyDriver m3stepper(200,10,11,3,4,2); 
AH_EasyDriver m4stepper(200,12,13,3,4,2); 

                                          

//add the rest of the drivers (when i have them)
                                        
void setup() {

  Serial.begin(9600);                  //initialize sc
  Serial.println("Arduino is ready");
  
  m1stepper.resetDriver();              
  m1stepper.enableDriver();           
  m1stepper.setMicrostepping(0);        // 0 -> Full Step                                
                                        // 1 -> 1/2 microstepping
                                        // 2 -> 1/4 microstepping
                                        // 3 -> 1/8 microstepping
  m1stepper.setSpeedRPM(speedrpm);           // set speed in RPM, rotations per minute
//  m1stepper.setSpeedHz(100);            

  m2stepper.resetDriver();
  m2stepper.enableDriver();
  m2stepper.setMicrostepping(0);
  m2stepper.setSpeedRPM(speedrpm);

  m3stepper.resetDriver();
  m3stepper.enableDriver();
  m3stepper.setMicrostepping(0);
  m3stepper.setSpeedRPM(speedrpm);
  
  m4stepper.resetDriver();
  m4stepper.enableDriver();
  m4stepper.setMicrostepping(0);
  m4stepper.setSpeedRPM(speedrpm);
  
 
}

void loop() {
  
  receive();
  if (newdata == true) {
    strcpy(tempChars, receivedChars);  //this copies the values in recerivedchars into tempchars (string) for a temporary copy
    parsedata();
    showpd();  //show parsed data
    newdata = false;
    
    m1stepper.sleepOFF();                 
    m1stepper.move(-m1steps);      //movement of the motor1     
    m1stepper.sleepON();

    m2stepper.sleepOFF();                 
    m2stepper.move(-m2steps);         
    m2stepper.sleepON();

    m3stepper.sleepOFF();                 
    m3stepper.move(-m3steps);         
    m3stepper.sleepON();

    m4stepper.sleepOFF();                 
    m4stepper.move(-m4steps);       
    m4stepper.sleepON();

  }

}

//=======functions======

//receiving (and stop receiving) the data
//the data needs to be sent as <m1steps,m2steps,m3steps,m4steps>
void receive() {
  static boolean rip = false;  //receive in process
  static byte ndx = 0;
  char startmarker = '<';      //start of the reading 
  char endmarker = '>';        //end of the reading
  char rc;

  while (Serial.available() > 0 && newdata == false) {  //check to see if anything is available in the serial receive buffer
    rc = Serial.read();                                 // we add to the array the characters until the endmarker
    if (rip == true) {
      if (rc != endmarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      } else {
        receivedChars[ndx] = '\0';  //terminate the string
        rip = false;
        ndx = 0;
        newdata = true;
      }
    } else if (rc == startmarker) {
      rip = true;
    }
  }
}

//split the data into the different parts
//four sets of data in float 

void parsedata() {
  char* strtokindx; //use as an index for the strtok funtion

  strtokindx = strtok(tempChars, ",");  //get the first part of the string
  m1steps = atol(strtokindx);           //converts this to a float
  
  strtokindx = strtok(NULL, ",");  //continues where the previous call left
  m2steps = atol(strtokindx);

  strtokindx = strtok(NULL, ",");  //continues where the previous call left
  m3steps = atol(strtokindx);

  strtokindx = strtok(NULL, ",");  //continues where the previous call left
  m4steps = atol(strtokindx);
}


//show what we have received the characters (confirmation of arrival and movement of the motors)
void showpd() {  //show parsed data
  Serial.print("m1steps: ");
  Serial.print( m1steps);
  Serial.print("; m2steps: ");
  Serial.print( m2steps);
  Serial.print("; m3steps: ");
  Serial.print( m3steps);
  Serial.print("; m4steps: ");
  Serial.print( m4steps);
  Serial.println();
}

Thanks a lot!

Look at library

and see what type the variable

is declared as, if it is an INT then any value grater than 32767 will wrap around and become a negative number.

1 Like

yeah seems they made the poor decision to use int instead of long

2 Likes

Oh no. I guess I cannot change that...

Negative numbers are handled

void AH_EasyDriver::move(int NUMBER_OF_STEPS)
{  
  int STEPS = abs(NUMBER_OF_STEPS);  

  if (NUMBER_OF_STEPS > 0) {setDirection(FORWARD); }
  if (NUMBER_OF_STEPS < 0) {setDirection(BACKWARD);}    

//... 

So you are limited to 32767 steps forward or backwards.

a7

No, but you could simply request multiple moves to get to the number you want. It just won't be smooth. Or, you could take on rewriting that portion of the library for the benefit of others.

2 Likes

I would do it, but I don't really know how to do that

Or switch to the Accelstepper Library that doesn't have that problem.

2 Likes

Agreed.

Can I use the AccelStepper library with the EasyDrivers?

the library is open source... so you could

Yes

How can I do that?

Okay nvm I did it:) Thanks for the help!

  • you find the .cpp and the .h from the library
  • you copy those over inside your sketch's directory
  • you open the sketch
  • In your sketch instead of chevrons #include <AH_EasyDriver.h> you use quotes #include "AH_EasyDriver.h" to say you want to use the version in your project's folder

then that's the "hard" part : you go through the .cpp and .h and change any int type that relates to movement into a long.

Just keep the pins as int

    int DIR_pin;
    int STEP_pin;
    int MS1_pin;
    int MS2_pin;
    int SLP_pin;
    int ENABLE_pin;
    int RST_pin;

(or better make them byte)

the rest is probably fine to go to long

1 Like

This forum has an old thread on this code here:

which points here:

http://www.alhin.de/arduino/index.php?n=44

The modifications are fairly simple. You change the int move(... to a long move(... in in the AH_EasyDriver.h and AH_EasyDriver.cpp files like this:


/*************************************************************************
**  Device: EasyDriver 4.3                                          	**
**  File:   AH_EasyDriver.h - Stepper motor Driver		    	**
**			  		     				**
**  Created by A. Hinkel 2012-05-05                                 	**
**  Modification         2013-03-21  		   			**
**  Modification         2023-03-24 for move(long NUMBER_OF_STEPS)
**  Code at https://forum.arduino.cc/t/problem-with-numbers-bigger-than-32767/1106116/17
**									**
**  Released into the public domain.  		                    	**
**                                                                  	**
*************************************************************************/


#ifndef AH_EasyDriver_h
#define AH_EasyDriver_h



#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#define FORWARD   true
#define BACKWARD  false

class AH_EasyDriver {
  public:
  AH_EasyDriver(int RES, int DIR, int STEP);
    AH_EasyDriver(int RES, int DIR, int STEP, int MS1, int MS2, int SLP);
    AH_EasyDriver(int RES, int DIR, int STEP, int MS1, int MS2, int SLP, int ENABLE, int RST);

    void setSpeedRPM(int RPM);
    void setSpeedHz(int FREQ);
    void setMicrostepping(int MODE);

    void enableDriver();
    void disableDriver();
    void sleepON();
    void sleepOFF();
    void resetDriver();

    void move(long NUMBER_OF_STEPS);
    void move(long NUMBER_OF_STEPS, boolean DIRECTION);
    void rotate(float DEGREES);
    void revolve(float TIMES);

    long getMaxSpeedRPM();
    long getMaxSpeedHz();


  private:
    void stepMotor();
    void setDirection(boolean DIRECTION);
    void setEnable(boolean VALUE);
    void setSleep(boolean VALUE);

    long STEP_DELAY;
    long LAST_STEP_TIME;

    int INIT_MODE;
    int STEP_NUMBER;
    int MOTOR_RESOLUTION;
    int DIRECTION;
    int STEPPING_FACTOR;

    int DIR_pin;
    int STEP_pin;
    int MS1_pin;
    int MS2_pin;
    int SLP_pin;
    int ENABLE_pin;
    int RST_pin;
	

};

#endif


/*************************************************************************
**  Device: EasyDriver 4.3
**  File:   AH_EasyDriver.h - Stepper motor Driver
**
**  Created by A. Hinkel 2012-05-05
**  Modification         2013-03-21
**  Modification         2023-03-24 for move(long NUMBER_OF_STEPS)
**  Code at https://forum.arduino.cc/t/problem-with-numbers-bigger-than-32767/1106116/17
** 
**  Released into the public domain.
**
*************************************************************************/


#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "AH_EasyDriver.h"

//*******************************************************************
//*** INIT ****
//*******************************************************************
AH_EasyDriver::AH_EasyDriver(int RES, int DIR, int STEP)
{ 
  this->INIT_MODE = 0;

  this->MOTOR_RESOLUTION = RES;
  this->DIR_pin = DIR;
  this->STEP_pin = STEP;

  pinMode(this->DIR_pin, OUTPUT);
  pinMode(this->STEP_pin, OUTPUT);

  this->STEPPING_FACTOR = 8;
  setSpeedRPM(60);   		// default velocity
  
}

//*******************************************************************
AH_EasyDriver::AH_EasyDriver(int RES, int DIR, int STEP, int MS1, int MS2, int SLP)
{
  this->INIT_MODE = 1;

  this->MOTOR_RESOLUTION = RES;
  this->DIR_pin = DIR;
  this->STEP_pin = STEP;
  this->MS1_pin = MS1;
  this->MS2_pin = MS2;
  this->SLP_pin = SLP;

  pinMode(this->DIR_pin,    OUTPUT);
  pinMode(this->STEP_pin,   OUTPUT);
  pinMode(this->MS1_pin,    OUTPUT);
  pinMode(this->MS2_pin,    OUTPUT);
  pinMode(this->SLP_pin,    OUTPUT);

  setMicrostepping(3);   	// 1/8 microstep as default setting
  setSpeedRPM(60);   		// default velocity
  
}

//*******************************************************************
AH_EasyDriver::AH_EasyDriver(int RES, int DIR, int STEP, int MS1, int MS2, int SLP, int ENABLE, int RST)
{
  this->INIT_MODE = 2;

  this->MOTOR_RESOLUTION = RES;
  this->DIR_pin = DIR;
  this->STEP_pin = STEP;
  this->MS1_pin = MS1;
  this->MS2_pin = MS2;
  this->SLP_pin = SLP;
  this->ENABLE_pin = ENABLE;
  this->RST_pin = RST;

  pinMode(this->DIR_pin,    OUTPUT);
  pinMode(this->STEP_pin,   OUTPUT);
  pinMode(this->MS1_pin,    OUTPUT);
  pinMode(this->MS2_pin,    OUTPUT);
  pinMode(this->SLP_pin,    OUTPUT);
  pinMode(this->ENABLE_pin, OUTPUT);
  pinMode(this->RST_pin,    OUTPUT);

  setMicrostepping(3);   	// 1/8 microstep as default setting
  setSpeedRPM(60);   		// default velocity
  
}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::resetDriver(){

  if (this->INIT_MODE>1){
    digitalWrite(this->RST_pin, LOW);
    delay(1);
    digitalWrite(this->RST_pin, HIGH);
    delay(1);
  }

}

//*******************************************************************
//*******************************************************************

void AH_EasyDriver::setSpeedRPM(int RPM)
{
  this->STEP_DELAY = 60L*1000000L/(RPM*(this->MOTOR_RESOLUTION)*(this->STEPPING_FACTOR));
}


//*******************************************************************

void AH_EasyDriver::setSpeedHz(int FREQ)
{
  this->STEP_DELAY = 1000000/FREQ;
}


//*******************************************************************
//*******************************************************************

long AH_EasyDriver::getMaxSpeedRPM()
{
  return (60*1000000)/(this->MOTOR_RESOLUTION*this->STEPPING_FACTOR);
}


//*******************************************************************

long AH_EasyDriver::getMaxSpeedHz()
{
  return 1000000;
}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::setDirection(boolean DIRECTION){

  digitalWrite(this->DIR_pin, DIRECTION);
  delayMicroseconds(100);

}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::enableDriver(){

  setEnable(LOW);
}

//*********************************************

void AH_EasyDriver::disableDriver(){

  setEnable(HIGH);
}

//*********************************************

void AH_EasyDriver::setEnable(boolean VALUE){

  if (this->INIT_MODE>0){
    digitalWrite(this->ENABLE_pin, VALUE);
    delayMicroseconds(100);
  }
}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::sleepON(){

   setSleep(LOW);
}

//********************************************

void AH_EasyDriver::sleepOFF(){

   setSleep(HIGH);
}

//********************************************
void AH_EasyDriver::setSleep(boolean VALUE){

  if (this->INIT_MODE>0){
    digitalWrite(this->SLP_pin, VALUE);
    delayMicroseconds(100);

  }

}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::setMicrostepping(int MODE){

  switch (MODE) {
    case 0:  					// 1/1 Vollschritt
      digitalWrite(this->MS1_pin, LOW);
      digitalWrite(this->MS2_pin, LOW);
      this->STEPPING_FACTOR = 1;
      break;
    case 1:					// 1/2 Halbschritt
      digitalWrite(this->MS1_pin, HIGH);
      digitalWrite(this->MS2_pin, LOW);
      this->STEPPING_FACTOR = 2;
      break;
    case 2:					// 1/4 Viertelschritt
      digitalWrite(this->MS1_pin, LOW);
      digitalWrite(this->MS2_pin, HIGH);
      this->STEPPING_FACTOR = 4;
      break;
    case 3:					// 1/8 Achtelschritt
      digitalWrite(this->MS1_pin, HIGH);
      digitalWrite(this->MS2_pin, HIGH);
      this->STEPPING_FACTOR = 8;
      break;
    default: 					// 1/8 
      digitalWrite(this->MS1_pin, HIGH);
      digitalWrite(this->MS2_pin, HIGH);
      this->STEPPING_FACTOR = 8;
  }

}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::move(long NUMBER_OF_STEPS)
{  
  long STEPS = abs(NUMBER_OF_STEPS);  

  if (NUMBER_OF_STEPS > 0) {setDirection(FORWARD); }
  if (NUMBER_OF_STEPS < 0) {setDirection(BACKWARD);}    
 
  while(STEPS > 0) {
   if (micros() - this->LAST_STEP_TIME >= this->STEP_DELAY) {
      this->LAST_STEP_TIME = micros();
      STEPS--;
      stepMotor();
    }
  }

}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::move(long NUMBER_OF_STEPS, boolean DIRECTION)
{  
  long STEPS = abs(NUMBER_OF_STEPS);   
  setDirection(DIRECTION);
   
  while(STEPS > 0) {
    if (micros() - this->LAST_STEP_TIME >= this->STEP_DELAY) {
      this->LAST_STEP_TIME = micros();
      STEPS--;
      stepMotor();
    }
  }
}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::rotate(float DEGREES){

  long steps_to_move = (long)((DEGREES * this->MOTOR_RESOLUTION * this->STEPPING_FACTOR)/360);
  move(steps_to_move);

}


//*******************************************************************
//*******************************************************************

void AH_EasyDriver::revolve(float TIMES){

  long steps_to_move = (long)(TIMES * this->MOTOR_RESOLUTION * this->STEPPING_FACTOR);
  move(steps_to_move);

}

//*******************************************************************
//*******************************************************************

void AH_EasyDriver::stepMotor()
{
    digitalWrite(this->STEP_pin, HIGH);
    digitalWrite(this->STEP_pin, LOW);
}

You could either change them within your Arduion/libraries/AH_EasyDriver folder, or you could make copies in your sketch directory and call out the local copy with this change in your sketch:

//#include <AH_EasyDriver.h>  // https://www.alhin.de/arduino/index.php?n=44
#include "AH_EasyDriver.h" // long moves edit from https://forum.arduino.cc/t/problem-with-numbers-bigger-than-32767-solved/1106116

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