Protocol for avoiding pointers

Hi @J-M-L ,

in the example I am just using the external MotorData struct to initialize the class internal MotorData. I know it could have been done in the class constructor! But init() had to be called in setup anyway to set the pinMode of stepPin and dirPin.

Do you think it has advantages to set the data in the constructor? I'm just curious!

What's definitely missing in my class example is a function to get and - if required - reset the data.steps value as the class internal struct is private.

Always appreciate your advices!
ec2021

P.S.: Based on your comment I changed the code to demonstrate the use of the constructor :wink:

MotorClass using Constructor to set the Motor Data
/*
   Forum: https://forum.arduino.cc/t/protocol-for-avoiding-pointers/1394145
   Wokwi: https://wokwi.com/projects/436081346719270913

  Corrected version 
  * unsigned long steps to float
  * MICROSTEP_SIZE to float

  2025/07/11
  ec2021

*/

#define NUM_ELEMENTS(_ArrayName) (sizeof(_ArrayName) / sizeof(_ArrayName[0]))

constexpr int CLOCKWISE {1};
constexpr int COUNTERCLOCKWISE {0};

constexpr long MOTOR_REV {0};
constexpr long DRIVER_MODE {0};

//constexpr long MICROSTEP_SIZE {1 / 8}; 
// Corrected 2025/07/11
constexpr float MICROSTEP_SIZE {1.0/8};


//******************************************************************************
class MotorClass {
  private:
    int stepPin;
    int dirPin;
    int direction;
    int rpm;
    long speed;
    bool run;
    // unsigned long steps = 0;
    // Corrected 2025/07/11
    float steps = 0;
  public:
    MotorClass(int _stepPin, int _dirPin, int _direction, int _rpm) {
      stepPin = _stepPin;
      dirPin = _dirPin;
      direction = _direction;
      rpm = _rpm;
      speed = 10000;  // ((60000000L) / ((long)rpm * ((long)MOTOR_REV * (long)DRIVER_MODE))) / 2;
      run = false;
    }
    void init() {
      pinMode(stepPin, OUTPUT);
      pinMode(dirPin, OUTPUT);
    }
    void setClockWise(boolean cw) {
      if (cw) {
        direction = CLOCKWISE;
      } else {
        direction = COUNTERCLOCKWISE;
      }
      digitalWrite(dirPin, direction); //Set the direction.
    }
    void toggleDirection() {
      setClockWise(direction == COUNTERCLOCKWISE);
    }
    void setRun(bool shall_run) {
      run = shall_run;
      if (!run) {
        digitalWrite(stepPin, LOW); //Pulse OFF.
      }
    }
    void resetSteps() {
      steps = 0;
    }
    // unsigned long getSteps() {
    // Corrected 2025/07/11
    float getSteps() {
      return steps;
    }
    void handle() {
      if (run) {
        digitalWrite(stepPin, HIGH); //Pulse ON.
        delayMicroseconds(speed); //Period halftime.
        digitalWrite(stepPin, LOW); //Pulse OFF.
        delayMicroseconds(speed); //Period halftime.
        steps += MICROSTEP_SIZE; //Add 1/8 step (motor driver step mode.)
      }
    }
};
//******************************************************************************

MotorClass motor[] = {
  {12, 11, 1, 360},
  {10,  9, 1, 360},
  { 8,  7, 1, 360},
  { 6,  5, 1, 360}
};
constexpr int nMotor = NUM_ELEMENTS(motor);

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < nMotor; i++) {
    motor[i].init();
  }
}

void loop() {
  doSomethingAll(2);
  for (int i = 0; i < nMotor; i++) {
    motor[i].handle();
  }
}

void doSomethingAll(unsigned long seconds) {
  static unsigned long lastChange = 0;
  static int activeMotor = 0;
  static boolean isFirstCall = true;
  if (millis() - lastChange > seconds * 1000UL || isFirstCall) {
    lastChange = millis();
    if (isFirstCall) {
      isFirstCall = false;
    } else {
      motor[activeMotor].setRun(false);
      Serial.print("Motor no = ");
      Serial.print(activeMotor+1);
      Serial.print("\tsteps  = ");
      Serial.println(motor[activeMotor].getSteps());      
      activeMotor += 1;
      if (activeMotor >= nMotor) {
        activeMotor = 0;
      }
    }
    motor[activeMotor].toggleDirection();
    motor[activeMotor].setRun(true);
  }
}


To be checked out on Wokwi: https://wokwi.com/projects/436081346719270913

And added methods to get/reset steps ...

And found a glitch, I declared steps as unsigned long but add 1/8... That's not working of course. I will have to correct the versions ...

Corrections done (2025/07/11) [Never trust that code will work if it hasn't been thoroughly tested. :slight_smile: ]