Arduino - Coding without delays using program Ticks

Hi Arduino Forum, I've created a helpful article on my blog that explains how to add delays to your program without actually delaying your program.

http://bakingtechnology.blogspot.com/2013/11/arduino-coding-without-delays-using.html

I've created a helpful article on my blog that explains how to add delays to your program without actually delaying your program.

Why would you want to add delays to your program? Using millis() as in the blink without delay example, WILL allow you to achieve accurate timing. At least more accurate than guessing how many times loop needs to iterate to achieve the desired intervals.

PaulS:

I've created a helpful article on my blog that explains how to add delays to your program without actually delaying your program.

Why would you want to add delays to your program? Using millis() as in the blink without delay example, WILL allow you to achieve accurate timing. At least more accurate than guessing how many times loop needs to iterate to achieve the desired intervals.

Long time ago such delay was done in assembly using NOP and other magic words. In these days I prefer the machine to do the work and figure out how many times the "wait code" needs to be executed to accomplish the desired delay.
Vaclav

millis() is already a "program tick", except that it's one that continues to tick away, at rate meaningful in human terms, regardless of how much code is running in your loop and how much other stuff is going on. You can uses millis() in a sketch pretty much exactly the way the OP's example uses "programTick", giving you approximately the same thing that happens in the Blink_without_delay sketch, without have your code actually "delay" anywhere.

You might also be interested in Arduino Playground - HomePage

attachInterrupt(function, period)
Calls a function at the specified interval in microseconds. Be careful about trying to execute too complicated of an interrupt at too high of a frequency, or the CPU may never enter the main loop and your program will 'lock up'. Note that you can optionally set the period with this function if you include a value in microseconds as the last parameter when you call it.

Completely removes the need for anything in the loop.

Give it a go:

#include <TimerOne.h>

void setup() {
  DDRB |= _BV (5); //pinMode(13, OUTPUT);
  Timer1.initialize();
  Timer1.attachInterrupt(blink, 500000);
}

void loop() {
}

void blink() {
  PINB |= _BV (5);  // digitalWrite(13, !digitalRead(13));
}

Also has the advantage of operating completely independently of "the loop", leaving it free for other things.

Not saying it's a better way, but another different way that might serve a different purpose.

Incidentally, I used this opportunity to "big up" that nice Mr Nick Gammon's post listing the direct port numbers. I have it pinned on my wall for permanent reference!

Simply replacing:

pinMode(13, OUTPUT);

with

DDRB |= _BV (5);

and

digitalWrite(13, !digitalRead(13));

with

PINB |= _BV (5);

takes it from 1,478 to 904 bytes saving 574 bytes. Reasonably significant. (Your example is 980 bytes, so actually smaller code without "fiddling"!).

void blink() {
  PINB |= _BV (5);  // digitalWrite(13, !digitalRead(13));
}

Almost works as expected. You're off by one character.

[quote author=Coding Badly link=topic=201848.msg1497405#msg1497405 date=1386380934]

void blink() {
  PINB |= _BV (5);  // digitalWrite(13, !digitalRead(13));
}

Almost works as expected. You're off by one character.
[/quote]Huh??!? I'm looking at the board flashing away right in front of me - been running like that with that code since I posted it.

What am I missing? Which character? What happens when your run it? What do you mean by "almost" as expected?

EDIT: Just copied that code directly from the forum into a new sketch, flashed it again just in case there was a forum character encoding glitch, and the LED blinks on and of once per second. This is what I expected. Clearly you're not getting the same result. What's happening to your LED? Which board are you using? I'm on the Atmega328-based Uno.

Try expanding the expression.

(also, consider putting some LEDs on the other PORTB pins and watch what they do. )

[quote author=Coding Badly link=topic=201848.msg1497467#msg1497467 date=1386389197]
Try expanding the expression.[/quote]

I'm not sure I follow. I'm "OR"-ing bit 5 of PORTB with whatever bit 5 of PORTB currently is.

This will cause it to flip. Well, it will according to CrossRoads and Nick Gammon....

CrossRoads:
writing a logic one to a bit in the PINx Register, will result in a toggle in the corresponding bit in the Data Register

And it seems to do so. The only thing I could do differently is to put
PINB = _BV (5);
instead of
PINB |= _BV (5);

but while the end result is the same, it uses 2 more bytes. So it wouldn't be that, either.
I also just tried & and ^ in case there was some big byte-saving technique I wasn't aware of, but, as I expected, that doesn't work either.

westfw:
(also, consider putting some LEDs on the other PORTB pins and watch what they do. )

OK, a couple glow very dimly, the rest are all off. As I'd expect, as I've not set them to be or do anything. Not sure why I would for this exercise, but if I make them output and low, then all go out and stay out.
If I make them outputs and high, they stay bright while pin 13 flashes.
As I expect, as I'm only addressing pin13. Should they be doing anything different?

OK, I give up. Hands in the air - I know your point is meant to make me think it out for myself, but I've spent an hour puzzling over this since you told me my code "almost works", but was "off by one character". I'm missing the knowledge gap that's allowing me to fill in the blanks here.

This (now thoroughly confused!) newbie is throwing in the towel and shamelessly begging for a clear explanation :slight_smile:

mixania:
Hi Arduino Forum, I've created a helpful article on my blog that explains how to add delays to your program without actually delaying your program.

http://bakingtechnology.blogspot.com/2013/11/arduino-coding-without-delays-using.html

I do not think the concept you present is usable for accurate timing, on contrary it heavily depends on the flow of loop().
On the other hand, it can be powerful to know how often loop has been called (from main).

But there are some problems you need to tackle. e.g. how to handle continue; return; and break;

void loop()
{
  ...(A)
  if (..) continue;
  ..(B)
  if (..) break;
  ..(C)
  if (..) return;
  ..(D)
}

It really depends where you increase/reset the counter - A,B,C,D - to have the number still correct.

I would put an uint32_t counter into main that would be incremented every time loop is called.
main can be found near the core libs, have to look for exact location
*_ <em>*main() {   uint32_t loopCounter= 0;   setup();   for(;;)   {     loop();     loopCounter++;   } }*</em> _*

lardconcepts:
This (now thoroughly confused!) newbie is throwing in the towel and shamelessly begging for a clear explanation :slight_smile:

You have done an excellent job investigating. You have even identified the symptom. Try slowly carefully rereading your last post. Compare what happened with what you expected to happen. If the light bulb doesn't come on I will put you out of your misery and explain.

OK, I give up! Step by step, here's each stage:

The OP posted a technique for "how to add delays to your program without actually delaying your program".

As others noted, this might be susceptible to other things going on in the loop.
I thought it might also consume a few cycles checking for a count every time the loop runs.

So, having followed some of Nick Gammon's tutorials on on both PWM timers and direct port manipulation, the Crossroad's post about bit-flipping (which also led me to a tip about saving a couple of bytes by "OR-ing") and then being guided toward the TimerOne library, I put all three together and offered an alternative in Timer1.attachInterrupt() function.
I'd been using this library and function for a few days with great success as I needed to fire off an SPI byte to another 328 not only quickly, but regularly too.

What I expected the code to do was to switch the LED on and off once a second. What it did was switch the LED on and off once a second.

You then wrote:

And westfw wrote:

westfw:
(also, consider putting some LEDs on the other PORTB pins and watch what they do. )

I explained that that also behaved in the way I expected.

In fact, to put it all together, this will pulse the LED on and off completely unaffected by the delay in blinking an LED on pin 12, and I've even made the PIN12 LED flash at a different rate so you have a sort of "3/2 time beat" so you can see that neither LED is affected when the other changes state.

#include <TimerOne.h>

void setup() {
  DDRB |= _BV (5); // pinMode (13, OUTPUT);
  pinMode(12, OUTPUT);
  Timer1.initialize();
  Timer1.attachInterrupt(blink, 500000);
}

void loop() {
  digitalWrite(12, HIGH);
  delay(1250);
  digitalWrite(12, LOW);
  delay(1250);
}

void blink() {
  PINB |= _BV (5); // digitalRead (13);
}

All is behaving exactly as I'd expect. So going back to your quote:

OK, the light bulb is coming on, and in the way I expect. As it also did in response to westfw's request.

I did wonder, for a short moment, if it was because I was using "blink()", even though I was redefining it, but changing it to anything else worked just the same, so it wasn't that either.

So, "put me out of my misery" and explain how it "almost works as expected" and which character I am "off by one of"?

I'm genuinely intrigued!

Let's start with the symptom...

lardconcepts:

westfw:
(also, consider putting some LEDs on the other PORTB pins and watch what they do. )

OK, a couple glow very dimly, the rest are all off.

Why would "a couple glow very dimly"? There is nothing in your code that would power any more than one LED. That seems suspicious. (Important lesson: in software development, when something suspicious happens it is always a bug.)

The hints...

[quote author=Coding Badly link=topic=201848.msg1497405#msg1497405 date=1386380934]

void blink() {
  PINB |= _BV (5);  // digitalWrite(13, !digitalRead(13));
}

Almost works as expected. You're off by one character.[/quote]

As far as I can tell, there is only one modification you can make and still have something that compiles and works. You had considered making that change but dismissed it...

The only thing I could do differently is to put
PINB = _BV (5);
instead of
PINB |= _BV (5);

but while the end result is the same

Is the result the same? What's different between the two expressions?

lardconcepts:

[quote author=Coding Badly link=topic=201848.msg1497467#msg1497467 date=1386389197]
Try expanding the expression.

I'm not sure I follow. I'm "OR"-ing bit 5 of PORTB with whatever bit 5 of PORTB currently is.[/quote]

The expanded expression is...

PINB = PINB | _BV (5);

Read PINB, set bit 5 high, write that value to PINB. Reading PINB reads the current state of the eight inputs and outputs on I/O port B. What if input zero is already high? We end up with this...

PINB = PINB | _BV (5);
PINB = 0x01 | 0x20;
PINB = 0x21;

...which toggles two pins! That is definitely not what was expected! In your case, the symptom did not cause any serious problems. What if I/O pin zero was configured as an output that was turned on? That line of code, meant to toggle an LED on I/O pin 5, would also turn off the output on I/O pin zero! Not good.

Does that help?

[quote author=Coding Badly link=topic=201848.msg1500641#msg1500641 date=1386615160]Let's start with the symptom...
Why would "a couple glow very dimly"?

Ah, slight red herring there. The two (very, very faintly) glowing pins are on 11 and 12, MOSI/MISO, breadboarded to an Adafruit level shifter for the SPI. Remove that link and they go out.

What if I/O pin zero was configured as an output that was turned on? That line of code, meant to toggle an LED on I/O pin 5, would also turn off the output on I/O pin zero! Not good.
Does that help?[/quote]

Sort of. Well, yes. And no. In an explanation theory way, yes. In practice, well....

Taking what you said, 0x21 = 0b00100001, with the 1's representing pins 8(PB0) and 13(PB5) ?

So do you mean something along the lines of adding

 pinMode(8, OUTPUT);
 digitalWrite(8, HIGH);

to the top of my sketch?

If I understand what you're saying, pin8(PB0) should be affected - I couldn't replicate that. The light on pin8 (PB0) just stays on.

In fact, just for good measure, I even changed it to
DDRB = 0XFF;
PORTB = 0xFF;

wired them all up, all came on and stayed on except pins 13 and 12 which happily blinked away in their 3/2 time.

Possible I might have misunderstood you there. All I can say is - I most definitely didn't come up with the 2-byte-saving technique myself! I just noted it under "top tips".

I've been searching my history for where I got that " PINB |= _BV (5) is better than PINB = _BV (5) " technique from. All I can say is it wasn't a Nick Gammon tip (he can breath a sigh of relief!) but that around the same time on that evening, I visited various sites including Ready, Set, Oscillate! The Fastest Way to Change Arduino Pins « The Mind of Bill Porter and Hardware XOR For Output Pins On AVR Microcontrollers | Hackaday and and Todays Arduino Moment | Hackaday

And fortunately, a copy-and-paste of "the secret lies in using PINB instead of PORTB" led me to http://letsmakerobots.com/node/22154 too which is similar, but not the same.

If I DO find the exact link I got it from, I'll post back here.

I like how this post became into a "hot" post :stuck_out_tongue: :slight_smile:

PINB = PINB | _BV (5);

What if input zero is already high? We end up with this...
:
...which toggles two pins!

This is actually a really interesting question.

PORTB |= _BV(5);

is well-known to compile down to a single "set bit in IO register" (sbi) instruction. If it didn't, the assembler-lovers would gloat too much.
The sbi instruction, theoretically, does a read-modify-write of the bytewide port, down at the hardware level (which is why it takes two cycles rather than just one.)
But the datasheet EXPLICITY says that "the SBI instruction can be used to toggle one single bit in a port", so it's not quite as straightforward as that.
PROBABLY, the statement above will compile to a single sbi instruction (at least with optimization on), and probably it will only toggle the single bit.

But wait - not all of PINx registers are reachable by "sbi." If you were working with PINL on a MEGA, the compiler would have to generate a read, or, and out instructions. And it would behave DIFFERENTLY...

What fun!

westfw:
What fun!

No doubt!

So, to illustrate the problem on an Uno we need to cripple the optimizer. This may do it...

#define ALT_PINB  (*((uint8_t volatile *)0x23))
...
  ALT_PINB = ALT_PINB | _BV(5);

lardconcepts:
I've been searching my history for where I got that " PINB |= _BV (5) is better than PINB = _BV (5) " technique from.

It is not a question of which is better. It is a question of which is correct. This is simply not correct...

PINB |= _BV (5);

As @westfw described, that it works at all is an accident (a side-effect of the compiler's optimization, the AVR instruction set, and the location of the PIN register in the I/O space).