Spin up DC Motor without Delay

The following code works just fine but I want to add blinking LEDs as well and the Delay() function associated with spinning up the motor will throw off the timing. Anyone know how to slowly spin up/down a DC motor that doesn’t use Delay()? I plan to also implement spin down/up when the direction changes, but I don’t want that to affect the blinking LEDs (which I’ve yet to add)

const int enablePin  = 3;         // Same RPM for both motors, so only need 1 PWM pin to connect
                                  // to both enable pins on SN754410

const int switchPin1 = 2; 
const int motor1Pin2 = 4; 
const int motor1Pin1 = 5; 

const int switchPin2 = 7; 
const int motor2Pin2 = 8; 
const int motor2Pin1 = 12; 

const int potPin = 0;             // trim pot middle wiper arm connected to A0
const int startRPM = 40;
const int minRPM = 50;            // The min mapped value depends on your motor and the voltage applied; you want
                                  // this to be the slowest observed speed (no stall) for your selected motor
const int motorDelay = 15;

int RPM = 0;

int setRPM(int readPotValue = 0); // Set up function for optional parameter




void setup()  
{ 
#if defined(DEVMODE)
    Serial.begin(9600);
    Serial.println("DEVMODE ON");
#endif
 
  pinMode(switchPin1, INPUT_PULLUP);
  pinMode(switchPin2, INPUT_PULLUP);
  
  pinMode(enablePin, OUTPUT);
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(motor2Pin1, OUTPUT);
  pinMode(motor2Pin2, OUTPUT);


  // What about using LEDFader? Should work here as it's just a PWM signal

  // switchPin1 SPDT switch determines starboard side motor direction
  if (digitalRead(switchPin1) == HIGH) 
  {
    digitalWrite(motor1Pin2, HIGH); 
    digitalWrite(motor1Pin1, LOW); 
  }
  else 
  {
    digitalWrite(motor1Pin1, HIGH); 
    digitalWrite(motor1Pin2, LOW); 
  }

  // switchPin2 SPDT switch determines port side motor direction
  if (digitalRead(switchPin2) == HIGH) 
  {
    digitalWrite(motor2Pin2, HIGH); 
    digitalWrite(motor2Pin1, LOW); 
  }
  else 
  {
    digitalWrite(motor2Pin1, HIGH); 
    digitalWrite(motor2Pin2, LOW); 
  }

  // Spin up motor at start to trim pot setting
  analogRead(potPin);                         // Discard first reading
  RPM = setRPM(1);                            // Call function to set motor RPM (first time)
  spinUpMotor(startRPM, RPM);                 // Call function to spin up motor

}

void loop()  
{   

  RPM = setRPM();
  analogWrite(enablePin, RPM);       

  // switchPin1 SPDT switch determines starboard side motor direction
  if (digitalRead(switchPin1) == HIGH) 
  {
    // TODO: if switch value has changed, spin down then up motor
    
    digitalWrite(motor1Pin2, HIGH); 
    digitalWrite(motor1Pin1, LOW); 
  }
  else 
  {
    // TODO: if switch value has changed, spin down then up motor
    
    digitalWrite(motor1Pin1, HIGH); 
    digitalWrite(motor1Pin2, LOW); 
  }

  // switchPin2 SPDT switch determines port side motor direction
  if (digitalRead(switchPin2) == HIGH) 
  {
    // TODO: if switch value has changed, spin down then up motor
    
    digitalWrite(motor2Pin2, HIGH); 
    digitalWrite(motor2Pin1, LOW); 
  }
  else 
  {
    // TODO: if switch value has changed, spin down then up motor
    
    digitalWrite(motor2Pin1, HIGH); 
    digitalWrite(motor2Pin2, LOW); 
  }

  //delay(2);
}

int setRPM(int readPotValue)
{
  static int ewsPotVal;                             // Static variable; will retain value from previous function call but
                                                    // can only be modified by this function
#if defined(DEVMODE)
  Serial.print("optional readPotValue = " );     
  Serial.println(readPotValue);
#endif

  int newPotValue=analogRead(potPin);               // Read voltage across trim pot; this gets converted to a digital
                                                    // value between 0-1023

  if(readPotValue = 1){
    ewsPotVal = newPotValue;                        // Set ewsPotVal for first time thru function call from Setup()
  }
  
/* 
https://electronics.stackexchange.com/questions/64677/how-to-smooth-potentiometer-values

A very simple software technique to smooth values is exponentially-weighted smoothing. 
This is a beautiful trick which allows the smoothed value to depend on all prior values, 
without retaining a history of prior samples.
*/
  ewsPotVal += (newPotValue - ewsPotVal)/4;             // optimizes to s += (sample - s) >> 2;
  int mappedVal = map(ewsPotVal, 0, 1023, minRPM, 255); // 8-bit PWM values are limited to 0-255; use map function to set RPM

#if defined(DEVMODE)
  Serial.print("ews trim pot value = " );     
  Serial.print(ewsPotVal);
  Serial.print(", motor RPM = ");
  Serial.println(mappedVal);
#endif

  return mappedVal;
}

void spinUpMotor(int fromRPM, int toRPM)
{

#if defined(DEVMODE)
  Serial.print("fromRPM = " );     
  Serial.print(fromRPM);

  Serial.print(", toRPM = " );     
  Serial.println(toRPM);

  Serial.println("Starting spinning up ...");
#endif

  for(int motorVal = fromRPM; motorVal <= toRPM; motorVal +=1){
    analogWrite(enablePin, motorVal); 

#if defined(DEVMODE)
    Serial.print("motor RPM = " );     
    Serial.println(motorVal);
#endif

    delay(motorDelay);
  }

#if defined(DEVMODE)
  Serial.println("... stopped spinning up.");
#endif

}

void spinDwnMotor(int fromRPM, int toRPM)
{

#if defined(DEVMODE)
  Serial.print("fromRPM = " );     
  Serial.print(fromRPM);

  Serial.print(", toRPM = " );     
  Serial.println(toRPM);

  Serial.println("Starting spinning down ...");
#endif

  for(int motorVal = fromRPM; motorVal <= toRPM; motorVal -=1){
    analogWrite(enablePin, motorVal); 

#if defined(DEVMODE)
    Serial.print("motorVal = " );     
    Serial.println(motorVal);
#endif

    delay(motorDelay);
  }

#if defined(DEVMODE)
  Serial.println("... stopped spinning down.");
#endif

}

My approach would be to call a routine like set_motor_speed(speed), with “speed” slowly increasing or decreasing, each time a defined time increment has passed.

Code it similarly to the “blink without delay” example sketch.

The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique. Note how each function runs very briefly and returns to loop() so the next one can be called. And there may be dozens of calls to a function before it is actually time for it to do anything.

As well as not using delay() don't use FOR or WHILE either as they are also blocking concepts. Allow loop() to do the repetition.

...R

Thanks jremington & Robin2 (does that make you Jason Todd?). I'm going to look into that example of doing several things at once.

Robin2 - I hadn't heard that about FOR loops causing blocking. Is it significant? I ask because I'm using an LEDFader library for multiple fading LEDs and the example uses a FOR loop to iterate through an array of all the 5 LEDs attached, setting random fade down/up times as well as intensity. If what you say is true I need to convert that to multiple individual functions for each LED.

I hadn't heard that about FOR loops causing blocking.

They don't "cause" blocking, but it is easy to write blocking code using them.

Such loops are usually unnecessary in applications like yours, because you already have a loop (the loop function) that executes as rapidly as possible.

In your case, you do not need to write "multiple individual functions for each LED". Just have an index that cycles through them.