Go Down

Topic: A handy hint? or not. Blink without delay 3.0. (Read 2806 times) previous topic - next topic

cjdelphi

Sep 27, 2012, 10:06 am Last Edit: Sep 28, 2012, 06:54 pm by Coding Badly Reason: 1
I was thinking...  what's the easiest and i mean EASIEST way to create a "delay" without actually implementing a delay, for example, you
have a sensor sending the results between 0-1024.

but, when you do Serial.println(data);

so, what are your options?

Create a Delay time, measure how many seconds pass and if > 3 seconds, display(whatever); the other way is to simply

Serial.println(data)
delay(400);


but that might effect time critical routines... so a few weeks back it occurred to me ...

Code: [Select]

int n = random(500);
if (n==65)
  Serial.println(data);


every couple of seconds or so, you see the data coming in, is using Random? taxing on the CPU? any benefits to using this method?


Coding Badly

Quote
is using Random? taxing on the CPU?


Relative to the println, no.

westfw

You might also think about something like
Code: [Select]
if ((millis() & 0x1ff) == 0) {
  Serial.println(data);
}

That should print something about every half a second...

PeterH


any benefits to using this method?


The only benefit I can see is that you output arrives at random intervals. If that's what you wanted, this achieves it.

If what you really want is to have the output arrive at defined regular intervals while also doing other things in the meantime, then the technique demonstrated in the 'blink without delay' example sketch shows you how to achieve that.
I only provide help via the forum - please do not contact me for private consultancy.

cjdelphi

i was offering this as a "tip" for other users and if it's worthy enough to be used as a tip.


obviously not.

Oracle


Code: [Select]
if ((millis() & 0x1ff) == 0) {
  Serial.println(data);
}



If your loop takes more than half a millisecond or so, won't you miss some of the times the last 9 bits of millis() are 0?  It seems you'll have your println at some pseudo-random multiple of half a second.


WizenedEE

Well the correct way to do it is only three lines:
Code: [Select]

static unsigned long lasttime;
if (millis() - lasttime > 1000) {
  Serial.println();
  lasttime = milis();
}


I suppose you could make a macro
Code: [Select]

#define RUNEVERY(n) for (static unsigned long lasttime; millis() - lasttime > (n); lasttime = millis())


and then use it like this:
Code: [Select]

void loop() {
  int sens = analogRead(0);
  RUNEVERY(500) {
    Serial.print(F("Sens: "));
    Serial.println(sens);
  }
}


That's untested, since I don't have arduino on this computer. But if that works, I'd support it being defiend in Arduino.h --- it is extremely useful and would preempt a lot of questions on this forum. (Although there is something to be said for learning to do it the "right" way, the same can be said of "hibyte," "lowbyte," "shiftout," "bitRead," etc.)

PeterH

I've never tried declaring a static variable in the initialisation expression of a for loop. It that legal?
I only provide help via the forum - please do not contact me for private consultancy.

pYro_65

Yes, its legal. If GCC is standard conforming, it should only be in scope for the loop that's all.

Coding Badly

#9
Sep 28, 2012, 04:23 am Last Edit: Sep 28, 2012, 04:25 am by Coding Badly Reason: 1

"Run every" implies that it should run N times in T time...

[font=Courier New]  #define RUNEVERY(n) for (static unsigned long lasttime, unsigned long t = (n); millis() - lasttime > t; lasttime += t)[/font]

"Run after" implies that it should run after T milliseconds have elapsed...

[font=Courier New]  #define RUNAFTER(n) for (static unsigned long lasttime; millis() - lasttime > (n); lasttime = millis())[/font]

The variable should be named to reduce the chances of a conflict...

[font=Courier New]  #define RUNAFTER(n) for (static unsigned long _lasttime; millis() - _lasttime > (n); _lasttime = millis())[/font]

To be more Arduinoish the macro should be named in modified camel...

[font=Courier New]  #define runAfter(n) for (static unsigned long _lasttime; millis() - _lasttime > (n); _lasttime = millis())[/font]

To eliminate drift, time should be sampled once...

[font=Courier New]  #define runAfter(n) for (static unsigned long _lasttime, unsigned long _thistime = millis(); _thistime - _lasttime > (n); _lasttime = _thistime)[/font]

The error needs to be eliminated...

[font=Courier New]  #define runAfter(n) for (static unsigned long _lasttime, unsigned long _thistime = millis(); _thistime - _lasttime >= (n); _lasttime = _thistime)[/font]

16 bit may be a better choice...

[font=Courier New]  #define runAfter(n) for (static uint16_t _lasttime, uint16_t _thistime = millis(); (uint16_t)(_thistime - _lasttime) >= (uint16_t)(n); _lasttime = _thistime)[/font]

What did I forget?

WizenedEE

Code: [Select]
static uint16_t _lasttime, uint16_t _thistime

is illegal. You might be able to do some strange things with a struct though:

Code: [Select]

#define runAfter(n) for (struct { static uint16_t last; uint16_t now; } _rA = {0, millis()}; _rA.now - _rA.last >= (n); _rA.last += (n))


That doesn't work either, though: static means something different there.


I also think that runEvery is a better name because it reads "Run every 500" (ms) which is exactly what it does. runAfter imples it only runs once, and has a built in delay.

_thistime is unnecessary if you do the += (n) trick, since then millis() wil only be called once.

so this is what I'm thinking of:
Code: [Select]

#define runEvery(t) for (static uint16_t _lasttime; millis() - _lasttime > (t); _lasttime += (t))


which is tested and works on my uno.



Thanks for checking it out though --- hopefully a macro like this one will be useful to others.

pYro_65

#11
Sep 28, 2012, 07:56 am Last Edit: Sep 28, 2012, 08:02 am by pYro_65 Reason: 1

Code: [Select]
static uint16_t _lasttime, uint16_t _thistime

is illegal. You might be able to do some strange things with a struct though:


According to the standard. 6.5.3 - 3

Quote
If the for-init-statement is a declaration, the scope of the name(s) declared extends to the end of the for-statement.


But I see the static now, :( . hmmm

westfw

Both the original (random) and my hack (bitwise and) don't use extra ram...
Whether they're suitable or not depends on unspecified requirements and behaviors.

sbright33

Nice Macro!  Very useful.  I wish there was a way for beginners to find it easily while Googling.
If you fall... I'll be there for you!
-Floor

Skype Brighteyes3333
(262) 696-9619

Coding Badly

I wish there was a way for beginners to find it easily while Googling.


You can give Google a helping hand.  If you or anyone you know has a blog, add a paragraph or two about the macro and include a link to this topic.

Go Up