Hey everyone! So, I´m a total begginer in Arduino, and I have to program something for college. I discovered millis() while trying to print something in 1 second intervals while doing a bunch of other stuff with delay, but I still can't quite get the hang of it.
I already know how to make an LED blink without delay, but it's when the blink intervals change that I get completely lost.
I have to turn on the LED for 1s, then turn if off for another second, turn it on 0.5s and off 0.5s. I know it's a really basic question but I really need help, I can't get it to change intervals, it just stays on or blinks every 1s. I would really appreciate any help, it doesn't need to be a whole code, just tell me how to change the interval after the first blink, or something like that. Thanks a lot!
The basic form of the millis timing statement reads like this:
if (the_current_time - the_last_time > some-interval)
So if the interval is changing, then make the some-interval part a variable whose value you can change when needed.
All you're doing is calculating how long it has been since you took some action. It's just like with a clock. If it is 2:20 now and at 2:05 you saw a clown ride by, how long has it been since you saw the clown. You just subtract right? Same here, only in milliseconds.
Then once you have how long it's been since some event, you're comparing with an interval to see if it has been longer than some given time.
I hadn't thought of changing the variable (thanks for the tip), and I gave it a try applying the same logic as the "blink without delay" code, but my LED just stays off. Here's my code:
long intervaluno=1000;
long tiempoinicial1=0;
int pin=12;
int ledState=LOW;
void setup()
{
pinMode(pin, OUTPUT);
}
void loop()
{
if (millis()-tiempoinicial1>=intervaluno)
{
tiempoinicial1=millis();
if (ledState==LOW && intervaluno==1000)
{ledState=HIGH;}
if (ledState==HIGH && intervaluno==1000)
{ledState=LOW;
intervaluno=500;}
if (ledState==LOW && intervaluno==500)
{ledState=HIGH;}
if (ledState==HIGH && intervaluno==500)
{ledState=LOW;}
}
digitalWrite(pin, ledState);
}
BTW, i speak spanish so the variables are in spanish, tiempoinicial1 being the "currentMillis" and intervaluno being the time interval.
I don't know what else to do to make it work :(, please, help!
if (ledState == LOW && intervaluno == 1000)
{
ledState = HIGH;
}
if (ledState == HIGH && intervaluno == 1000)
{
ledState = LOW;
intervaluno = 500;
}
The second if should be an else
You have two intervals starting with 1000 and then changing to 500. If you test both conditions and the 1000 tests true, the 500 will test true as well. This is why there are tests where only one condition can be true, and the first one wins. Examine the 1000 case first, if intervaluno is 500 it will never happen so it can only happen the first time.
void loop()
{
elapsedMillis = (millis() - currentMillis);
if (interval == 1000)
{
if (elapsedMillis >= interval) // only do this if the elapsed has exceeded interval
{
currentMillis = millis(); // reset the timer counter
if (ledState == LOW)
{
ledState = HIGH;
}
else
{
ledState = LOW;
interval = 500;
}
}
}
else // if interval is not 1000 then it must be 500
{
// All you need to do here now is check the time
if (elapsedMillis >= interval)
{
currentMillis = millis();
if (ledState == LOW)
{
ledState = HIGH
};
else
{
ledState = LOW;
}
}
}
}
The demo Several Things at a Time illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.
Have a look at Using millis() for timing. A beginners guide if you need more explanation.
If you have delay()s in a program as well as timing using millis() you may find that the millis() timing does not appear to work because the delay() has used up all the time before the code next gets around to testing the millis() value.
...R
First of all, thanks for replying!
Second, I wrote the code again so it was like yours, but the LED just keeps blinking every 1s, I don't know if I interpreted it wrong or I wrote something the wrong way, but it's like it never changes to 500, even though it should.
Code:
long intervaluno=1000;
long tiempoinicial1=0;
int pin=12;
int ledState=LOW;
void setup()
{
pinMode(pin, OUTPUT);
}
void loop()
{
unsigned long ellapsedmillis=millis()-tiempoinicial1;
if (intervaluno=1000)
{if (ellapsedmillis >= intervaluno)
{tiempoinicial1=millis();
if (ledState==LOW)
{ledState=HIGH;}
else
{ledState=LOW;
intervaluno=500;}
}
}
else
{if (ellapsedmillis >= intervaluno)
{tiempoinicial1=millis();
if (ledState==LOW)
{ledState=HIGH;}
else
{ledState=LOW;
intervaluno=1000;}
}
}
digitalWrite(pin, ledState);
}
if (intervaluno=1000)
BONG !
Can't belive I missed that lol, it works now!
Thanks to everyone who replied!!
A data driven approach to the problem
const byte ledPin = LED_BUILTIN;
unsigned long previousMillis = 0;
const byte states[] = {HIGH, LOW};
const unsigned long intervals[] = {1000, 1000, 500, 500};
const byte NO_OF_INTERVALS = sizeof(intervals) / sizeof(intervals[0]);
byte state;
void setup()
{
pinMode(ledPin, OUTPUT);
}
void loop()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= intervals[state % NO_OF_INTERVALS])
{
previousMillis = currentMillis;
digitalWrite(ledPin, states[state++ % 2]);
}
}
Thanks for your reply! I've been looking at the code you sent and I still can't wrap my head around these lines
const byte NO_OF_INTERVALS = sizeof(intervals) / sizeof(intervals[0]);
byte state;
if (currentMillis - previousMillis >= intervals[state % NO_OF_INTERVALS]
I can't understand how the state variable works, as it's not assigned any value (or I can't see it), and how it relates to NO_OF_INTERVALS
const byte NO_OF_INTERVALS = sizeof(intervals) / sizeof(intervals[0]);
byte state;
This calculates the number of entries in the array by dividing the total number of bytes used by the array by the size of its first element. Doing it that way and using the calculated value later in the code if you want to add or remove entries from the array then you don't have to change any other variables or constants.
The state variable will have an initial value of zero because it is declared at global scope.
intervals[state % NO_OF_INTERVALS]
Uses the modulus operator (%) to determine the current level of the array to look at for the current interval. The modulus is the remainder of the division of 2 integers, in this case the current state and the number of intervals. Using the % operator removes the need to check whether the state variable has reached its upper limit and therefore needs to be reset to zero.
digitalWrite(ledPin, states[state++ % 2]);
state is incremented each time the state of an LED is changed. Once again the % operator is used to determine which level of the states array should be accessed. Using a value of 2 gives a result of either 0 or 1, hence HIGH or LOW from the array.
Work your way through the program on paper, writing down the value of state at each step where it involved and you should see what is going on.
I will check it out, thanks a lot! It seems a lot more compact and convenient!