Motor not running after execute 'START'

Hi, I have connected a keypad, LCD_I2C, Hall effect sensor and a DC motor thru a motor driver (MD25HV). I made a menu which (1) will enter the speed using the keypad (2) enter the time and (3) to start the motor. But somehow my motor driver does not receive the signal of the PWM.

#include <LiquidCrystal_I2C.h>
#include <Keypad.h>;
#include "CytronMotorDriver.h"
#define HASKEYPAD
#define LCD20X4

// LCD variables
#define LCD_ADDRESS 0x27
#define LCD_ROWS 4
#define LCD_COLUMNS 20
#define SCROLL_DELAY 150
#define BACKLIGHT 255
LiquidCrystal_I2C lcd(0x27, 20, 4);

 //motor driver variable
CytronMD motor(PWM_DIR, 11, 12);  // PWM = Pin 11, DIR = Pin 12.

#define ST_DISPLAY_MAINMENU 0
#define ST_WAIT 1
#define ST_SETSPEED 2
#define ST_SETTIMING 3
#define ST_SETMOTOR 4

// options to control the motor
#define MOTOR_CONTINUE 0
#define MOTOR_START 1
#define MOTOR_FORCESTOP 2


//HE sensor define
byte sensor = 13;
unsigned long startTime;
unsigned long endTime;
unsigned long duration;
byte timerRunning;
int RPM = 0;
int count = 0;
int totRPM = 0;
int avgRPM = 0;
//20000/255=78.43

#ifdef HASKEYPAD

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

char keys[ROWS][COLS] = {
  {'0', '#', '0', '*'},
  {'8', '9', '8', '7'},
  {'5', '6', '5', '4'},
  {'2', '3', '2', '1'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

Keypad customKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
#else
#define NO_KEY 0
#endif

// initialize the library with the numbers of the interface pins
/*
#ifdef LCD20X4
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);
#else
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
#endif
*/

// the state of our application; start with main menu display
byte currentState = ST_DISPLAY_MAINMENU;

// speed and timing variables
// both are global so we can display them in the main menu
int theSpeed = 0;
long theTiming = 0;


void setup() {
  //serial start 
  Serial.begin(9600);
 //setup for HE sensor
  pinMode (sensor, INPUT_PULLUP);
  // set up the LCD's number of columns and rows:
  lcd.begin();
}

void loop()
{
  // single key from keypad
  char key;
  // text from keypad
  char *text;

  // let the motor do what it was doing
  runMotor(MOTOR_CONTINUE);

  //Serial.print("Speed: "); Serial.println(theSpeed);

  switch (currentState)
  {
    case ST_DISPLAY_MAINMENU:
      // display main menu
      displayMenu();
      // switch to wait state
      currentState = ST_WAIT;
      break;
      
    case ST_WAIT:
      // get key
      key = getKeyWithEcho();
      // if speed setting selected
      if (key == '1')
      {
        // display speed 'menu'
        displaySpeedMenu();
        // change to state where user can enter speed
        currentState = ST_SETSPEED;
      }
      // if timing setting selected
      if (key == '2')
      {
        // display 'timing' menu
        displayTimingMenu();
        // change to state where user can enter timing
        currentState = ST_SETTIMING;
      }
       // if timing setting selected
      if (key == '3')
      {
        // display 'timing' menu
        displayMotorMenu();
        // change to state where user can enter timing
        currentState = ST_SETMOTOR;
      }
      // Note: state does not change if entry is not '1' or '2' or '3'
      break;
      
    case ST_SETSPEED:
      // get the text entered on the keypad
      text = getKeypadText();
      // if text complete
      if (text != NULL)
      {
        // if user did enter a speed
        if (text[0] != '\0')
        {
          theSpeed = atoi(text);
        }
        currentState = ST_DISPLAY_MAINMENU;
      }
      break;
      
    case ST_SETTIMING:
      // get the text entered on the keypad
      text = getKeypadText();
      // if text complete
      if (text != NULL)
      {
        // if user did enter a speed
        if (text[0] != '\0')
        {
          theTiming = atoi(text);
          runMotor(MOTOR_START);
        }
        currentState = ST_DISPLAY_MAINMENU;
      }
      break;

      case ST_SETMOTOR:
      // get the text entered on the keypad
      text = getKeypadText();
      // if text complete
      if (text != NULL)
      {
        // if user did enter a speed
        if (text[0] != '\0')
        {
          runMotor(MOTOR_START);
        }
        currentState = ST_DISPLAY_MAINMENU;
      }
      break;
  } // end_of_switch

}


/*
  display a title on the first line of the display; it always clears the LCD
*/
void displayTitle()
{
  // clear the lcd
  lcd.clear();

  // print the project title on the first line
  //lcd.setCursor(0, 0);
  //lcd.print("");
}

/*
  display main menu
*/
void displayMenu()
{
  lcd.clear();
  // current line where to write on LCD; every time that we write, currentLine will be incremented
  byte currentLine = 0;
  // text buffer for 20 characters and string terminator
  char textbuffer[21];

  // display the title on the first line and update currentLine
  //displayTitle();
  currentLine = 0;

  // print the current settings on the second line
  lcd.setCursor(0, currentLine++);
  sprintf(textbuffer, "S = %d, T = %d", theSpeed, theTiming);
  lcd.print(textbuffer);


  // print the first menu option on the third line
  lcd.setCursor(0, currentLine++);
  lcd.print("1 Set speed");

  // print the second menu option on the fourth line
  lcd.setCursor(0, currentLine++);
  lcd.print("2 Set time");

  lcd.setCursor(0, currentLine++);
  lcd.print("3 START");

}

/*
  display a 'menu' where the user can enter a speed
*/
void displaySpeedMenu()
{
  // display the title on the 1st line
  //displayTitle();
  lcd.clear();
  // display additional info on 3rd line
  lcd.setCursor(0, 2);
  lcd.print("#Finish, *Cancel");

  // prompt user to set speed (2nd line)
  lcd.setCursor(0, 1);
  lcd.print("Set speed: ");
}


/*
  display a 'menu' where the user can enter a timing
*/
void displayTimingMenu()
{
  // display the title on the 1st line
  //displayTitle();

  // display additional info on 3rd line
  lcd.clear();
  lcd.setCursor(0, 2);
  lcd.print("#Finish, *Cancel");

  // prompt user to set speed (2nd line)
  lcd.setCursor(0, 1);
  lcd.print("Set time: ");
}

/*
  display a 'menu' where the user can enter a speed
*/
void displayMotorMenu()
{
  // display the title on the 1st line
  //displayTitle();
   lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Spincoat RUNNING!");
    lcd.setCursor(0, 1);
    lcd.print("Please wait");
}

CytronMotorDriver.cpp (931 Bytes)

CytronMotorDriver.h (631 Bytes)

coding too long so this is the left of it

/*
  get a keystroke from the keypad
  echo the key that was pressed to the LCD
  the echo will be on the current position of the LCD
  returns
    the key that was pressed or NO_KEY
*/
char getKeyWithEcho()
{
  // read a key
#ifdef HASKEYPAD
  char key = customKeypad.getKey();
#else
  char key;
  if (Serial.available() > 0)
  {
    key = Serial.read();
  }
  else
  {
    key = NO_KEY;
  }

#endif
  // if no key pressed
  if (key != NO_KEY)
  {
    // for debugging, output to serial monitor
    Serial.print("Key: "); Serial.println(key);
    // display on current position of LCD
    lcd.print(key);
  }
  return key;
}

/*
  get a text from the keypad (max 20 characters)
  '#' finishes the entry of data
  '*' cancels the entry of data
  returns
    NULL if not complete
    empty text if canceled
    entered tet (might be empty)
*/
char *getKeypadText()
{
  // a buffer for 20 keypresses and one
  static char keypadbuffer[21];
  // index in above buffer
  static char index = 0;

  // read a key
  char key = getKeyWithEcho();
  // if nothing pressed
  if (key == NO_KEY)
  {
    // indicate no complete data
    return NULL;
  }
  // if 'cancel' key
  if (key == '*')
  {
    // reset index
    index = 0;
    // create empty text
    keypadbuffer[index] = '\0';
    // return text
    return keypadbuffer;
  }
  // if 'enter' key
  if (key == '#')
  {
    // add a string terminator
    keypadbuffer[index] = '\0';
    // reset index for next time
    index = 0;
    // return the text
    Serial.println(keypadbuffer);
    return keypadbuffer;
  }
  // check for buffer overflow
  if (index >= sizeof(keypadbuffer))
  {
    // add a string terminator
    keypadbuffer[sizeof(keypadbuffer) - 1] = '\0';
    // reset index for next time
    index = 0;
    // return the text
    return keypadbuffer;
  }

  // add the character to the buffer
  keypadbuffer[index++] = key;

  // indicate that text is not complete
  return NULL;
}


/*
  starts or stops the motor or runs the motor for a given time
  parameter
    option: option to control motor
    MOTOR_FORCESTOP: force an (emergency) stop; oberrides any other options
    MOTOR_START: if not started, start it; if already started, it's ignored
    for any other option value, motor keeps on doing what it was doing
*/
void runMotor(byte options)
{
  // the 'time' that the motor started running
  static unsigned long motorRunStarttime = 0;

  // if FORCESTOP received
  if ((options & MOTOR_FORCESTOP) == MOTOR_FORCESTOP)
  {
    // for debugging
    Serial.println("FORCESTOP received");
    // stop the motor
    motor.setSpeed(0);
    // reset start 'time'
    motorRunStarttime = 0;
    // nothing more to do
    return;
  }

  // if START received and motor not started yet
  if ((options & MOTOR_START) == MOTOR_START && motorRunStarttime == 0)
  {
    // for debugging
    Serial.println("START received while motor was not running");
    Serial.print("Speed: "); Serial.println(theSpeed);
    Serial.print("Timing: "); Serial.println(theTiming);
    
    // for LCD
    lcd.clear();
    lcd.println("START received while motor was not running");
    lcd.print("Speed: "); lcd.println(theSpeed);
    lcd.print("Timing: "); lcd.println(theTiming);

    // set the start 'time'
    motorRunStarttime = millis();
    
    // serial display the start time
    Serial.print("Time: "); Serial.println(motorRunStarttime);
    
    //lcd display the start time
    lcd.clear();
    lcd.print("Time: "); lcd.println(motorRunStarttime);
  }

  // if the motor has run for the specified duration
  if (millis() - motorRunStarttime >= (theTiming * 1000UL))
  {
    // inform the user that motor has stopped
    if (motorRunStarttime != 0)
    {
      //Motor stopped message
      lcd.clear();

      //motor stop
      motor.setSpeed(0);
      lcd.print("Motor stopped");
      lcd.setCursor(0, 2);
      lcd.print("Please wait");
      delay(3000);

      //Spinocat completed message
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Spincoat Completed");
      lcd.setCursor(0, 1);
      lcd.print("Open the lid");
      //lcd.setCursor(0, 1);
      //lcd.print("End Time: "); lcd.println(millis());
      lcd.setCursor(0, 3);
      lcd.print("0# Return MAINMENU");

      //debugging
      Serial.println("Motor stopped");
      Serial.print("End Time: "); Serial.println(millis());
    }
    // stop the motor;
    motor.setSpeed(0);
    // reset the start 'time'
    motorRunStarttime = 0;
  }
  else
  {
    // set the motor speed
    if (theSpeed >= 0 && theSpeed <= 255)
    {
      motor.setSpeed(theSpeed);
    }
  }
}

One important detail that you left out: does the motor work when you have a simple sketch that starts and stops the motor with some hard coded values?

...
...
int theSpeed = 50;
long theTiming = 1000;

...
...

void setup()
{
  ...
  ...
}

void loop()
{
  runMotor(MOTOR_START);
}

sterretje:
One important detail that you left out: does the motor work when you have a simple sketch that starts and stops the motor with some hard coded values?

...

...
int theSpeed = 50;
long theTiming = 1000;

...
...

void setup()
{
  ...
  ...
}

void loop()
{
  runMotor(MOTOR_START);
}

I tried using the motor driver sketch it works, using like you suggested it does not work after execute start

What do all the debug prints in this section say?

void runMotor(byte options)

cattledog:
What do all the debug prints in this section say?

void runMotor(byte options)

So the debug section has Motor_Start and motor_forcestop. For 'motor_forcestop' it will send '0' to the motor driver if called. For 'motor_start' it will send the speed setting that is 'theSpeed' (Value 0~255 entered from the keypad) to the motor driver.

Syameer25:
So the debug section has Motor_Start and motor_forcestop. For 'motor_forcestop' it will send '0' to the motor driver if called. For 'motor_start' it will send the speed setting that is 'theSpeed' (Value 0~255 entered from the keypad) to the motor driver.

The question was what is displayed in serial monitor when you try to start the motor. Does it say*"START received while motor was not running"* and the speed and time? And possibly what else?

sterretje:
The question was what is displayed in serial monitor when you try to start the motor. Does it say*“START received while motor was not running”* and the speed and time? And possibly what else?

yes it does stated motor running and all

Please confirm that you are entering this section of code by adding some Serial printing. If you actually get to the motor.setSpeed(theSpeed) the motor should be running. Are you absolutely certain that the basic cytron motor driver example sketch runs the motor?

else
  {
    // set the motor speed
    if (theSpeed >= 0 && theSpeed <= 255)
    {
      Serial.println("motor.setspeed");
      motor.setSpeed(theSpeed);
    }
  }

When I run your code with my lcd setup and these fixed values I can see the code apparently running the repeat cycles of the motor.

//int theSpeed = 0;
//long theTiming = 0;
int theSpeed = 50;
long theTiming = 20;

I’m very doubtful about your lcd code. What exact library are you using? Where did it come from. Does it support lcd.println() syntax? You have many statements like this

// for LCD
    lcd.clear();
    lcd.println("START received while motor was not running");
    lcd.print("Speed: "); lcd.println(theSpeed);
    lcd.print("Timing: "); lcd.println(theTiming);

cattledog:
Please confirm that you are entering this section of code by adding some Serial printing. If you actually get to the motor.setSpeed(theSpeed) the motor should be running. Are you absolutely certain that the basic cytron motor driver example sketch runs the motor?

else

{
    // set the motor speed
    if (theSpeed >= 0 && theSpeed <= 255)
    {
      Serial.println(“motor.setspeed”);
      motor.setSpeed(theSpeed);
    }
  }




When I run your code with my lcd setup and these fixed values I can see the code apparently running the repeat cycles of the motor.


//int theSpeed = 0;
//long theTiming = 0;
int theSpeed = 50;
long theTiming = 20;




I'm very doubtful about your lcd code. What exact library are you using? Where did it come from. Does it support lcd.println() syntax? You have many statements like this


// for LCD
    lcd.clear();
    lcd.println(“START received while motor was not running”);
    lcd.print("Speed: "); lcd.println(theSpeed);
    lcd.print("Timing: "); lcd.println(theTiming);

  1. Yes Im very certain my cytron motor works by running its sketch, I tested the hardware and see it works like it should be.

  2. I’ll add the serial printing to ‘theSpeed’ section, thanks for the suggestion.

  3. Yes I forgot to remove the variables, because yesterday I tried hard coding as suggested, the motor driver receives the PWM signal from Arduino but the wires connecting the motor driver to the DC motor becomes so hot.

  4. I got the library from here: http://scienceclub.org.au/download/1602-lcd-display-serial-connection-arduino-library/

Hi guys appreciated all your help, I have made my motor running after execute ‘START’.
First I serial print every outcome as suggestes. After that I know whats wrong with the flow.
The problem was runmotor(Motor_START) was ran 2 times. Below are the fixes.

....
     case ST_SETSPEED:
      // get the text entered on the keypad
      text = getKeypadText();
      // if text complete
      if (text != NULL)
      {
        // if user did enter a speed
        if (text[0] != '\0')
        {
          theSpeed = atoi(text);
        }
        currentState = ST_DISPLAY_MAINMENU;
      }
      break;

    case ST_SETTIMING:
      // get the text entered on the keypad
      text = getKeypadText();
      // if text complete
      if (text != NULL)
      {
        // if user did enter a speed
        if (text[0] != '\0')
        {
          theTiming = atoi(text);
          /*runMotor(MOTOR_START);*/
        }
        currentState = ST_DISPLAY_MAINMENU;
      }
      break;

    case ST_SETMOTOR:
      {
        runMotor(MOTOR_START);
        currentState = ST_DISPLAY_MAINMENU;
      }
      break;
  } // end_of_switch

}

plus if anyone wanted to go back to main menu after the motor have stop you can edit the code as shown.

...
 // if the motor has run for the specified duration
  if (millis() - motorRunStarttime >= (theTiming * 1000UL))
  {
    // inform the user that motor has stopped
    if (motorRunStarttime != 0)
    {
      //Motor stopped message
      lcd.clear();

      //motor stop
      motor.setSpeed(0);
      lcd.print("Motor stopped");
      lcd.setCursor(0, 2);
      lcd.print("Please wait");
      delay(3000);

      //Spinocat completed message
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Spincoat Completed");
      lcd.setCursor(0, 1);
      lcd.print("Open the lid");
      //lcd.setCursor(0, 1);
      //lcd.print("End Time: "); lcd.println(millis());
      lcd.setCursor(0, 2);
      lcd.print("Return to Main Menu");
      lcd.setCursor(0, 3);
      lcd.print("Please w8");
      delay (2000);
      displayMenu();

      //debugging
      Serial.println("Motor stopped");
      Serial.print("End Time: "); Serial.println(millis());
    }
    // stop the motor;
    motor.setSpeed(0);
    Serial.println("motor done setSpeed = 0");``
    // reset the start 'time'
    motorRunStarttime = 0;
  }
  else
  {
    // set the motor speed
    if (theSpeed >= 0 && theSpeed <= 255)
    {
      Serial.println("Sending DATA to DRIVER");
      motor.setSpeed(theSpeed);
      Serial.println("theSpeed OK 1");
      Serial.println("theSpeed=");
      Serial.println(theSpeed);
    }
  }
}

Now I can proceed to my 2nd generation project. The heating of wire is because of the DC motor needed 5.5V with a pwm value of ‘127’ to start operating (no manual provided actually).