How to implement elapsed millis as the timer for my motor spinning time?

I have been using delay() as the function for my motor spinning time. However, at the same time, I need to calculate the rpm of my motor. Delay() function have to make it impossible for me to get the rpm whilst the motor spin. I have learned that I needed to use Elapsed millis as a replacement for delay() for my timing.

I have tried it and to no avail, I did not get the result in wanted. Yes, the motor spin according to the speed that I desired, however, it does not spin according to the time I wanted. It kept on spinning non-stop till I have to disconnect the power supply.

So, my question is, how do I implement the elapsed millis as my timer for my spinning motor?
please, guys, help me with this… Just guide me through and give me guidance.

This is my code that I have tried using elapsed millis. Any suggestion is welcome.

#include <elapsedMillis.h>
#include <Keypad.h>
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
Servo myservo;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
elapsedMillis timeElapsed;

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
{
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {9,8,7,6}; //row pinouts of the keypad (L1, L2, L3, L4)
byte colPins[COLS] = {5,4,3}; //column pinouts of the keypad (R1, R2, R3)
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

 
void setup()
{ 
   
  Serial.begin(9600);
  lcd.begin(20,4);
  myservo.attach(11);

   lcd.setCursor(0,0);
  lcd.print("S=");
  lcd.setCursor(0,1);
  lcd.print("T=");
  lcd.setCursor(0,2);
  lcd.print("S=");
  lcd.setCursor(0,3);
  lcd.print("T=");
  lcd.setCursor(10,0);
  lcd.print("S=");
  lcd.setCursor(10,1);
  lcd.print("T=");
  lcd.setCursor(10,2);
  lcd.print("RPM");
 
}


 void loop()
 
{ 
  
  int stage1speed = getTheNumber();
  lcd.setCursor(2,0);
  lcd.print(stage1speed);
  lcd.print("sv");
  int stage1time = getTheNumber();
  lcd.setCursor(2,1);
  lcd.print(stage1time);
  lcd.print("sec");
  
  int stage2speed = getTheNumber();
  lcd.setCursor(2,2);
  lcd.print(stage2speed);
  lcd.print("sv");
  int stage2time = getTheNumber();
  lcd.setCursor(2,3);
  lcd.print(stage2time);
   lcd.print("sec");
  

  int stage3speed = getTheNumber();
  lcd.setCursor(12,0);
  lcd.print(stage3speed);
  lcd.print("sv");
  int stage3time = getTheNumber();
  lcd.setCursor(12,1);
  lcd.print(stage3time);
  lcd.print("sec");
  




   if ( stage1speed > 0 && stage1time > 0 && stage2speed > 0 && stage2time > 0 && stage3speed > 0 
        && stage3time > 0 )

   {

    if(timeElapsed <= 1000*stage1time)

    {

     myservo.write(stage1speed);

     }

    if(timeElapsed <= 1000*stage2time)

    {

     myservo.write(stage2speed);

     }

    if(timeElapsed <= 1000*stage3time)

    {

     myservo.write(stage3speed);

     }
  }

}
   


int getTheNumber()
{
    char buffer[4];
    // Input up to 3 numbers until we find a * or #
    int i=0;
    while (1)
    {
        char key = keypad.getKey();

        // If it's a number AND we have space left, add to our string
        if ('0' <= key && key <= '9' && i < 3)
        {
            buffer[i] = key;
            i++;        
        }
        // If it's a * or #, end
        else if ('#' == key && i > 0)
        {
            // Null terminate
            buffer[i] =0; 
           int value = atoi(buffer);  // Convert to an integer
            break;
        } 
           
    }
    return atoi(buffer);
    }

Rather than using a library that you don’t understand I suggest you just control your timing directly using millis() as illustrated in Several Things at a Time

…R

Hi sir, my project requires me to use elapsed millis, I have tried to do it in state machine. I have no idea where I go wrong. Maybe you can pinpoint my mistakes in my coding. The code compiled, however when I key in the speed and time, the motor only spin at the stage1speed and no timing.

Here is the code and modification I made using state machine:

#include <elapsedMillis.h>
#include <Keypad.h>
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
Servo myservo;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
elapsedMillis timeElapsed;
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
{
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {9,8,7,6}; //row pinouts of the keypad (L1, L2, L3, L4)
byte colPins[COLS] = {5,4,3}; //column pinouts of the keypad (R1, R2, R3)
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
unsigned int interval = 1000;
int idleValue=0; 
void setup()
{ 
   
  Serial.begin(9600);
  lcd.begin(20,4);
  myservo.attach(11);

  lcd.setCursor(4,1);
  lcd.print("SPIN COATER");
  lcd.setCursor(6,2);
  lcd.print("MACHINE");
  delay(5000);
  lcd.clear();

  lcd.setCursor(3,1);
  lcd.print("S = speed(sv)");
  lcd.setCursor(3,2);
  lcd.print("T = time(sec)");
  delay(5000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Servo value (sv):");
  lcd.setCursor (3,2);
  lcd.print("Between 103-180");
  delay (10000); 
  
  lcd.clear();


  lcd.setCursor(0,0);
  lcd.print("S=");
  lcd.setCursor(0,1);
  lcd.print("T=");
  lcd.setCursor(0,2);
  lcd.print("S=");
  lcd.setCursor(0,3);
  lcd.print("T=");
  lcd.setCursor(10,0);
  lcd.print("S=");
  lcd.setCursor(10,1);
  lcd.print("T=");
  lcd.setCursor(10,2);
  lcd.print("RPM");
   
}


 void loop()
 
{ 
  int stage1speed = getTheNumber();
  lcd.setCursor(2,0);
  lcd.print(stage1speed);
  lcd.print("sv");
  int stage1time = getTheNumber();
  lcd.setCursor(2,1);
  lcd.print(stage1time);
  lcd.print("sec");
  
  int stage2speed = getTheNumber();
  lcd.setCursor(2,2);
  lcd.print(stage2speed);
  lcd.print("sv");
  int stage2time = getTheNumber();
  lcd.setCursor(2,3);
  lcd.print(stage2time);
   lcd.print("sec");
  

  int stage3speed = getTheNumber();
  lcd.setCursor(12,0);
  lcd.print(stage3speed);
  lcd.print("sv");
  int stage3time = getTheNumber();
  lcd.setCursor(12,1);
  lcd.print(stage3time);
  lcd.print("sec");

  
static enum { IDLE, STAGE1, STAGE2, STAGE3 } state;
switch (state) {
    case IDLE:
        if ( stage1speed > 0 && stage1time > 0 && stage2speed > 0 && stage2time > 0 && stage3speed > 0 && stage3time > 0  ) 
        {
            myservo.write(stage1speed);
            state = STAGE1;
            timeElapsed = 0;
        }
        break;
    case STAGE1:
        if (timeElapsed >= stage1time*interval) {
            myservo.write(stage2speed);
            state = STAGE2;
            timeElapsed = 0;
        }
        break;
    case STAGE2:
        if (timeElapsed >= stage2time*interval) {
            myservo.write(stage3speed);
            state = STAGE3;
            timeElapsed = 0;
        }
        break;
    case STAGE3:
        if (timeElapsed >= stage3time*interval) {
            myservo.write(idleValue);
        }
        break;
}
  }
   


int getTheNumber()
{
    char buffer[4];
    // Input up to 3 numbers until we find a * or #
    int i=0;
    while (1)
    {
        char key = keypad.getKey();

        // If it's a number AND we have space left, add to our string
        if ('0' <= key && key <= '9' && i < 3)
        {
            buffer[i] = key;
            i++;        
        }
        // If it's a * or #, end
        else if ('#' == key && i > 0)
        {
            // Null terminate
            buffer[i] =0; 
           int value = atoi(buffer);  // Convert to an integer
            break;
        } 
           
    }
    return atoi(buffer);
    }

rjadkins: Hi sir, my project requires me to use elapsed millis,

Why?

And if it does I'm afraid I am not familiar with that library. But I do have a program that measures the speed of a small DC motor.

And it seems to me very strange to be setting the stage1speed when you are not in the STAGE1 state. That will trip you up some day.

case IDLE:
        if ( stage1speed > 0 && stage1time > 0 && stage2speed > 0 && stage2time > 0 && stage3speed > 0 && stage3time > 0  )
        {
            myservo.write(stage1speed);
            state = STAGE1;
            timeElapsed = 0;
        }
        break;
    case STAGE1:

...R

rjadkins: Hi sir, my project requires me to use elapsed millis, I have tried to do it in state machine. I have no idea where I go wrong. Maybe you can pinpoint my mistakes in my coding. The code compiled, however when I key in the speed and time, the motor only spin at the stage1speed and no timing.

Here is the code and modification I made using state machine:

ElapsedMillis is like a resettable millis(). You save like 1 or 2 lines of code using it. Using millis() directly you save the value into a variable and then use millis() - variable to get the elapsed time.

If I read the code correct, at start you set your speeds and times for all the stages. Next enters switch case and motor start to spin. Then main loop jumps back to top of loop() asking for new inputs. Here I see 2 possibilities. Your program halts waiting for new input or you need to input new values to continue.

Sir, I have decided to use millis() as my timer. However, the motor spins only on stage1speed and does not follow the timing set in stage1time. Moreover, how do I make the motor to spin according to 3 separate speed and time? What I want this program to do is to use the key in values to spin the motor in 3 stages.

The first stage is stage1speed and stage1time, after stage1time is fulfill, the motor continue to spin according to stage2speed and stage2time and then repeat the process with stage3speed and stage3time. After that, the motor stop immediately after stage3time is finished.

Somehow, I cannot make the program to run the way I wanted it to be. Maybe you can shed a little light upon the usage of millis(). I have been using delay() all this time, but delay() have cause some of my program not functioning.

Please, sir, help me solve this.

Here is the code:

#include <Keypad.h>
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
Servo myservo;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
{
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {9,8,7,6}; //row pinouts of the keypad (L1, L2, L3, L4)
byte colPins[COLS] = {5,4,3}; //column pinouts of the keypad (R1, R2, R3)
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

unsigned long previousMillis = 0;
const unsigned long delayTime = 1000; // how long you want your delay to be, in this case 1000 mS

void setup()
{ 
   
  Serial.begin(9600);
  lcd.begin(20,4);
  myservo.attach(11);

  lcd.setCursor(4,1);
  lcd.print("SPIN COATER");
  lcd.setCursor(6,2);
  lcd.print("MACHINE");
  delay(5000);
  lcd.clear();

  lcd.setCursor(3,1);
  lcd.print("S = speed(sv)");
  lcd.setCursor(3,2);
  lcd.print("T = time(sec)");
  delay(5000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Servo value (sv):");
  lcd.setCursor (3,2);
  lcd.print("Between 103-180");
  delay (10000); 
  
  lcd.clear();


  lcd.setCursor(0,0);
  lcd.print("S=");
  lcd.setCursor(0,1);
  lcd.print("T=");
  lcd.setCursor(0,2);
  lcd.print("S=");
  lcd.setCursor(0,3);
  lcd.print("T=");
  lcd.setCursor(10,0);
  lcd.print("S=");
  lcd.setCursor(10,1);
  lcd.print("T=");
  lcd.setCursor(10,2);
  lcd.print("RPM");
   
}


 void loop()
 
{ 
  
  int stage1speed = getTheNumber();
  lcd.setCursor(2,0);
  lcd.print(stage1speed);
  lcd.print("sv");
  int stage1time = getTheNumber();
  lcd.setCursor(2,1);
  lcd.print(stage1time);
  lcd.print("sec");
  
  int stage2speed = getTheNumber();
  lcd.setCursor(2,2);
  lcd.print(stage2speed);
  lcd.print("sv");
  int stage2time = getTheNumber();
  lcd.setCursor(2,3);
  lcd.print(stage2time);
   lcd.print("sec");
  

  int stage3speed = getTheNumber();
  lcd.setCursor(12,0);
  lcd.print(stage3speed);
  lcd.print("sv");
  int stage3time = getTheNumber();
  lcd.setCursor(12,1);
  lcd.print(stage3time);
  lcd.print("sec");



  if ( stage1speed > 0 && stage1time > 0 && stage2speed > 0 && stage2time > 0 && stage2speed > 0 && stage2time > 0 )
  {
    unsigned long currentMillis = millis();
    unsigned long passedTime = currentMillis - previousMillis;

    if (passedTime >= delayTime*stage1time)// servo spin according to time 
    {
       myservo.write(stage1speed);   // servo spin according to the key in speed
       previousMillis = currentMillis; // reset your delay timer
    }
     else if ((passedTime < delayTime*stage1time) &&  (passedTime >= delayTime*stage2time)) // servo spin after stage1time is completed with stage2speed
    {
       myservo.write(stage2speed);// servo spin according to the key in speed
      previousMillis = currentMillis; // reset your delay timer
    }
      else if ((passedTime < delayTime*stage2time) &&  (passedTime >= delayTime*stage3time))// servo spin after stage2time is completed with stage3speed
    {
       myservo.write(stage3speed);// servo spin according to the key in speed
      previousMillis = currentMillis; // reset your delay timer
    }
     else if (passedTime < delayTime*stage3time ) // motor stop spin right after stage3time have complete
    {
       myservo.write(0);
       previousMillis= currentMillis; // reset your delay timer    
  }
  }
   
}

int getTheNumber()
{
    char buffer[4];
    // Input up to 3 numbers until we find a * or #
    int i=0;
    while (1)
    {
        char key = keypad.getKey();

        // If it's a number AND we have space left, add to our string
        if ('0' <= key && key <= '9' && i < 3)
        {
            buffer[i] = key;
            i++;        
        }
        // If it's a * or #, end
        else if ('#' == key && i > 0)
        {
            // Null terminate
            buffer[i] =0; 
           int value = atoi(buffer);  // Convert to an integer
            break;
        } 
           
    }
    return atoi(buffer);
    }

This is not the way to use millis()

unsigned long passedTime = currentMillis - previousMillis;

    if (passedTime >= delayTime*stage1time)// servo spin according to time

just do it the simple way

if (currentMillis - previousMillis >= delayTime * stage1time) {

Can you set out for us (in a English rather than code) how the stages are intended to operate - especially the timing for each.

...R

There are 3 stages . The stages flow continuously until the time in stage 3 have been completed. The motor must spins according to the time given. For example, for stage one, the speed is set :180 servo value , time: 30 second. The motor must spin at 180 speed within that 30 second. Once the 30second is finish, the motor then go to stage 2 , taking the speed(eg 123 servo value) and time(eg 20sec) that have been set for stage 2. After the motor finish spinning at 123 in 20 second, the motor then enter stage 3. Stage 3 with speed 103 and time 50 sec. Motor spin at speed of 103 and time 50 sec, once the 50sec is up, the motor stop immediately to speed of 0. Then , that's the end of the stages of motor flow. I hope this clarifies all.

Mr. Gabriel, what modifications should I do if I want to use switch case to move my motor.? Please help me out sir, I really need this.. I need condition for the IDLE if(.....) So that the programming can run the whole code.

rjadkins: There are 3 stages . The stages flow continuously until the time in stage 3 have been completed. The motor must spins according to the time given. For example, for stage one, the speed is set :180 servo value , time: 30 second. The motor must spin at 180 speed within that 30 second. Once the 30second is finish, the motor then go to stage 2 , ....

To get that to work you should first move to stage1 (however that happens) and as the first thing in stage1 save the value of millis() and set the motor speed.

Then when the stage1 time has elapsed move to stage2. As the first thing in stage 2 ... (same as for stage1)

Something like this

void updateStages() {
  if (stage == 0) {
    if (something is done to move to stage1) {
       stage ++;
    }
 }
 else if (stage == 1 && stageStarted = false) {
   startMillis = millis();
   stageTime = 30000;
   motorSpeed = 180;
   stageStarted = true;
 }
 else if (stage == 2 && stageStarted = false) {
   startMillis = millis();
   stageTime = 2000;
   motorSpeed = 123;
   stageStarted = true;
 }
 // etc
}

void checkTime() {
   if (millis() - startMillis >= stageTime) {
     stage ++; // move to next stage
     stageStarted = false;
   }
}

void motorMove() {
   servo.write(motorSpeed);
}

and the code in loop() would be something like

void loop() {
  updateStages();
  checkTime();
  motorMove();
}

...R

can I use if ( key == '*') to move the stage??

rjadkins: can I use if ( key == '*') to move the stage??

I can't answer that without seeing it in the context of your program

If there can be an asterisk character in a variable called "key" I can't see why the line of code would not work - but whether it would make sense in context is a whole other ballgame.

...R

I can't answer that without seeing it in the context of your program

You can see the program on page 3 of the other thread asking the same question http://forum.arduino.cc/index.php?topic=455176.50

I had no idea I was wasting my time on a duplicate Thread. Thanks for pointing it out.

...R