Arduino How to  control led without blocking delay  - Page 1
Forum section: electronics / general

author: King123
author_rank: Contributor
timestamp: August 27, 2022, 10:51:48 am
content: Hi everyone,I need help on a program, How to control led without blocking delay . How to get rid of the delay(4000)Code://Mega2560 board//LED pinint LED1 = 8;int LED2 = 9;int LED3 = 10;void setup() {Serial.begin(9600);pinMode(LED1, OUTPUT);pinMode(LED2, OUTPUT);pinMode(LED3, OUTPUT);digitalWrite(LED1, HIGH);digitalWrite(LED2, HIGH);digitalWrite(LED3, HIGH);}void loop() {// Check if there is anything in the Serial Bufferif (Serial.available()){// Read one value from the Serial buffer and store it in the variable com1int com1 = Serial.read();// Act according to the value receivedif (com1 == 'x'){// stop the leddigitalWrite(LED1, LOW);delay(4000);// Start the LEDdigitalWrite(LED1, HIGH);}}// Check if there is anything in the Serial Bufferif (Serial1.available()){// Read one value from the Serial buffer and store it in the variable com2int com2 = Serial1.read();// Act according to the value receivedif (com2 == 'y'){// stop the LED2digitalWrite(LED2, LOW);delay(4000);// Start the LED2digitalWrite(LED2, HIGH);}}// Check if there is anything in the Serial Bufferif (Serial2.available()){// Read one value from the Serial buffer and store it in the variable com3int com3 = Serial1.read();// Act according to the value receivedif (com3 == 'z'){// stop the LED3digitalWrite(LED3, LOW);delay(4000);// Start the LED3digitalWrite(LED2, HIGH);}}}following linkhttps://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay

author: Ed.Kloonk
author_rank: Super Contributor
timestamp: August 27, 2022, 10:58:04 am
content: Change toCode:delay(1);

author: ggchab
author_rank: Frequent Contributor
timestamp: August 27, 2022, 11:28:34 am
content: Use a timer and interruptions to restart the led

author: King123
author_rank: Contributor
timestamp: August 27, 2022, 12:19:40 pm
content: Quote from: Ed.Kloonk on August 27, 2022, 10:58:04 amThis is very short time while I want led to turn on/off at least for 4 seconds

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 27, 2022, 12:38:38 pm
content: Quote from: Ed.Kloonk on August 27, 2022, 10:58:04 amWrong. Change toCode:But we are being mean.To do something like this without blocking the rest of the code one would use a timer. This can be done in several ways, of which one is to control the led in the interrupt routine and make sure the interrupt is only triggered once every 4 seconds. Another one is to check on time past in the main loop (compare the timer value to a previous saved value and calculate the difference) and when it hits 4 second control the led.Search google for how to use the timer in Arduino projects.

author: mariush
author_rank: Super Contributor
timestamp: August 27, 2022, 12:53:42 pm
content: It would make more sense to have the timer programmed to interrupt every 100ms or every 10ms. Each time the interrupt is called, decrease a counter by 1 if the counter value is bigger than 0. When that counter is 0, launch the code that turns off the led.This way, if somewhere in the code you want to turn on the led while the led is still on, you could simply reset the counter value to whatever means 4 seconds or what you want.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 27, 2022, 01:45:16 pm
content: It depends. If it is just the led the original poster wants to toggle every 4 seconds then there is no need for a shorter timer interrupt. It of course depends on the timer if it is possible to set it to a 4 second timeout. The main clock frequency, timer pre-scaler and the width of the timer are factors in play here.

author: pqass
author_rank: Super Contributor
timestamp: August 27, 2022, 02:00:52 pm
content: Why overcomplicate a simple sketch with timers when the usual remedy is to just count clock ticks.Repeat the code marked in red for the other LEDs....unsigned long LED1CountDown = 0;void loop() {if (LED1CountDown > 0 && (millis() - LED1CountDown) > 4000) {LED1CountDown = 0;// Start the LEDdigitalWrite(LED1, HIGH);}// Check if there is anything in the Serial Bufferif (Serial.available()){// Read one value from the Serial buffer and store it in the variable com1int com1 = Serial.read();// Act according to the value receivedif (com1 == 'x'){// stop the leddigitalWrite(LED1, LOW);LED1CountDown = millis();}}...

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 27, 2022, 02:17:23 pm
content: Is millis() not a timer based thing?And you are making it to easy for the original poster. He is trying to learn programming. This only enlarges the copy and paste mentality instead of the think for yourself mentality.

author: pqass
author_rank: Super Contributor
timestamp: August 27, 2022, 02:36:12 pm
content: Quote from: pcprogrammer on August 27, 2022, 02:17:23 pm"perfection is the enemy of good ."--some smart french guyYes millis() is a timer under the covers. I'm sure OP will get to flex his raw timer chops when he gets to multiplexed displays. Don't snuff-out his nascent curiosity just yet with a wall of incomprehensible i/o register assignments.

author: Peabody
author_rank: Super Contributor
timestamp: August 27, 2022, 02:48:18 pm
content: I suggest you look at the built-in Arduino example called "BlinkWithoutDelay.ino". It's under Files/Examples/02Digital in the IDE. It uses the millis() function.Also, there is an Arduino forum.https://forum.arduino.cc/index.php

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 27, 2022, 02:50:35 pm
content: Take a look at my earlier postQuoteThis is just what you gave him on a platter.

author: Nominal Animal
author_rank: Super Contributor
timestamp: August 27, 2022, 03:20:35 pm
content: Quote from: King123 on August 27, 2022, 10:51:48 amRight now, you have the procedural/imperative mindset: "Turn the LED on. Wait for 4000ms. Turn the LED off. Wait for 4000ms. Repeat."What you want to do, is to switch to theasynchronousmindset: "Is is time to toggle the LED state?"Arduino library provides a functionmillis(), which returns anunsigned long, which increases by one every millisecond. To measure elapsed time in milliseconds, use anunsigned longvariable to record the value ofmillis()when the interval starts:unsigned long started = millis();Then, the time elapsed is simply(millis() - started). Becauseunsigned longuses modular arithmetic, this is correct even whenmillis()wraps around (as it does every 232milliseconds, or 49 days, 17 hours, 2 minutes, and 47.296 seconds).Since anunsigned longcan represent integers between 0 and 4294967295 in Arduino, modular arithmetic means that whenaandbareunsigned longs,(a - b)isa-bwhena >= b, buta+4294967296-bwhena < b.If we want to instead set a marker for a future time, we dounsigned long marker = millis() + 4000; /* 4 seconds in the future */and test if we have reached that time yet usingif ((unsigned long)(marker - millis() - 1uL)) >= 2147483648uL) {// At or after the marker} else {// Before the marker}which works, because the the difference jumps to four billion when millis() reaches marker, even if they wrapped around.Because all Arduino architectures use two's complement for signed integers, the if clause can be written asif ((long)(marker - millis()) <= 0) {where it does the exact same thing. This works, because with two's complement signed types, the upper half of the representable values (2147483648 to 4294967295, here) becomes negative (-2147483648 to -1, correspondingly). Because we can now test for "negative or zero", we don't need the -1 anymore, to achieve the exact same thing.Note, also, thatmarkercan be up to 24 days and some hours into the future, and it'll still work fine.I like this latter form, because it is logical; it does the same thing asif (marker < millis()), but without any problems when millis() wraps around! The direct comparison, of course, triggers immediately if the time wraps around between now/millis() and the future momentmarkerwas set to.A lot of programmers say "well, it won't ever happen in practice, because who runs my program for 50 days straight?", but that's stupid and evil. Don't be evil, do it right from the get go. We already have enough code that occasionally shits itself and goes bonkers, please don't add to that stinky pile.Consider the following Arduino sketch skeleton:Code:bool led_lit;unsigned long led_next_toggle;void setup() {led_lit = false;led_next_toggle = millis(); /* Now */}void loop() {unsigned long ms = millis();/* Is it time to toggle the led? */if ((long)(led_next_toggle - ms) < 0) {/* Yes. On or off? */if (led_lit) {// TODO: Turn LED offled_lit = false;led_next_toggle = ms + 1500uL; /* LED stays off for 1.5 seconds */} else {// TODO: Turn LED onled_lit = true;led_next_toggle = ms + 2500uL; /* LED stays on for 2.5 seconds */}}/* You can do other stuff here */}Anything else you do in loop() that does not take longer than a few milliseconds at most, will just cause jitter ("inexact timing") to the LED blinking.The way the above skeleton is written, each on and off delay set is theminimum. It can take longer than that by the amount of time that the other stuff you do in loop() happens to take.If we write the skeleton in a slightly different way,Code:bool led_lit;unsigned long led_next_toggle;void setup() {led_lit = false;led_next_toggle = millis(); /* Now */}void loop() {unsigned long ms = millis();/* Is it time to toggle the led? */if ((long)(led_next_toggle - ms) < 0) {/* Yes. On or off? */if (led_lit) {// TODO: Turn LED offled_lit = false;led_next_toggle += 1500uL; /* Turn LED on 1.5 seconds after the moment it ought to have been turned off */} else {// TODO: Turn LED onled_lit = true;led_next_toggle += 2500uL; /* Turn LED off 2.5 seconds after the moment it ought to have been turned on */}}/* You can do other stuff here */}we advance the marker itself by a fixed time, so that jitter (delay due to other stuff you do in loop()) is not cumulative. Essentially, our sequence of time markers has a fixed period, and jitter only affects the moment when we notice we need to do something. However, if you have say a twelve-second delay, theled_next_togglewill fall behind by that amount, and in the next six or seven loop() iterations, the LED will be toggled!So, this way you always have the exact number of toggles, but there is really no lower limit how long each state can take, if you dilly-dally in your other stuff in loop().When you understand how to construct this kind of asynchronous timer based events yourself, and understand the difference between the two timer marker approaches above, and how this differs from the imperative/procedural thinking shown in most examples, you already understand more than the vast majority of Arduino programmers. With these building blocks, you can start making some really interesting stuff. Consider, for example, how would you do three LEDs that blink completely independently? Yes, it is that simple, no magic involved.. and hopefully you also realize you can use the same for all kinds of different stuff other than blinking LEDs, andthatis what opens up the vast universe of possibilities!

author: eugene
author_rank: Frequent Contributor
timestamp: August 27, 2022, 03:27:12 pm
content: Quote from: Peabody on August 27, 2022, 02:48:18 pmThis ^. You can find a good example of how to do it (and a lot of other things) without leaving the comfort of the Arduino IDE.

author: pcprogrammer
author_rank: Super Contributor
timestamp: August 27, 2022, 03:33:56 pm
content: @Nominal Animal, you see you are better with words. Nice lesson for King123.

author: pqass
author_rank: Super Contributor
timestamp: August 27, 2022, 03:35:19 pm
content: Quote from: pcprogrammer on August 27, 2022, 02:50:35 pmYes you did. How about that! My bad for not reading every reply. However, I can't guarantee it won't happen again.As for my post, I like to give [and see] concrete examples. If he cares, he'll study why it works.