Need Help in Multitasking

I tried this code using Millis() but it wont work. I need to run a pump for 60 seconds and stop when I give input from serial monitor and also to 'Switch On' an solenoid valve for 30 seconds and stop both with the same serial input.

int pulse = 9;
int step = 10;
int direct = 11;

int inc;

int sol = 13;

unsigned long start_sol = 0;
unsigned long interval_sol = 30000;
unsigned long start_pum = 0;
unsigned long interval_pum = 60000;


void setup() {
 Serial.begin(9600);
 pinMode(pulse, OUTPUT);
 pinMode(step, OUTPUT);
 pinMode(direct, OUTPUT);
 pinMode(sol, OUTPUT);

 digitalWrite(sol,LOW);
}

void pump(){
  unsigned currentTime = millis();
  Serial.println(currentTime);
  if(currentTime - start_pum >= interval_pum){
    start_pum = currentTime;
    digitalWrite(step,HIGH);
    digitalWrite(direct,HIGH);
    analogWrite(pulse,255);
  }
  else{
    digitalWrite(step,LOW);
    digitalWrite(direct,HIGH);
    analogWrite(pulse,0);
  }
}

void solenoid(){
  unsigned currentTime1 = millis();
  Serial.println(currentTime1);
  if(currentTime1 - start_sol >= interval_sol){
    start_sol = currentTime1;
    digitalWrite(sol,HIGH);
   }
   else{
    digitalWrite(sol,LOW);
   }
  
}

void loop() {
 if (Serial.available()>0){
   inc = Serial.read();
  Serial.println(inc);

  switch(inc){
    case 'a':
        pump();
        solenoid();
        break;
    case 'b':
        digitalWrite(sol,LOW);
        break;
  }
 }
}

How does the program behaviour differ from what you expect?

void solenoid(){
  unsigned currentTime1 = millis();

did you mean

void solenoid(){
  unsigned long currentTime1 = millis();
1 Like

doubt this is doing what you expect. it's certainly not multi-tasking

it exercises your sub-functions: pump() and solenoid() based on a command line input. but both of these have a time component.

without being repeatedly invoked, that time component when get exercised.

perhaps what you want to do is call both pump() and solenoid(), without the else parts and possibly more, during each iteration of loop to reset them and have the command line activate them

what do you want to do?

I think you when you're calling the millis() timer in each function, you're just comparing the time to itself and not any reference time because you're doing it all in house, that is within each function so it loops through really fast and essentially keeps canceling itself out. So it enters your function, updates the stopwatch to whatever millis() is at right now, says "nope, the if statement doesn't match" so it bails from the function back to loop(). Then it rinses and repeats, updating the stopwatch everytime it enters your solenoid or pump functions so the condition can never be met.
I didn't try running it or anything but does that seem to jibe with the behavior you're seeing?

Also ^. I've never seen it written as just unsigned without a type of unsigned something. Maybe it thinks you mean int? Maybe long? Who knows?

consider

#undef MyHW
#ifdef MyHW
int pulse  = 10;
int step   = 11;
int direct = 12;
int sol    = 13;
unsigned long intervalSol  = 3000;
unsigned long intervalPump = 6000;

#else
int pulse  = 9;
int step   = 10;
int direct = 11;
int sol    = 13;
unsigned long intervalSol  = 30000;
unsigned long intervalPump = 60000;
#endif


char inc;

enum { Off = HIGH, On = LOW };

unsigned long msecSol;
unsigned long msecPump;
unsigned long msec;

// -----------------------------------------------------------------------------
void pump ()
{
    if (On == digitalRead (direct) && (msec - msecPump) >= intervalPump)  {
        digitalWrite (step,   Off);
        digitalWrite (direct, Off);
        analogWrite  (pulse,  255);
    }
}

void solenoid ()
{
    if (On == digitalRead (sol) && (msec - msecSol) >= intervalSol)  {
        digitalWrite (sol, Off);
    }
}

// -----------------------------------------------------------------------------
void loop () {
    msec = millis ();

    pump ();
    solenoid ();

    if (Serial.available ())  {
        inc = Serial.read ();
        Serial.println (inc);

        switch (inc){
        case 'p':
            digitalWrite (direct, On);
            analogWrite  (pulse,  0);
            msecPump = msec;
            break;

        case 's':
            digitalWrite (sol, On);
            msecSol = msec;
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void setup () {
    Serial.begin (9600);

    digitalWrite (pulse,  Off);
    digitalWrite (step,   Off);
    digitalWrite (direct, Off);
    digitalWrite (sol,    Off);

    pinMode (pulse,  OUTPUT);
    pinMode (step,   OUTPUT);
    pinMode (direct, OUTPUT);
    pinMode (sol,    OUTPUT);
}
1 Like

Everyone. Or they should.

unsigned really is a shorthand for unsigned int , and so defined in standard C.

And presumably C++.

a7

See? So if you're using an Uno, that will be very different than an int on a PC in other languages. Best to explicitly declare what you explicitly want, IMO. If you're on here asking for help at this level (which is great, there shouldn't be any barriers to learners) it's probably best to avoid shortcuts like the one in question.

Totally good point! By that good advice, ppl should use the

uint16_t foo;

declaration and the others if that's what they want.

a7

Thank you very much this code works perfectly as to execute two or more lines of code.

#undef MyHW
#ifdef MyHW
int pulse  = 10;
int step   = 11;
int direct = 12;
int sol    = 13;
unsigned long intervalSol  = 3000;
unsigned long intervalPump = 6000;

#else
int pulse  = 9;
int step   = 10;
int direct = 11;
int sol    = 13;
unsigned long intervalSol  = 30000;
unsigned long intervalPump = 60000;
#endif


char inc;

enum { Off = HIGH, On = LOW };

unsigned long msecSol;
unsigned long msecPump;
unsigned long msec;

// -----------------------------------------------------------------------------
void pump ()
{
    if (On == digitalRead (direct) && (msec - msecPump) >= intervalPump)  {
        digitalWrite (step,   Off);
        digitalWrite (direct, Off);
        analogWrite  (pulse,  255);
    }
}

void solenoid ()
{
    if (On == digitalRead (sol) && (msec - msecSol) >= intervalSol)  {
        digitalWrite (sol, Off);
    }
}

// -----------------------------------------------------------------------------
void loop () {
    msec = millis ();

    pump ();
    solenoid ();

    if (Serial.available ())  {
        inc = Serial.read ();
        Serial.println (inc);

        switch (inc){
        case 'p':
            digitalWrite (direct, On);
            analogWrite  (pulse,  0);
            msecPump = msec;
            break;

        case 's':
            digitalWrite (sol, On);
            msecSol = msec;
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void setup () {
    Serial.begin (9600);

    digitalWrite (pulse,  Off);
    digitalWrite (step,   Off);
    digitalWrite (direct, Off);
    digitalWrite (sol,    Off);

    pinMode (pulse,  OUTPUT);
    pinMode (step,   OUTPUT);
    pinMode (direct, OUTPUT);
    pinMode (sol,    OUTPUT);
}

But my Aim is to--
--> When I start my Arduino Mega at default state the pump and the solenoid should be at off state (LOW).
--> When I provide a Input from serial monitor example: 'p' pump should start only for 60 seconds (intervalpump) and again get back to off state (LOW).

I tried altering this code but it works in reverse. The pump and solenoid are always at 'on' state, when ever I provide with 'p' or 's' input it stops for the given interval and starts again.

can you please look into this...

saying some output is LOW/HIGH doesn't make it clear whether it is Off/On,.

just change the enum for your system

I have changed the 'enum'. The code works fine for solenoid but doesn't work for peristaltic pump.

My peristaltic pump was not starting so I changed the pump function code to

void pump ()
{
    if (On == digitalRead (direct) && (msec - msecPump) >= intervalPump)  {
        digitalWrite (step,   On);
        digitalWrite (direct, On);
        analogWrite  (pulse,  255);
    }
}

now after giving input the peristaltic pump starts after 6 seconds(intervalpump) but it won't go back to off state. Is it the problem with my peristaltic pump ?

I am using T100S302WX10-14H pump (manual attached below)

peristaltic pump

you're controlling the pump, "pulse", with an analog output. looks like 255 turns it on and 0 turns it off. so should the 'p' command be

I tried changing the pulse but it won't work. :smiling_face_with_tear:
here is the full code which works perfectly with solenoid but not with peristaltic pump.
please let me know is there any leads on this. Also I have attached the peristaltic pump manual above.

#undef MyHW
#ifdef MyHW
int pulse  = 9;
int step   = 10;
int direct = 11;
int sol    = 13;
unsigned long intervalSol  = 3000;
unsigned long intervalPump = 6000;

#else
int pulse  = 9;
int step   = 10;
int direct = 11;
int sol    = 13;
unsigned long intervalSol  = 3000;
unsigned long intervalPump = 6000;
#endif


char inc;

enum { Off = LOW, On = HIGH };

unsigned long msecSol;
unsigned long msecPump;
unsigned long msec;

// -----------------------------------------------------------------------------
void setup () {
    Serial.begin (9600);

    digitalWrite (pulse,  Off);
    digitalWrite (step,   Off);
    digitalWrite (direct, Off);
    digitalWrite (sol,    Off);

    pinMode (pulse,  OUTPUT);
    pinMode (step,   OUTPUT);
    pinMode (direct, OUTPUT);
    pinMode (sol,    OUTPUT);
}

// -----------------------------------------------------------------------------
void pump ()
{
    if (On == digitalRead (direct) && (msec - msecPump) >= intervalPump)  {
        digitalWrite (step,   Off);
        digitalWrite (direct, Off);
        analogWrite  (pulse,  255);
    }
}

void solenoid ()
{
    if (On == digitalRead (sol) && (msec - msecSol) >= intervalSol)  {
        digitalWrite (sol, Off);
    }
}

// -----------------------------------------------------------------------------
void loop () {
    msec = millis ();

    pump ();
    solenoid ();

    if (Serial.available ())  {
        inc = Serial.read ();
        Serial.println (inc);

        switch (inc){
        case 'p':
            digitalWrite (direct, On);
            analogWrite  (pulse,  255);
            msecPump = msec;
            break;

        case 's':
            digitalWrite (sol, On);
            msecSol = msec;
            break;
        }
    }
}

shouldn't pulse be set to 0 to turn it off?
does setting it to 255 turn it on?

setting it to 0 turns it off and setting it to 255 turns it on.
Tried changing that too but no results.

void pump ()
{
    if (On == digitalRead (direct) && (msec - msecPump) >= intervalPump)  {
        digitalWrite (step,   Off);
        digitalWrite (direct, Off);
        analogWrite  (pulse,  0);
    }
}

so setting it to 0 or 255 doesn't turn it off and on
don't know how i can help

okay, can you look in to this code now, solenoid works fine with the code but peristaltic pump don't.

#undef MyHW
#ifdef MyHW
int pulse  = 9;
int step   = 10;
int direct = 11;
int sol    = 13;
unsigned long intervalSol  = 3000;
unsigned long intervalPump = 6000;

#else
int pulse  = 9;
int step   = 10;
int direct = 11;
int sol    = 13;
unsigned long intervalSol  = 3000;
unsigned long intervalPump = 6000;
#endif


char inc;

enum { Off = LOW, On = HIGH };

unsigned long msecSol;
unsigned long msecPump;
unsigned long msec;

// -----------------------------------------------------------------------------
void setup () {
    Serial.begin (9600);

    analogWrite (pulse,  0);
    digitalWrite (step,   Off);
    digitalWrite (direct, On);
    digitalWrite (sol,    Off);

    pinMode (pulse,  OUTPUT);
    pinMode (step,   OUTPUT);
    pinMode (direct, OUTPUT);
    pinMode (sol,    OUTPUT);
}

// -----------------------------------------------------------------------------
void pump ()
{
    if (On == digitalRead (direct) && (msec - msecPump) >= intervalPump)  {
        digitalWrite (step,   Off);
        digitalWrite (direct, Off);
        analogWrite  (pulse,  0);
    }
}

void solenoid ()
{
    if (On == digitalRead (sol) && (msec - msecSol) >= intervalSol)  {
        digitalWrite (sol, Off);
    }
}

// -----------------------------------------------------------------------------
void loop () {
    msec = millis ();

    pump ();
    solenoid ();

    if (Serial.available ())  {
        inc = Serial.read ();
        Serial.println (inc);

        switch (inc){
        case 'p':
            digitalWrite (direct, On);
            analogWrite  (pulse,  255);
            msecPump = msec;
            break;

        case 's':
            digitalWrite (sol, On);
            msecSol = msec;
            break;
        }
    }
}

i would expect it to work if using analogWrite() to set it to 255 turns it on and to 0 turns it off.

doesn't this configure the pin as a digital output. aren't you using it as an analog pin?

yes, I have changed in Setup too but no change.

void setup () {
    Serial.begin (9600);

    analogWrite (pulse,  0);
    digitalWrite (step,   Off);
    digitalWrite (direct, Off);
    digitalWrite (sol,    Off);

    pinMode (pulse,  OUTPUT);
    pinMode (step,   OUTPUT);
    pinMode (direct, OUTPUT);
    pinMode (sol,    OUTPUT);
}