@alto777 can you explain the math behind it or post a solution that is calculating blinkfreqeuency and pausing time based on user-changeable constants?
@PaulRB I tested your code and found it to function plausibly.
I timed that for fun. It took me 70 seconds to copy your code, place it in a simulation, wire an LED so I could see it better and then compile and execute the code.
Also I have an UNO connected semi-permanently, it already has a nice extra LED on pin 13. I did not measure but it could not have taken a minute to test it IRL on that hardware.
Now maybe I'll look at your code.
I've been seeing more subtle miscastings of millis() in the service of eliminating delay(), not saying this is the case with any of the examples here, but I have become less confident in my own ability to sling together things like this, and more surprised about how a dropped millisecond here or there (or other flaw) can, over sometimes not that very long a time, start to "misbehave".
So let's all be careful out there. Testing something like these examples for correctness is probably harder than writing them in the first palce.
The two hacks @alto777 visited upon us were, I assume, for your amusement. They are one bad and the other horrible. I hate tricks like that.
They both can be generalized a bit, but are far from suitable should the requirements change even a little bit. Some of the other examples may be a bit more flexible.
The code in #10 can support only changes in the number of blinks and the length of the pause between groups of blinks, and can be changed to operate faster or slower. Blink duty cycle is frozen at 50 percent, and all timing is based on units of N ms, hard coded here at 250.
The method in #13 is a bit more flexible algorithmically, but quite tricky to flex. An obvious (!) extension to the way it works would allow a fixed duty cycle of 1/2^N, that is to say 50, 25, 12.5 percent and so forth.
I now am thinking that #10 could be altered to allow similar change to the duty cycle.
All exercises for the reader. Or not. Srsly, I would say go to the beach instead.
Though it depends on the knowledge about what each part means
and for me personal it will take a longer time to understand it because I'm not familiar with this kind of calculations.
So there is still air upwards regarding easyness to understand.
Seems to be the cause of a little startup transient. Make it 777 and see.
Both 250 and 1000 should be manifest constants, then this wouldn't have cropped up.
int flash = 250;
int pause = 1000;
unsigned long msecPeriod = flash;
unsigned long msecLst;
and so forth.
Another thing I would change is to add a real variable instead of reading back the output pin to determine the LED state. I can't imagine that it wouldn't always be possible to do that (read the output register), though. It is something I've done more recently, usually in quick hacks as a convenience.
I should have sarcasm tags. The second version is a nightmare, and the use of hex, decimal and octal constants was intentionally obfuscatory.
Both my versions will yield to analysis. One is only one line of code, so how hard could it be?
I also assumed you were coaxing an explanation/elaboration on a pedagogical basis. TBH I don't think anyone should be taught those tricks, but I do think it would be fun to figure out. My hope is that code like that would never make it into any serious piece of software.
Agree. That would use a shift operation instead of division, added to '&' and '%', which are arguably not always among the first few handfuls of knowledge someone picks up or is taught learning C, so a win-win.
I knew something would happen 49.7 days out. I did not think about what that might be. And for human consumption, the two percent difference in the period would be negligible. Maybe it would be closer on Arduinos on the high end of their lousy clocks.
I have said the second version is horrible. Here's a version that is still bad, with a few comments that I hope are not misleading.
# define TICK 200 // basic step size milliseconds
# define LENGTH 32 // number of TICKS for entire sequence
# define OFFSET 108 // move the index close to 128 (0x80)
# define MASK 0x43 // light the LED if we are under 0x40 and at 0x3 of the low two bits count of 4 (25 % duty cycle);
void setup() {
pinMode(13, OUTPUT);
}
void loop() {
digitalWrite(13, ((millis() / TICK % LENGTH + OFFSET) & MASK) == MASK);
}
The first steps up to LENGTH are OFFSET so we can use a high bit to mean we are in the flashing portion of the sequence, the bottom 2 bits used further to make the flash on/off. Once we get to where that high bit (0x40) is clear, we are in the pause portion.
I will say again I don't like clever stuff like this. A warning for anyone is a special feeling of accomplishment when a few lines of code does something clever or obscure - ask yourself if even you will be able to read it in the future. Here, a future when I mightn't understand what I did yesterday is tomorrow or even today.
Basically it's like indexing a table at an offset. There is no table, as each entry is equal to the index.
if it's time (TICK loop throttle)
onOff = table[counter];
counter++;
if (counter >= LENGTH) counter = 0;
digitalWrite(theLED, onOff);
OK, I've been playing with the adjustable version above. It is. Adjustable. But evidently adjustments are fraught, and can only be done correctly every time by someone who understands whats going on better than I.