How to run two events independently

Hello Everyone! I am using ESP32 to read an analog input and to blink a LED.
My problem is that delay after reading analog input is interfering OFF duration of LED.
LED remains ON for the duration of delay added after ON command but it remains OFF for the duration of delay added after OFF command plus duration of delay added after analogread(). Please help to run LED ON/OFF independent of delay after analogread.

// Potentiometer is connected to GPIO 34 (Analog ADC1_CH6) 
const int potPin = 34;

// variable for storing the potentiometer value
int potValue = 0;

void setup() {
  Serial.begin(115200);
  delay(1000);
  // initialize digital pin GPIO18 as an output.
  pinMode(18, OUTPUT);
}

void loop() {
  // Reading potentiometer value
  potValue = analogRead(potPin);
  Serial.print("Analog value: ");
  Serial.println(potValue);
  delay(2000);
  
  digitalWrite(18, HIGH); // turn the LED on
  delay(500);             // wait for 500 milliseconds
  digitalWrite(18, LOW);  // turn the LED off
  delay(500);             // wait for 500 milliseconds
}

This is the result of "blocking code." The function delay() stops the mcu from processing any other commands until the delay time is finished. What you need is a timing mechanism. A great place to start is "blink without delay()" This will show you how to use timing to make an event happen. After that, find "doing multiple things"

Here is a simulation that I used to get up to speed on timing... small description is in the code.

1 Like

Take a look at ESP32 Dual Core with Arduino IDE | Random Nerd Tutorials

Or consider writing your own non blocking code. See Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

the measurement/printing should be done every two seconds.
the blinking will be done every half second.

As already mentioned, avoid delay().
Use Blink Without Delay | Arduino Documentation to see how to blink the LED.

Apply the same concept for the analogRead/Serial print.

If you get stuck - post your updated code, then we can help you.

Not sure if you are interested in coding the solution on your own or just in a solution for your specific task ...

If it's a solution feel free to look here

https://wokwi.com/projects/383811900704320513

Sketch
/*
  Forum: https://forum.arduino.cc/t/how-to-run-two-events-independently/1199135
  Wokwi: https://wokwi.com/projects/383811900704320513

*/

// Potentiometer is connected to GPIO 34 (Analog ADC1_CH6)
// The last time a measurement was performed will be stored in lastMeasurement
// variable for storing the potentiometer valueconstexpr byte potPin = 34;
constexpr byte potPin = 34;
unsigned long lastMeasurement = 0;
int potValue = 0;

// Led is connected to pin 18
// lastBlinkTime holds the controller time in ms since last reset when the led pin was changed
// state holds the state the led pin has been set to
constexpr byte ledPin = 18;
unsigned long lastBlinkTime = 0;
byte state = HIGH;


void setup() {
  Serial.begin(115200);
  delay(1000);
  // initialize digital ledPin as output.
  pinMode(ledPin, OUTPUT);
}

void loop() {
  blinkEvery(500);
  measureEvery(2000);
}



// The content after the if-condition is only performed 
// when "interval" ms are expired since the last measurement

void measureEvery(unsigned long interval) {
  if (millis() - lastMeasurement >= interval) {
    lastMeasurement = millis();
    // Reading potentiometer value
    potValue = analogRead(potPin);
    Serial.print("Analog value: ");
    Serial.println(potValue);
  }
}


// The content after the if-condition is only performed 
// when "interval" ms are expired since the last change of the 
// digital pin state

void blinkEvery(unsigned long interval) {
  if (millis() - lastBlinkTime >= interval) {
    lastBlinkTime = millis();
    state = !state;
    digitalWrite(ledPin, state);
  }
}

Good luck!

1 Like

1. How often (I mean how many times per sec) you wish to read the analog input?

2. What are the On-time (for how long the LED remains On) and Off-time (for how long the LED remains Off) of your blinking LED?

3. It is seen from your sketch of Post #1 that you are acquiring input signal at at every 1200 ms (200 + 500 + 500) interval. Your LED is turned On at every 1200 ms interval and remains On for 500 ms. The LED is turned Off at every 1200 ms interval and remains Off for 500 ms. This is a process of sequentila operation whose timing diagram is given below (Fig-1).


Figure-1:

4. You want to feel that the two tasks (ADC acquisition at 200 ms interval) and LED blinking at 1-sec interval should happen concurrently/simultaneously. The tming diagram would be something like Fig-2. (Note that the tasks are asynchronous though timing lines are aligned.)


Figure-2:

5. There is only one processor in your MCU which must execute tasks one-after-another in a sequential manner. How can it perform tasks simultaneously when it (the MCU) is a Serial Device? It can't; but, there is mechanism to do do it; where, the eyes are hyptonized to believe that the tasks are being executed concurrently (untrue parallelism.)

6. Many ways have been prescribed in the previous posts to blink the LEDs concurrently. I wish to do it using FreeRTOS Library that is supported by ESP32 and UNOR4.
.... pending

7. Example: Blinking three LEDs concurrently using FreeRTOS Library. This sketch can be modified for "two LEDs" or "two LED + one ADC channe (Fig-3)".

Schematic:
esp32-3led
Figure-1:

Timing Diagram:


Figure-2:

Sketch:

//function declarations
TaskHandle_t  Task10Handle;
TaskHandle_t  Task11Handle;

//GPIO definitions
#define LED   2
#define LED10 21
#define LED11 22

//task creation using FreeRTOS.h Librray functions
void setup()
{
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
  pinMode(LED10, OUTPUT);
  pinMode(LED11, OUTPUT);

  xTaskCreatePinnedToCore(Task10, "Task-10", 2048, NULL, 2, &Task10Handle, 1);
  xTaskCreatePinnedToCore(Task11, "Task-11", 2048, NULL, 3, &Task10Handle, 1);
}

//LED blinks at 2000 ms interval
void loop()
{
  digitalWrite(LED, HIGH);
  vTaskDelay(pdMS_TO_TICKS(2000)); // Delay the task for 100 milliseconds
  digitalWrite(LED, LOW);
  vTaskDelay(pdMS_TO_TICKS(2000)); 
}

//LED10 blins at 1000 ms interval
void Task10(void *pvParameters)
{
  while (true)
  {
    digitalWrite(LED10, HIGH);
    vTaskDelay(pdMS_TO_TICKS(1000)); // Delay the task for 1000 milliseconds
    digitalWrite(LED10, LOW);
    vTaskDelay(pdMS_TO_TICKS(1000)); 
  }
}

//LED11 blinks at 500 ms interval
void Task11(void *pvParameters)
{
  while (true)
  {
    digitalWrite(LED11, HIGH);
    vTaskDelay(pdMS_TO_TICKS(500)); // Delay the task for 500 milliseconds
    digitalWrite(LED11, LOW);
    vTaskDelay(pdMS_TO_TICKS(500)); 
  }
}

8. Upload sketch of Step-7 and observe that the three LEDs are blinking concurrentlt at their respective intervals.

9. Eexrcise: Blinking Two LEDs and one ADC channel acquisition concurrently.
esp32-2ledAdc
Figure-3:

look this over

// multiple things

const byte PotPin = 34;
const byte LedPin = 18;         // Capitalize Constants

unsigned long msec;

// -----------------------------------------------------------------------------
void taskPot ()
{
    static unsigned long msecLast;
    if (msec - msecLast >= 2000)  {
        msecLast = msec;

        Serial.print   ("Analog value: ");
        Serial.println (analogRead (PotPin));
    }
}

// -----------------------------------------------------------------------------
void taskLed ()
{
    static unsigned long msecLast;
    static int           state;
    if (msec - msecLast >= 500)  {
        msecLast = msec;

        if (HIGH == state)
            state = LOW;
        else
            state = HIGH;
        digitalWrite (LedPin, state);
    }
}

// -----------------------------------------------------------------------------
void loop ()
{
    msec = millis ();
    taskPot ();
    taskLed ();
}

// -----------------------------------------------------------------------------
void setup () {
    Serial.begin (115200);
    pinMode (LedPin, OUTPUT);
}
1 Like

Thanks for your help. "blink without delay" is working well. But its ON and OFF duration is same. What modification is required to obtain desired ON and OFF duration?

Thanks for reply. I think at #3, time duration should be 2000+500+500=3000 and not 200+500+500=1200. Is'nt it?

When the timing period comes to an end change the timing period to the next one required. Something like

if (period == 1000)
{
  period = 5000;
}
else
{
  period = 1000;
}

Did you draw this diagram yourself? What program did you use?

Look into the options here:

Hello @asharet - Have a look at the code in Post #2... there is a line that shows:

unsigned long interval[] = {300, 700, 900, 2100}; // event intervals

This line shows four durations: 300ms, 700ms, 900ms and 2100ms. You only need to change these values for the LEDs to blink at your durations.

Yes! I have drawn the diagram manually using the tools of Microsoft Visio Application.

Yes! It is 3000 ms (2000 + 500 + 500) interval (mentioned in your post #1 and not post #3). Just change 200 to 2000 in the timing diagram and codes of my post #6.

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