This is my function I created to blink the LED without delay using the millis() timer function.
ledPin is mapped to which led
ledstate is mapped to state variable for the led
n is the number of blinks passing thru argument
interval is set to 20ms (tried 1000ms) but i think this is just how long before it moves to next instruction
void blinkLed(const int &ledPin,int &ledState, int &n)
{
for(int i = 0; i < n; i++)
{
currentMillis = millis();
if(currentMillis - timer > interval)
{
timer = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
{
ledState = HIGH;
}
else
{
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
}
perhaps I shouldn't be using a for loop? I thought the millis() is a timer and then loops to next iteration. I do have a feeling I need to multiply n*2 to cover the off state.
as of right now if I set n = 2; then it only turns on the led, no off
Umm.. Looks like your building in your own delay() by holding everything in this function 'till you finish blinking.
This "blink without delay" thing. You are looking at it the wrong way.
If someone tells you to feed their cat once a day for a week. Do you go to their place, wait the entire week watching the clock for the correct times to feed their cat? Do you never think you may be missing something in the outside world while doing this?
I thinking you'd amuse yourself living life keeping track of time 'till it's time to go feed the cat then head back for more fun and games in the real world.
You watch "time" in loop(), this is the real world. When its time, you pop off and either turn the light on, or turn it off setting whatever state globals you need. Then exit. The trick is, you don't wait for anything. You don't want to waste your life watching the cat eat.
Sounds like i need to pull out my millis snippet to outside the function with other stuff going on that could be happening and figure out how long it takes for the one cycle to blink and apply that by multiplying by N for the interval. I'm going to go experiment, will report back soon
The most used solution is to start the blinking with a function. That functions enables the millis timer and sets a few global variables. Then in the loop() is a "update()" function that does the millis timing.
In the "update()" function, you can keep track of how many times the led should blink (using global variables).
The base of the "update()" function is the Blink Without Delay: https://www.arduino.cc/en/tutorial/BlinkWithoutDelay.
Maybe you have already used a library that uses a "update()" function in the loop().
I have not used update() before. I checkout the example you suggested, I ee no mention of an updated() feature. Im rethinking my strategy here see what I am missing.
I understand what the first poster says. Its a watchdog timer, you set the timer do what needs to be done , even if its nothing, then come back to it when its done, so you are not stuck in a dead loop
Thank you very much. I was able to successfully do it I think. this is not the complete code but the snippet of the most important part showing the implementation
code removed to restrict plagerism
Please excuse the comments and serial prints they were for debugging
I tested it on my board, seems to be working as expected
You still use millis() as a delay. In that code you block everything with the while-statement. That means you can not do other things while the led is blinking.
When a sketch is using delay() and the sketch needs to be converted to millis(), that means that the whole sketch has to be rewritten. That is why the Blink Without Delay example is so important. Once you have your mind set to that, then you can move on.
The goal is to keep the loop() running as fast and as often as possible.
Start with the Blink Without Delay example.
I have almost written the sketch for you.
Make a small test-sketch first, that we can test ourselves.
yeah I'm still having trouble, here's where I am with your instructions. Ill keep at it until I can figure out. I find another site that talks about the blink without delay.
When you store or calculate something with millis() then always use 'unsigned long', never a 'long'.
My millis_within_millis.ino example shows two millis() timers. One controls the other with a 'bool' variable.
A small but complete and working sketch is the best.
Adding it to your other code and starting it with a serial command, that is something else.
Rule of thumb: Run a millis-timer in the main level of the loop().
That means that if you want to control and blink ten leds, then all the millis-timers should be in the main level in the loop(). That also means that you have to start it somewhere else.
Once you have the millis-timer behind "if((Serial_series == "SR1")" then it will not work. So you need two functions, one to start it and one that runs the millis-timer.
When using a 'bool' variable, a if-statement can be: "if( enable) ...
This is your working sketch, but I changed it a little to prepare it for the next step (to use the serial input):
// Blink a led three times.
const int ledPin = LED_BUILTIN; // the onboard led (pin 13 for Arduino Uno)
// Variables will change:
int ledState = LOW; // ledState used to toggle the LED
unsigned long previousMillis; // will store last time LED was updated
bool enable;
unsigned long interval = 500; // interval between toggles in milliseconds
int count1; // keep track of how many times the led has blinked
const int maxBlink = 3; // number to blink
void setup()
{
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
// Start the blinking
previousMillis = millis();
count1 = 0;
enable = true;
}
void loop()
{
// A 'currentMillis' variable is not needed, but often handy
unsigned long currentMillis = millis();
if( enable) // should we blink ?
{
if( currentMillis - previousMillis > interval) // millis-timer
{
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
if( ledState == LOW)
{
count1++;
}
if( count1 >= maxBlink)
{
enable = false; // enough with this blinking, stop it.
}
}
}
}
With serial input and a "update()" function it becomes this:
// Enter a number using the serial monitor,
// and blink a led that many times.
// As soon as a number is entered, the led turns on.
const int ledPin = LED_BUILTIN; // the onboard led (pin 13 for Arduino Uno)
int ledState; // ledState used to toggle the LED
unsigned long previousMillis; // will store last time LED was updated
bool enable; // turn on (true) and off (false) the millis-timer
unsigned long interval = 500; // interval between toggles in milliseconds
int count1; // keep track of how many times the led has blinked
int maxBlink; // number to blink
void setup()
{
Serial.begin( 9600);
Serial.setTimeout( 50); // Avoid the parseInt to wait too long.
Serial.println( "Enter a number");
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
}
void loop()
{
// Warning: This serial input code is quick and dirty.
// It might not be quick, but it sure is dirty.
if( Serial.available() > 0) // something received ?
{
delay( 50); // wait to hopefully receive the full line
int n = Serial.parseInt(); // I really don't like the parseInt() function
if( n > 0) // was it a valid number ?
{
blinkLed( n); // Start the blinking of the led.
}
// Clear serial input buffer.
// There could be a linefeed and/or a carriage return.
while( Serial.available() > 0)
{
Serial.read(); // read it and throw it away
}
}
// In the main level of the loop(), run the millis-timer.
// This will only work if there are no long delays or
// while-loops in the rest of the loop().
updateLed();
}
void blinkLed( int n)
{
// The led is immediately turned on,
// and after the first interval the led is turned off.
// That will be the first blink.
ledState = HIGH;
digitalWrite(ledPin, ledState);
// Start the blinking
previousMillis = millis(); // update the stored millis time to this moment.
count1 = 0; // start from zero
maxBlink = n; // blink up to this number
enable = true; // enable the millis-timer in the "update" function.
}
void updateLed()
{
// A 'currentMillis' variable is not needed, but is often handy
unsigned long currentMillis = millis();
if( enable) // should we blink ?
{
if( currentMillis - previousMillis > interval) // millis-timer
{
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
ledState = ledState == HIGH ? LOW : HIGH;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
// When the led has just turned low, increase the number that is blinked
if( ledState == LOW)
{
count1++;
if( count1 >= maxBlink)
{
enable = false; // enough with this blinking, stop it.
}
}
}
}
}
This sketch has a blink function that can turn ON/OFF by setting the interval >0 / 0.
It has another function that turns the blink ON/OFF 5 times before taking a break.
// add-a-sketch_on-off_blinker 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 30/2018 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch shows a led blink task turned on-off by another task.
// This led blinker has a built-in on-off switch, if wait > 0 it is ON.
// BlinkSwitcher is a demo that uses OnOffBlinker.
// blinker vars
byte ledState, ledPin = 13;
word startBlink, waitBlink; // 16 bit millis is good to 65.535 seconds
// blink switching vars
byte blinkCounter, lastLedState; // these are to change the blinking
word startOffTime;
const word waitOffTime = 3000; // millis
void setup()
{
Serial.begin( 115200 );
Serial.println( F( "\n\n\n Blink Led, free by GoForSmoke\n" ));
Serial.println( F( "This sketch shows a led blink task turned on-off by another task." ));
pinMode( ledPin, OUTPUT );
waitBlink = 250;
}
void OnOffBlinker() // only blinks if there's a wait time, can be switched on/off
{
if ( waitBlink > 0 ) // this is the on/off switch
{
// word( millis()) gets the low 16 bits of the 32-bit millis() return.
if ( word( millis()) - startBlink >= waitBlink ) // difference in time by subtracting start from end
{
ledState = !ledState; // ! is NOT: not_0/true becomes 0/false else 0 becomes 1.
digitalWrite( ledPin, ledState ); // the led changes state.
startBlink += waitBlink; // next blink starts when it should, where diff > wait.
}
}
else if ( ledState > 0 ) // waitBlink == 0 turns blinking off
{
digitalWrite( ledPin, ledState = LOW ); // make sure the led is OFF
} // yes, you can set a variable during calculation in C, the write here is LOW.
}
void BlinkSwitcher()
{
// this task pauses the blinker after 5 blinks then turns blinking back on, repeat.
if ( waitBlink > 0 ) // while the led is blinking
{
if ( ledState != lastLedState ) // blink has just transitioned
{
if ( ledState == 0 ) // count a blink only if turned off, blink is finished
{
blinkCounter++;
if ( blinkCounter == 5 ) // 5 blinks then none for 3 seconds
{
blinkCounter = 0; // the if has the ++ first, count starts at 1.
waitBlink = 0; // turn the blinking off, start off timing
startOffTime = millis(); // set start to off time
}
}
lastLedState = ledState;
}
}
else // this only runs when blinking is off
{
// word( millis()) gets the low 16 bits of the 32-bit millis() return.
if ( word( millis()) - startOffTime >= waitOffTime )
{
startBlink = millis();
waitBlink = 250;
}
}
}
void loop()
{
// this is the interruptable blink task
OnOffBlinker(); // sets 'now' only when blinking
// this task pauses the blinker after 5 blinks then turns blinking back on, repeat.
BlinkSwitcher();
}
The reason for the "SR1" , its a user input for the command to select which series "n" has to go through to get the number of blinks(in my Case could be SR1 or SR2, but SR1 will always utilize red led and SR2 will utilize the green led). In this Lab we have two series the user can input through, however each series is designated to a specific color led anyways.
I am supposed to request a user command through serial prompt. but there can only be two types of commands
red led: " SR1 n R"
green led: "SR2 n G" // where n is an integer > 0
if any other command comes in I am to reject the input with "Invalid Command".
With your code snippet you created(thank you btw), I need to restrategize how I can I get in. If I'm understanding correctly to avoid dead loops there must be a lot of single checks(if-statements and flags) to be able to migrate around where I need to.
I just wake up, I am going to play around some more. I appreciate your help so far, you can tell I was up late last night trying my best to figure this out myself, the struggle is real. I keep reminding myself " Its always tough the first time trying new techniques after you get it right, you mostly never get it wrong on the same type of obstacle"
edit: it seems instead of Serial.avail() > 0 I should utilize the timeout feature, if no command in is inputted through first cycle, I catch the input on next loop cycle, and so forth , this way the loop can continue down the loop without waiting all the time for input
edit: one of my lab requirements, "execute only one command at a time". so that while loop might not be legal technically. but im thinking I could reject inputs instead of sticking in a while loop. I'm going to keep trying to implement without the while loop
thank you. i was able to get it to work. i closed off the serial.avail brace right after it reads the input and sets enable flag to 1 only after it receives a command.
All my if case statements have that flag enabler and once it enters it can reenter until cnt1 >= blink then all flags and counters are reset.
Im not going to share the code because of other students poaching. but its enough to help them if they see thread.
my code contains zero while loops, for loops, etc. big up to Koepel ,give many thanks