Hi all,
I am new here and read through the basic tutorials. I have however a project which I hoped was easy, but turns out to be more difficult that I expected and I am hoping someone can help me point into the right direction of figuring this out.
I have this project of a firetruck which has 2 random blinking lights on top. Something I found out to be usefull was the
const unsigned long led12interval = 400UL ;
const unsigned long led11interval = 450UL ;
The other thing I am trying to do is have a blinker in the front that flashes up 3 times and than delays about 1 second.
digitalWrite(led3, HIGH);
delay(50);
digitalWrite(led3, LOW);
delay(50);
digitalWrite(led3, HIGH);
delay(50);
digitalWrite(led3, LOW);
delay(50);
digitalWrite(led3, HIGH);
delay(50);
digitalWrite(led3, LOW);
delay(1000);
I basically took these examples of what I found on the forum, but I can't get them combined. The random flashlights need to keep on going as the blinker should only flash 3 times and wait.. I somehow get the delay to impact my flashlights as well.
The led3 code is the problem.
delay() does not work very well if you want to do more than one thing at a time.
use blink without delay for led3.
The "BLINK" program that is usually a beginners first sketch is written linearly:
Turn on LED;
Wait 1 second;
Turn off LED;
Wait 1 second;
Loop around and do it again.
Notice that it takes 2 whole seconds for loop to go around once. and if you try to do anything else things will get messed up.
This is not a good programming technique because during the time it is waiting(delay) the arduino could be doing literally millions of other things.
It's better to take a reactionary approach like in the " Blink without delay" sketch:
Loop;
Is it time yet (no);
Do other stuff;
Loop;
Is it time yet (no);
Do other stuff;
Loop;
Is it time yet (yes);
switch the LED;
Do other stuff;
With this sketch loop will go around THOUSANDS of times per second. Lots of time to do other stuff
It is allowed to change the interval runtime for random blinking:
const int ledPin = LED_BUILTIN;
unsigned long previousMillis;
unsigned long interval = 200UL; // not a constant, it will be changed
void setup()
{
pinMode( ledPin, OUTPUT);
}
void loop()
{
unsigned long currentMillis = millis();
if( currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
interval = random( 100, 500); // set the new interval
// toggle
digitalWrite( ledPin, digitalRead( ledPin) == HIGH ? LOW : HIGH);
}
}
There are many ways to blink three times and then wait some time using millis(). The most silly one is to have a counter and do certain things at specific counter values:
const int ledPin = LED_BUILTIN;
unsigned long previousMillis;
const unsigned long interval = 50;
int counter = 0;
void setup()
{
pinMode( ledPin, OUTPUT);
}
void loop()
{
unsigned long currentMillis = millis();
if( currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
// Select what to do with certain values of counter.
switch( counter)
{
case 0:
case 2:
case 4:
digitalWrite( ledPin, HIGH);
break;
case 1:
case 3:
case 5:
digitalWrite( ledPin, LOW);
break;
}
counter++;
if( counter >= 25)
{
counter = 0;
}
}
}
Thanks for your help! I finally managed to get to a setup I like
I now have:
2 leds which blink at a different pace
1 led which blinks randomly
1 led which flashes 3 times and waits for a bit and flashes 3 times again
/* Multiple independent delay - 3 different blinking patterns
Written by several forum members. In public domain. Oct 2011.
*/
// Which pins are connected to which LED
const byte led12 = 13;
const byte led11 = 12 ;
const int led3 = 4 ;
const byte led9 = 10 ;
// Time periods of blinks in milliseconds (1000 milliseconds to a second).
// Time variable and constants are always unsigned long
const unsigned long led12interval = 300UL ;
const unsigned long led11interval = 350UL ;
unsigned long previousMillis;
unsigned long previousMillisrandom;
unsigned long intervalblinkrandom = 200UL; // not a constant, it will be changed
unsigned long currentMillis = millis();
unsigned long currentMillisblinkrandom = millis();
unsigned long currentMillisblink = millis();
// Variable holding the timer value so far. One for each "Timer"
unsigned long led12timer = 0 ;
unsigned long led11timer = 0 ;
unsigned long led3timer = 0 ;
unsigned long led9timer = 0 ;
unsigned long waitUntil = 0;
// Variable to know what the current LED state is
int led12State = LOW ;
int led11State = LOW ;
int led3State = LOW ;
int led9State = LOW ;
const unsigned long intervalblink = 50;
int counter = 0;
void setup() {
pinMode (led12, OUTPUT) ;
pinMode (led11, OUTPUT) ;
pinMode (led3, OUTPUT) ;
pinMode (led9, OUTPUT) ;
led12timer = millis () ;
led11timer = millis () ;
led3timer = millis () ;
waitUntil += intervalblinkrandom;
}
void loop()
{
// Handling the blink of one LED.
// First, check if it is time to change state
if ( (millis () - led12timer) >= led12interval ) {
// It is time to change state. Calculate next state.
if (led12State == LOW)
led12State = HIGH ;
else
led12State = LOW ;
// Write new state
digitalWrite (led12, led12State ) ;
// Reset timer
led12timer = millis () ;
}
// The other LED is controlled the same way. Repeat for more LEDs
if ( (millis () - led11timer) >= led11interval ) {
if (led11State == LOW)
led11State = HIGH ;
else
led11State = LOW ;
digitalWrite (led11, led11State ) ;
led11timer = millis () ;
}
unsigned long currentMillisrandom = millis();
if ( currentMillisrandom - previousMillisrandom >= intervalblinkrandom)
{
previousMillisrandom = currentMillisrandom;
intervalblinkrandom = random( 25, 300); // set the new interval
// toggle
digitalWrite( led9, digitalRead( led9) == HIGH ? LOW : HIGH);
}
unsigned long currentMillisblink = millis();
if ( currentMillisblink - previousMillis >= intervalblink)
{
previousMillis = currentMillisblink;
// Select what to do with certain values of counter.
switch ( counter)
{
case 0:
case 2:
case 4:
digitalWrite( led3, HIGH);
break;
case 1:
case 3:
case 5:
digitalWrite( led3, LOW);
break;
}
counter++;
if ( counter >= 25)
{
counter = 0;
}
}
}
OK, you got it working, which is good. Now improve it
unsigned long currentMillis = millis();
unsigned long currentMillisblinkrandom = millis();
unsigned long currentMillisblink = millis();
Why have 3 variables holding the current time ?
copy the value of millis() into currentMillis at the start of loop() and use it wherever you need to do calculations based on the current value of millis()
unsigned long waitUntil = 0;
waitUntil += intervalblinkrandom;
What is this doing ?
if (led12State == LOW)
led12State = HIGH ;
else
led12State = LOW ;
// Write new state
digitalWrite (led12, led12State ) ;
can be replaced with
digitalWrite(led12, !digitalRead(led12));
led12timer = millis () ;
led11timer = millis () ;
Don't call millis() again, just set them to the value of currentMillis saved at the start of loop() (see above)
switch ( counter)
{
case 0:
case 2:
case 4:
digitalWrite( led3, HIGH);
break;
case 1:
case 3:
case 5:
digitalWrite( led3, LOW);
break;
}
Looks like a clumsy way of alternating between led3 being HIGH or LOW
@RoelDriessen Well done 8)
I agree with UKHeliBob, you should improve it to make the code look better.
Don't do that for us, but for yourself. When you want to change something later, it is a lot easier with good written code.
@UKHeliBob Can you scroll back and try my example with the blinking and the switch-case ? RoelDriessen wanted three short blinks and then a longer delay. I called it "The most silly one", you called it "a clumsy way". Ha ha ha, I will stop laughing when you show a sketch that is just as short and clear, but better
@UKHeliBob Thanks! I like it. Using a table for a sequence is the most common way to do this. I should have known that. Since there is complete control over the intervals it is indeed better.
The first objective should be to get things working. Then is the time to make it "better" but frankly, if it works, does it matter as long as there are no bugs lurking, perhaps to catch you out in 49 and a bit days time.
Hi there again! Weekend time, so picked up the arduino work again. Thanks again for your feedback and codes. I went through my code and did some cleanup and changed some namings to be inlign and also for me to understand which led is doing what.
It still works how I want it to work, so I am happy
/* Multiple independent blinking LED
This scetch was build with help of many forum members and contains 3 ways of blinking leds, for example used for Firetrucks in Netherlands, Germany etc
Led 1+2 are representing normal beacon who have an different interval so prevent a standard left right.
Led 3+4 are representing blinkers that simultaneously flash 3 times short and wait, this can be used for blinkers in the grill
Led 4+5 are representing blinkers that flash at a random speed and interval
*/
// Which pins are connected to which LED
const byte led1zw = 2;
const byte led2zw = 3 ;
const byte led3k = 4 ;
const byte led4k = 5;
const byte led5kr = 6 ;
const byte led6kr = 7;
// Time periods of blinks in milliseconds (1000 milliseconds to a second).
// Time variable and constants are always unsigned long
const unsigned long led1zwinterval = 300UL ;
const unsigned long led2zwinterval = 275UL ;
unsigned long previousMillis;
unsigned long previousMillisrandom;
unsigned long previousMillisrandom1;
unsigned long intervalblinkrandom = 200UL; // not a constant, it will be changed
unsigned long intervalblinkrandom1 = 200UL; // not a constant, it will be changed
unsigned long currentMillis = millis();
const long periods[] = {50, 50, 50, 50, 50, 50, 1000, 0};
byte index;
// Variable holding the timer value so far. One for each "Timer"
unsigned long led1zwtimer = 0 ;
unsigned long led2zwtimer = 0 ;
unsigned long led3ktimer = 0 ;
unsigned long led4_5ktimer = 0 ;
unsigned long led6krtimer = 0 ;
// Variable to know what the current LED state is
int led1zwState = LOW ;
int led2zwState = LOW ;
int led3kState = LOW ;
int led4kState = LOW ;
int led5krState = LOW ;
int led6krState = LOW ;
void setup() {
pinMode (led1zw, OUTPUT) ;
pinMode (led2zw, OUTPUT) ;
pinMode (led3k, OUTPUT) ;
pinMode (led4k, OUTPUT) ;
pinMode (led5kr, OUTPUT) ;
pinMode (led6kr, OUTPUT) ;
led1zwtimer = millis () ;
led2zwtimer = millis () ;
led3ktimer = millis () ;
led4_5ktimer = millis () ;
led6krtimer = millis () ;
}
void loop()
{
unsigned long currentMillis = millis();
if ( (millis () - led1zwtimer) >= led1zwinterval ) {
digitalWrite(led1zw, !digitalRead(led1zw));
led1zwtimer = millis () ;
}
if ( (millis () - led2zwtimer) >= led2zwinterval ) {
digitalWrite(led2zw, !digitalRead(led2zw));
led2zwtimer = millis () ;
}
if (millis() - led4_5ktimer >= periods[index])
{
digitalWrite(led3k, !digitalRead(led3k));
digitalWrite(led4k, !digitalRead(led4k));
index = ++index % 8;
led4_5ktimer = millis();
}
if ( currentMillis - previousMillisrandom >= intervalblinkrandom)
{
previousMillisrandom = currentMillis;
intervalblinkrandom = random( 25, 300);
digitalWrite( led5kr, digitalRead( led5kr) == HIGH ? LOW : HIGH);
}
if ( currentMillis - previousMillisrandom1 >= intervalblinkrandom1)
{
previousMillisrandom1 = currentMillis;
intervalblinkrandom1 = random( 50, 275);
digitalWrite( led6kr, digitalRead( led6kr) == HIGH ? LOW : HIGH);
}
}
It's nice when something works.
Now, can it be improved and/or tidied up even more ?
Having copied the value of millis() into the currentMillis variable at the start of loop() why not use it throughout the program when you need the value of millis() rather than reading it again ?
@RoelDriessen, here UKHeliBob and me have different opinions.
With the Arduino, false = 0, LOW = 0, INPUT = 0 and true = 1, HIGH = 1 and OUTPUT = 1.
I like to keep them seperated.
The boolean "not" operator is the "!", but I use that for 'bool' variables only.
A "not" with a "HIGH" or "LOW" has no meaning for me.
Of course, this verbose code will be dismissed by experienced programmers who delight in tricks to avoid typing. We should not forget that the compiler will optimise the code so we could end up with the same compiled code for several different source code solutions. The source code is meant to be read and understood by humans whilst the compiled code is meant to be read and understand by the computer.
Fastest solution ?
Use port manipulation for an extra level of obscurity or, of course, write the whole thing in assembler for extra points
The first requirement of any program is that it works and does what is required of it, preferably in a way that can be understood, maintained and fixed at some future date. If the requirement requires that the program operates in a given timeframe then by all means do what is necessary to achieve it.
You know what XOR does but others might not. A comment in the code as to what is being done would be appropriate I suggest. I try to make my code readable by one means or another.
Of course, all of this is dependant on the skill and experience of anyone reading the code. Here we tend to be dealing with questions from newcomers to the Arduino who are often new to coding of any kind, so any help that can be given is appreciated. What is blindingly obvious to you may look like a foreign language to someone else.