How to use millis() to run periodacally code line within a milli call

I written a code piece using millis to run dc motor using h-bridge on way. I want to stop it for fraction of time and then run backwards. I am not able to understand how to do it? If I write other functions for stop and opposit direction motor run, that probably is not option. As I think these all will be executed same time.

Here is my code:

//DC motor
const int pwm = 3;  //initializing pin 3 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;

//Sound sensor
//int soundSensor=2;
//boolean LEDStatus=false;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
const int motorUPinterval = 500;
const int motorUPduration = 3000;

byte motorState = LOW;
 
void setup() {
 
  Serial.begin(9600);
  Serial.println("starting......");
 
  pinMode(pwm,OUTPUT) ;   //we have to set PWM pin as output
  pinMode(in_1,OUTPUT) ;  //Logic pins are also set as output
  pinMode(in_2,OUTPUT) ;

}

void loop() {

    currentMillis = millis();

    runDCmotor(); // the method runs motor in one direction, I want the motor to stop and then run  
                        //backward same amount of time

     
 }

 void runDCmotor (){ 

      if(motorState == LOW) {

          if(currentMillis - previousMillis >= motorUPinterval) {
                      motorState = HIGH;
                      digitalWrite(in_1,HIGH) ;
                      digitalWrite(in_2,LOW) ;
                      analogWrite(pwm,255) ;       
                          
            }
       }

       else if(currentMillis - previousMillis >= motorUPduration)
               motorState = LOW;
               previousMillis += motorUPduration;
       
  }

You have only one procaessor, not much gets executed really “at the same time”, it’s sequential but fast in user time.

If you want to do two things in sequence with a pause in between and nothing else happening during the pause, then you can use delay()

moveForward();
delay(1000); // pause 1 sec
moveBackward();
delay(1000); // pause 1 sec
byte motorState = LOW;

You're nearly there!

Instead of making the motor states LOW and HIGH, think about adding a few more states. Like state 0 might be "waiting for start button", state 1 will be "moving forwards", state 2 will be "reversing back to start". After state 2, go back to state 0 again.

Since you don't seem to have a start button, you just need 1 and 2 for now.

Then split the runDCmotor() functions into two: let one manage the states. This looks at the times (and any other inputs) to decide when to change from 0 to 1 to 2 to 0. The second function should do the actual output: when in state 0, everything is off. State 1 and 2 will have different outputs. Note that the motor-output function doesn't have to know anything about buttons or millis(). It just drives in the direction that it's told to go.

I have to start the motor by sound sensor. Oo state 0 is 'waiting for input from sound sensor', state 1 'moving forward', state 2 'moving backward', and back to 0.

Do you mean I make three methods with 3 state machines of their own or one method with 3 using 3 state machines for all 3 states?

One question is I put 'motorUPduration' to set how much should it run in one direction and stop. But it keep running continuously. It will be problem I also when making 3 state machines as when one side motor motion stops and halts and start running other direction.

The code in this link may give you some ideas - it is in Reply #15

...R

Here is an example of a state machine close to what you want

enum : byte {WAITING_SOUND, SPIN_FWD, SHORT_PAUSE, SPIN_BWD} systemState;
unsigned long topChrono;
unsigned long currentDuration;
const unsigned long fwdDuration = 3000;   // 3 seconds
const unsigned long pauseDuration = 200;  // 0.2 seconds
const unsigned long bwdDuration = 3000;   // 3 seconds

boolean testSound()
{
  boolean soundOn = false;
  if (Serial.available()) {
    soundOn = ((char) Serial.read() == 'B'); // B for BOOOOM :)
  }
  return soundOn;
}

void spinFwd()
{
  Serial.println(F(" - MOTOR FWD"));
}

void stopMotor()
{
  Serial.println(F(" - MOTOR STOP"));
}

void spinBwd()
{
  Serial.println(F(" - MOTOR BWD"));
}

void waitForSound()
{
  systemState = WAITING_SOUND;
  Serial.println(F("\n\nENTER B to get started"));
}

void setup() {
  Serial.begin(115200);
  waitForSound();
}

void loop() {
  if ((systemState == WAITING_SOUND) && testSound()) {
    Serial.print(F("Millis = ")); Serial.print(millis());
    systemState = SPIN_FWD;
    topChrono = millis();
    currentDuration = fwdDuration;
    spinFwd();
  }

  if ((systemState != WAITING_SOUND) && (millis() - topChrono >= currentDuration)) {
    Serial.print(F("Millis = ")); Serial.print(millis());
    switch (systemState) {
      case SPIN_FWD: // we were in fwd mode and time is up, we stop the motor and wait a bit
        systemState = SHORT_PAUSE;
        topChrono = millis();
        currentDuration = pauseDuration;
        stopMotor();
        break;

      case SHORT_PAUSE:// we were in pause mode and time is up, we go spin the other way
        systemState = SPIN_BWD;
        topChrono = millis();
        currentDuration = bwdDuration;
        spinBwd();
        break;

      case SPIN_BWD: // we were in bwd mode and time is up, we stop the motor and wait for the sound
        stopMotor();
        waitForSound();
        break;

      default:
        Serial.println(F("ERROR THIS SHOULD NOT HAPPEN!"));
        break;
    }
  }


  // here you can do other stuff

}

if you run this, and you type B in the Serial monitor (setup at 115200 bauds) then you'll see the machine working and going through the stages at the pace we defined

this is the output:

[color=purple]
ENTER B to get started
Millis = 1286 - MOTOR FWD     [color=green]start time of motor t[sub]0[/sub] = 1286[/color]
Millis = 4286 - MOTOR STOP    [color=green]t[sub]1[/sub]=4286 - t[sub]0[/sub] = 3 seconds[/color]
Millis = 4486 - MOTOR BWD     [color=green]t[sub]2[/sub]=4486 - t[sub]1[/sub] = 0.2 seconds[/color]
Millis = 7486 - MOTOR STOP    [color=green]t[sub]3[/sub]=7486 - t[sub]2[/sub] = 3 seconds[/color]
[/color]

@MorganS:

I tried to split runDCmotor() into 2, one scheduler and other runDCmotor (). It is not working still. I am still thinking on the logic of how to stop when time elapsed and then run backward for same amount of time and do on.

Here is my code so far. It starts with clap and keeps running without break.

//DC motor
const int pwm = 3;  //initializing pin 2 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;


//Sound sensor
int soundSensor = 2;
boolean sensStatus = false;


//millis
unsigned long currentMillis = 0;

unsigned long previousUpMillis = 0;
const int motorUPinterval = 500;
const int motorUPduration = 3000;

/*
unsigned long previousDownMillis = 0;
const int motorDowninterval = 500;
const int motorDownDuration = 3000;
*/
byte motorState = LOW;


void setup() {

 Serial.begin(9600);

 pinMode(pwm, OUTPUT);  //we have to set PWM pin as output
 pinMode(in_1, OUTPUT); //Logic pins are also set as output
 pinMode(in_2, OUTPUT);

 pinMode(soundSensor, INPUT); //sound sensor

}

void loop() {

 currentMillis = millis();

 //sound sensor to start motor running by a clap
 int sensorData = digitalRead(soundSensor);
 if (sensorData == 1)
 {
   if (sensStatus == false)
   {
     sensStatus = true;
     runScheduleDCmotor();
     runDCmotor();
   }
   else {
     sensStatus = false;
   }
 }
}


void runScheduleDCmotor () {

 if (motorState == LOW) {
   if (currentMillis - previousUpMillis >= motorUPinterval) {
       motorState = HIGH;
   }
   } else if (currentMillis - previousUpMillis >= motorUPduration){
      motorState = LOW;
   previousUpMillis += motorUPduration; }
     }


void runDCmotor () {

 if (motorState == LOW) {
   digitalWrite(in_1, HIGH) ;
   digitalWrite(in_2, LOW) ;
   analogWrite(pwm, 255) ;
 }
 else if (motorState == HIGH)
 {
   digitalWrite(in_1, LOW) ;
   digitalWrite(in_2, HIGH) ;
   analogWrite(pwm, 255) ;
 }
}


void runNeoPixel() {

 //NeoPixel ring needs to run parallel to motor running, still to implement & it all start with sound sensor
}
    if (currentMillis - previousUpMillis >= motorUPinterval) {

motorState = HIGH;
    }
    } else if (currentMillis - previousUpMillis >= motorUPduration){
      motorState = LOW;
    previousUpMillis += motorUPduration; }

Can you see something different between these two actions that occur?

Please use code tags in the future.

Yes, first one is checking if the time elapsed is more than the interval between two pulse then it assigns HIGH value. While 2nd one checks if HIGH state exceeds the duration of a pulse so sate may be lowered when it does. And then last motorUPduration time is added to previous millis of the motor up counter.

You don't have enough states. LOW and HIGH are not enough. It's like a car with "Drive" and "Reverse" and no "Park".

See my sample code maybe for state management...

@J-M-L Yes, I tried to use state model in your provided example.
@MorganS: I added states, though even with previous states it was only using one state i.e. of BKWRDRUN.

Here is my current code with more states but its running motor in one direction constantly:

//DC motor
const int pwm = 3;  //initializing pin 2 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;


//Sound sensor
int soundSensor = 2;
boolean sensStatus = false;


//millis
unsigned long currentMillis = 0;

unsigned long previousUpMillis = 0;
const int motorUPinterval = 500;
const int motorUPduration = 3000;

unsigned long previousDOWNMillis = 0;
const int motorDOWNinterval = 50;
const int motorDOWNduration = 3000;

/*
unsigned long previousDownMillis = 0;
const int motorDowninterval = 500;
const int motorDownDuration = 3000;
*/
//byte motorState = LOW;

enum motorStateENUM {
   WAITING,
   FRWDRUN,
   BKWRDRUN,
   STOPPING,
   FINISHED,
};
motorStateENUM motorState = WAITING;


void setup() {

 Serial.begin(9600);

 pinMode(pwm, OUTPUT);  //we have to set PWM pin as output
 pinMode(in_1, OUTPUT); //Logic pins are also set as output
 pinMode(in_2, OUTPUT);

 pinMode(soundSensor, INPUT); //sound sensor

}

void loop() {

 currentMillis = millis();

 //sound sensor to start motor running by a clap
 int sensorData = digitalRead(soundSensor);
 if (sensorData == 1)
 {
   if (sensStatus == false)
   {
     sensStatus = true;
     runScheduleDCmotor();
     runDCmotor();
   }
   else {
     sensStatus = false;
   }
 }
}


void runScheduleDCmotor () {

 if (motorState == WAITING) {
   if (currentMillis - previousUpMillis >= motorUPinterval) {
       motorState = FRWDRUN;
   }
   } else if (currentMillis - previousUpMillis == motorUPduration){
      motorState = STOPPING;
   previousUpMillis += motorUPduration; 
     }
   else if (currentMillis - previousDOWNMillis >= motorDOWNinterval){
      motorState = BKWRDRUN;
   previousDOWNMillis += motorDOWNduration; 
     }

   else if (currentMillis - previousDOWNMillis >= motorDOWNduration){
      motorState = WAITING;
   previousDOWNMillis += motorDOWNduration; 
     }
   }
   

void runDCmotor () {

 if (motorState == WAITING) {
   digitalWrite(in_1, HIGH) ;
   digitalWrite(in_2, HIGH) ;
 }
 else if (motorState == FRWDRUN)
 {
   digitalWrite(in_1, LOW) ;
   digitalWrite(in_2, HIGH) ;
   analogWrite(pwm, 255) ;
 }
 if (motorState == STOPPING) {
   digitalWrite(in_1, HIGH) ;
   digitalWrite(in_2, HIGH) ;
 }
 else if (motorState == BKWRDRUN)
 {
   digitalWrite(in_1, HIGH) ;
   digitalWrite(in_2, LOW) ;
   analogWrite(pwm, 255) ;
 }
}


void runNeoPixel() {

 //NeoPixel ring needs to run parallel to motor running, still to implement & it all start with sound sensor
}

Compare your loop with mine - do you see the difference in handling the state machine?

Ok, thank you very much !
I think you wrote it for me. It's very nice example for me to understand & learn.

Here is my code now that I basically replaced things from my code to yours kind of stub. Its rotating the motor backward & forward.

//DC motor
const int pwm = 3;  //initializing pin 2 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;


[code]//Sound sensor
const int soundSensor = 2;
boolean sensStatus = false;

enum : byte {WAITING_SOUND, SPIN_FWD, SHORT_PAUSE, SPIN_BWD} systemState;
unsigned long topChrono;
unsigned long currentDuration;
const unsigned long fwdDuration = 3000;   // 3 seconds
const unsigned long pauseDuration = 200;  // 0.2 seconds
const unsigned long bwdDuration = 3000;   // 3 seconds

boolean testSound()
{
 //sound sensor to start motor running by a clap
 int sensorData = digitalRead(soundSensor);
 if (sensorData == 1)
 {
   if (sensStatus == false)
   {
     sensStatus = true;
    }
   else {
     sensStatus = false;
   }
 
 }
 return sensStatus;
}

void spinFwd()
{
   digitalWrite(in_1, LOW) ;
   digitalWrite(in_2, HIGH) ;
   analogWrite(pwm, 255) ;
}

void stopMotor()
{
  digitalWrite(in_1, HIGH) ;
  digitalWrite(in_2, HIGH) ;
}

void spinBwd()
{
   digitalWrite(in_1, HIGH) ;
   digitalWrite(in_2, LOW) ;
   analogWrite(pwm, 255) ;
}

void waitForSound()
{
 systemState = WAITING_SOUND;
 Serial.println(F("\n\nENTER B to get started"));
}

void setup() {
 Serial.begin(115200);
 waitForSound();
}

void loop() {
 if ((systemState == WAITING_SOUND) && testSound()) {
   Serial.print(F("Millis = ")); Serial.print(millis());
   systemState = SPIN_FWD;
   topChrono = millis();
   currentDuration = fwdDuration;
   spinFwd();
 }

 if ((systemState != WAITING_SOUND) && (millis() - topChrono >= currentDuration)) {
   Serial.print(F("Millis = ")); Serial.print(millis());
   switch (systemState) {
     case SPIN_FWD: // we were in fwd mode and time is up, we stop the motor and wait a bit
       systemState = SHORT_PAUSE;
       topChrono = millis();
       currentDuration = pauseDuration;
       stopMotor();
       break;

     case SHORT_PAUSE:// we were in pause mode and time is up, we go spin the other way
       systemState = SPIN_BWD;
       topChrono = millis();
       currentDuration = bwdDuration;
       spinBwd();
       break;

     case SPIN_BWD: // we were in bwd mode and time is up, we stop the motor and wait for the sound
       stopMotor();
       waitForSound();
       break;

     default:
       Serial.println(F("ERROR THIS SHOULD NOT HAPPEN!"));
       break;
   }
 }


 // here you can do other stuff

}

[/code]

I have to yet add Adafruit NeoPixel code to light the pixel ring as soon as & as long as motor starts & keep moving. I downloaded the source from adafruit site. But it uses delay fundtion, that I think would cause may be trouble when working with this code. But need to experiment.

One more thing is how to make sure the motor shaft stops stops after completing amount of time it's give for backward move? Basically because I have to use this motor to move the part of a lamp, up & down. So time will be calculated & adjusted to find how much time does motor take to move the moving part to down edge and how much to top edge. So it keeps moving within those limits.

But question is when motor is stopped, if it is stopped in middle and again started and it starts moving from there will break the moving part.

One problem with current code is it starts working without waiting for the sound signal from the sound sensor.

What’s your sound sensor? is it wired the right way?

if your sensor returns HIGH when it gets a 'clap' then the way to make this work is just to return that information.

boolean testSound()
{
  return (digitalRead(soundSensor) == HIGH);   //sound sensor to start motor running by a clap
}

the sensStatus variable is useless as your states are managing this for you (and you never reset sensStatus by the way)

It's Sparkfun sound detector:

I updated the code by new testSound () method and it's working same way. I tried to see what if I comment the return statement, then motor never starts. Seems some how it gets HIGH from sensor pin i.e. #2.

OK,