Multitasking program with motor and relay

Hello, I am currently carrying out an internship assignment where I have to automate a door for a solar-powered chicken coop.

I am currently using an Arduino UNO board, a 2 channel relay module and a 3.7V lipo battery.

The door is opened and closed using a motor that turns in either direction and rolls or unwinds a wire that opens or closes the door.

There I have to do a program loop where:

  • When starting, relay 1 is energized for 10 seconds, where the motor gradually closes the door.
    -10 seconds later, the 2 relays are deactivated and the motor is paused for 5 seconds.
    -Then, relay 2 is energized for 10 seconds, which turns the motor in the other direction and gradually opens the door.
    -10 seconds later, another engine pause for 5 seconds.

And so on.

Now I want to do a parallel action where I have to measure the voltage with an analog pin to check the motor consumption. The goal is to take a measurement every 250 milliseconds.

Here is the program I performed:

int RelayPin1 = 6;
int RelayPin2 = 7;
int valeur = analogRead(A0); // Mesure la tension sur la broche 

void setup() {
  // On met les pin de chaque relais en sortie
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);

    // Initialise la communication avec le PC
  Serial.begin(9600);
}

void loop() {
    // Sous traite les différentes tâches
    task_moteur1();
    task_moteur2();
  }

void task_moteur1() {
    // Transforme la mesure (nombre entier) en tension via un produit en croix
    float tension = valeur * (5.0 / 1023.0);
    
    // Envoi la mesure au PC pour affichage
    Serial.println(tension);
    delay(250);   

  }

void task_moteur2() {
  
    // On allume l'un des relais alors que l'autre est éteint...
    digitalWrite(RelayPin1, LOW);
    digitalWrite(RelayPin2, HIGH);
    delay(10000);

    // On éteint ensuite le ler relais: le moteur est en pause pendant 5 secondes...
    digitalWrite(RelayPin1, HIGH);
    digitalWrite(RelayPin2, HIGH);
    delay(5000);
  
    // Puis on allume l'autre...
    digitalWrite(RelayPin1, HIGH);
    digitalWrite(RelayPin2, LOW);
    delay(10000);

    // Enfin, on éteins le 2ème relais: le moteur est encore en pause pendant 5 secondes...
    digitalWrite(RelayPin1, HIGH);
    digitalWrite(RelayPin2, HIGH);
    delay(5000);
}

The problem is that when I test my program, the voltage is only measured whenever relay 1 is activated. Either every 30 seconds.

I would then like to create a non-blocking program, and I have heard of the millis () function. The problem is, I don’t know anything about this function.

Could someone help me ?!

Thank you in advance.

Hello,
avoid using the delay() function. This function blocks further execution of the sketch for the given time.
My standard recipe:
Take a bag of timers and a small finite state machine and stir everything together until the desired functionality. :smiley:

1 Like

and Overview | Multi-tasking the Arduino - Part 1 | Adafruit Learning System

Have a look at two of my tutorials,
How to write Timers and Delays in Arduino
and
Multi-tasking in Arduino

You will need to move to the multi-tasking form of coding and then test in the tasks if the timer has finished and set ‘flags’ to control what should happen

Compiles, not tested.

/*
 * Sketch...:   sketch_apr16b.ino
 * Target...:   ?
 * 
 * Notes....:
 */

//includes

//defines

//constants
const uint8_t RelayPin1 = 6;
const uint8_t RelayPin2 = 7;

//variables


void setup() 
{
    // On met les pin de chaque relais en sortie
    pinMode(RelayPin1, OUTPUT);
    pinMode(RelayPin2, OUTPUT);
    
    // Initialise la communication avec le PC
    Serial.begin(9600);
}

void loop() 
{
    // Sous traite les différentes tâches
    task_moteur1();
    task_moteur2();
    
}//loop

void task_moteur1() 
{
    static uint32_t
        timePrint;

    uint32_t timeNow = millis();

    if( (timeNow - timePrint) >= 250ul )
    {
        timePrint = timeNow;

        // Transforme la mesure (nombre entier) en tension via un produit en croix
        int valeur = analogRead(A0); // Mesure la tension sur la broche 
        float tension = (float)valeur * (5.0 / 1023.0);    
        
        // Envoi la mesure au PC pour affichage
        Serial.println(tension);
        //delay(250);   
        
    }//if    

}//task_moteur1

void task_moteur2() 
{  
    static uint8_t
        state = 0;
    static uint32_t
        timeRelays;

    uint32_t timeNow = millis();

    switch( state )
    {
        case    0:
            // On allume l'un des relais alors que l'autre est éteint...
            digitalWrite(RelayPin1, LOW);
            digitalWrite(RelayPin2, HIGH);
            //delay(10000);
            timeRelays = timeNow;
            state++;
        
        break;    

        case    1:
            if( (timeNow - timeRelays) >= 10000ul )
            {
                // On éteint ensuite le ler relais: le moteur est en pause pendant 5 secondes...
                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, HIGH);
                //delay(5000);
                timeRelays = timeNow;
                state++;
                
            }//if
            
        break;

        case    2:
            if( (timeNow - timeRelays) >= 5000ul )
            {
                // Puis on allume l'autre...
                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, LOW);
                //delay(10000);
                timeRelays = timeNow;
                state++;
                
            }//if
            
        break;

        case    3:
            if( (timeNow - timeRelays) >= 10000ul )
            {
                // Enfin, on éteins le 2ème relais: le moteur est encore en pause pendant 5 secondes...
                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, HIGH);
                //delay(5000);
                timeRelays = timeNow;
                state++;
                
            }//if
        
        break;

        case    4:
            if( (timeNow - timeRelays) >= 5000ul )
            {
                //after 5 seconds go back to state zero
                state = 0;
                
            }//if        
            
        break;                
        
    }//switch
    
}//task_moteur2

as an allday example with easy to follow numbers
delay() is blocking. As long as the delay is "delaying" nothing else of the code can be executed.
Now there is a technique of non-blocking timing.
The basic principle of non-blocking timing is fundamental different from using delay()
You have to understand the difference first and then look into the code.
otherwise you might try to "see" a "delay-analog-thing" in the millis()-code which it really isn't
Trying to see a "delay-analog-thing" in millis() makes it hard to understand millis()
Having understood the basic principle of non-blocking timing based on millis() makes it easy to understand.

imagine baking a frosted pizza
the cover says for preparation heat up oven to 200°C
then put pizza in.
Baking time 10 minutes

You are estimating heating up needs 3 minutes
You take a look onto your watch it is 13:02 (snapshot of time)
You start reading the newspaper and from time to time looking onto your watch
watch 13:02 not yet time
watch 13:03 not yet time
watch 13:04 not yet time 13:04 - 13:02 = 2 minutes is less than 3 minutes
watch 13:05 when did I start 13:02? OK 13:05 - 13:02 = 3 minutes time to put pizza into the oven

New basetime 13:05 (the snapshot of time)
watch 13:06 not yet time
watch 13:07 not yet time
watch 13:08 not yet time (13:08 - 13:05 = 3 minutes is less than 10 minutes
watch 13:09 not yet time
watch 13:10 not yet time
watch 13:11 not yet time
watch 13:12 not yet time
watch 13:13 not yet time
watch 13:14 not yet time (13:14 - 13:05 = 9 minutes is less than 10 minutes
watch 13:15 when did I start 13:05 OK 13:15 - 13:05 = 10 minutes time to eat pizza (yum yum)

You did a repeated comparing how much time has passed by
This is what non-blocking timing does

In the code looking at "How much time has passed by" is done

currentTime - startTime >= bakingTime

bakingTime is 10 minutes

13:06 - 13:05 = 1 minute >= bakingTime is false
13:07 - 13:05 = 2 minutes >= bakingTime is false
...
13:14 - 13:05 = 9 minutes >= bakingTime is false
13:15 - 13:05 = 10 minutes >= bakingTime is TRUE time for timed action!!

if (currentTime - previousTime >= period) {

it has to be coded exactly this way because in this way it manages the rollover from Max back to zero
of the function millis() automatically

baldengineer.com has a very good tutorial about timing with function millis() too .

There is one paragraph that nails down the difference between function delay() and millis() down to the point:

The millis() function is one of the most powerful functions of the Arduino library. This function returns the number of milliseconds the current sketch has been running since the last reset. At first, you might be thinking, well that’s not every useful! But consider how you tell time during the day. Effectively, you look at how many minutes have elapsed since midnight. That’s the idea behind millis()!

Instead of “waiting a certain amount of time” like you do with delay(), you can use millis() to ask “how much time has passed”?

I tested it and the program works !

Thank you a lot ! It will be very useful for my internship work !

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.