Problem with PWM Motor Drive

I have written a sketch to start and stop a DC motor

#include <string.h>;

/*  
 *   Variables we must track
 */
 // for the motor
 const int  motorOnOffPin  = 4;     // digital pin
 const int  motorSpeedPin  = 5;     // analog pin
       bool motorOn        = false; // flag
 const int  motorCruise    = 1023;  // cruising setting in PWM
 const int  motorCreep     = 300;   // very slow motor speed in PWM
       int  motorPace      = 0;     // current motor speed in PWM

 /*
  *   Declarative section
  */
// this routine starts the motor and accelerates it to cruise speed
bool accelerate();

// this routine decelerates motor from current speed to stopped
bool decelerate ();

/*
 *  Program setup
 */
void setup() 
{
  // debug - start Serial
  Serial.begin(9600);

  // set up motor controls
  pinMode      (motorOnOffPin, OUTPUT);
  digitalWrite (motorOnOffPin, LOW);
  pinMode      (motorSpeedPin, OUTPUT);
  analogWrite  (motorSpeedPin, 0);
} // end setup()

/*
 *  Program execution
 */
void loop() 
{
   // debug
   Serial.print ("motorSpeedPin reads ");
   Serial.println (analogRead (motorSpeedPin)); 
   Serial.print ("motorPace is ");
   Serial.println (motorPace);
   Serial.print ("motorOn is ");
   Serial.println (motorOn);
   Serial.print ("motorOnOffPin reads ");
   Serial.println (digitalRead (motorOnOffPin));
   Serial.println("");

   delay (3000);
     
   accelerate();
   
   // debug
   Serial.print ("motorSpeedPin reads ");
   Serial.println (analogRead (motorSpeedPin)); 
   Serial.print ("motorPace is ");
   Serial.println (motorPace);
   Serial.print ("motorOn is ");
   Serial.println (motorOn);
   Serial.print ("motorOnOffPin reads ");
   Serial.println (digitalRead (motorOnOffPin));
   Serial.println("");
   
   delay (3000);
   
  decelerate ();
} // end loop()


// this routine starts the motor and accelerates it to cruise speed
bool accelerate()
{
  // assert : trolley is stopped and motor is off
  // motorOn = false
  // motorPace = 0
  // motorOnOffPin = LOW       
  // motorSpeedPin = 0
    
  // set the flag
  motorOn = true;
  // give motorPace a start value
  motorPace = motorCreep;
  // turn on the motor
  digitalWrite (motorOnOffPin, HIGH);
  // get the motor moving
  analogWrite (motorSpeedPin, motorCreep);
  // steadily speed up the motor
  while (motorPace <= motorCruise)
  {
    motorPace++;
    analogWrite (motorSpeedPin, motorPace);
    delay (20);   
  } // end while (motorPace <= motorCruise)
  
  // assert: trolley is moving at cruise speed
  // motorOn = true  
  // motorPace = motorCruise  
  // motorOnOffPin = HIGH  
  // motorSpeedPin = motorCruise
  
} // end accelerate()

// this routine decelerates motor from current speed to stopped
bool decelerate ()
{
  // assert: trolley is moving a cruise speed
  // motorOn = true  
  // motorPace = motorCruise  
  // motorOnOffPin = HIGH  
  // motorSpeedPin = motorCruise
  
  // steadily slow down the motor
  while (motorPace > motorCreep)
  {
    motorPace--;
    analogWrite (motorSpeedPin, motorPace);
    delay (20);
  } // end while motorPace > motorCreep)

  // stop the motor
  analogWrite (motorSpeedPin, 0); 
  // turn the motor off
  digitalWrite (motorOnOffPin, LOW);
  // record the pace
  motorPace = 0;
  // unset the flag
  motorOn = false;
  
  // assert : trolley is stopped and motor is off
  // motorOn = false
  // motorPace = 0
  // motorOnOffPin = LOW       
  // motorSpeedPin = 0
  
} // end decelerate(

I have a movie of this thing in simulation using LCDs instead of the motor. Sorry about the download but its too big to attach. The Red LCD is the signal that the motor is on (lit) or off. The Green LCD echoes the revving up and revving down of the motor.

Two curiosities here:

  1. Why does the motor rev up three times, then rev down three times in each cycle?

  2. The intention is the that motor revs up, maintains the high revs, then revs down in each cycle. That is not what the Green LCD appears to indicate. Why does it not get to high glow and stay there until it fades down and the end of the cycle?

Any elucidation will be greatly appreciated.

You got the analogWrite wrong for

[color=red]int[/color]  motorPace      = 0;     // current motor speed in PWM

...

  // get the motor moving
  analogWrite (motorSpeedPin, [color=red]motorCreep[/color]);
  // steadily speed up the motor
  while (motorPace <= motorCruise)
  {
    [color=red]motorPace++;[/color]
    analogWrite (motorSpeedPin, [color=red]motorPace[/color]);
    delay (20);   
  } // end while (motorPace <= motorCruise)

What you need to pass to analogWrite is the duty cycle - that is a value between 0 (always off) and 255 (always on).

So the reason you see 3 rounds is because you pass an int and the function only uses the least significant byte

Your motor speed value moves from motorCreep = 300 to motorCruise = 1023

motorCreep = 300 in decimal which is 0x012C so you initialize actually your motor at 2C ==> actual duty cycle is = 44
then you increase to 301 --> duty cycle = 45
then you increase to 302 --> duty cycle = 46
...
then you increase to 511 (binary 0x1FF) --> duty cycle = 0xFF = 255 ==> FULL STEAM on!
then you increase to 512 (binary 0x200) --> duty cycle = 00 ==> stop
then you increase to 513 --> duty cycle = 01
...
then you increase to 767 (binary 0x2FF) --> duty cycle = 0xFF = 255 ==> FULL STEAM on!
then you increase to 768 (binary 0x300)--> duty cycle = 00 ==> stop
then you increase to 769 --> duty cycle = 01
...
then you increase to 1023 --> duty cycle = 255 ==> FULL STEAM on!

so you have there your 3 "FULL STEAM on" cycles. Same happens the other way when you decelerate

makes sense?

Thanks J-M-L. That certainly fixed the triple cycle problem. All I did was change a couple of constants

 const int  motorCruise    = 255;  //1023;  // cruising setting in PWM
 const int  motorCreep     = 20;  //300;   // very slow motor speed in PWM

Works a treat!

But now, why does the Green LCD go OFF between accelerate() and decelerate(). My thinking was that the last cycle of the loop in accelerate() would set the PWM to motorSpeedPin to motorCruise. motorSpeedPin being global, the PWM should remain unchanged until the call to decelerate().

Why not so?

  while (motorPace <= motorCruise)
  {
    motorPace++;
    analogWrite (motorSpeedPin, motorPace);
    delay (20);   
  } // end while (motorPace <= motorCruise)

motorPace overflows to 0 when motorPace == motorCruise and you increment. Chang the loop to (motorPace < motorCruise).

Those aren't LCDs, mate.

Thanks johnwasser. Now my LEDs (INTP) behave themselves.