The merits of delay() vs millis()

Of course it will. :frowning:

I miss that every time, I’m back from when that wasn’t a problem feature, one I do use but not with any pattern or consistency, any of that declaration in the middle of my program stuff…

Good catch. Well if I made it, it would’ve been.

a7

I, of course, have never made that mistake :grinning:

Nor have I ever used a variable declared as byte and tested to see whether its value was less than zero

I have, and it was.
But I was working in Java at the time.

The rules are obviously different in Java, but here in the UK a byte is never less that zero boom, tish ! :grinning:

The choice of "byte" as an unsigned datatype in Arduino is one of the more irritating decisions taken - it means code isn't compatible with the Processing it is supposed to resemble.

I was going to use break; but thought it might blur the concept for a beginner.
Fair points though.

C++ decided to not take side with std::byte

it is not a character type and is not an arithmetic type. A byte is only a collection of bits, and the only operators defined for it are the bitwise ones

If you want smooth running code without stutters, you only run short/fast loops so to keep void loop() running fast. To that end you make your own indexes and drive iterative processes to one per void loop() pass.

A delay 30 throws 480000 cpu cycles away.

And unsigned arithmetic, and increment/decrement. It can be used for pointer math.

But if have no use for those 480000 cpu cycles then it does not matter. Such decisions are, of course, at the heart of the delay() vs millis() decision

1 Like

The spec states this

std::byte is a distinct type that implements the concept of byte as specified in the C++ language definition.
Like char and unsigned char, it can be used to access raw memory occupied by other objects (object representation), but unlike those types, it is not a character type and is not an arithmetic type. A byte is only a collection of bits, and the only operators defined for it are the bitwise ones.

And then there's what they do in sketches that tells me once again, I write C.

Arduino’s byte is not the same as std::byte was my point.

I can only offer that reliance on a poor approach made this example. How far can it go without breaking should make an exercise in time wasted.

That is exactly the problem being discussed in this topic and your reply puts you firmly in the "never use delay()" camp

It seems like virtually every function in the supplied Arduino libraries is blocking. And writing linear code that blocks every step of the way seems to be the promoted "Arduino Style". Frankly it works great for people who have simple tasks to perform and are not educated as programmers.

I've written two books programming Arduinos, and am working on a third, and a key goal has been to avoid blocking functions. The new book starts out with a game program project implemented in five different ways:

  • Linear, everything happens in a loop, most every function blocks. When a second task is added all hell breaks loose.

  • State Machine. 11 states, IMHO much easier to follow but not linear. A second state machine handles the second task.

  • Callback functions -- state machines don't even run unless triggered by an external event.

  • Interrupt Driven -- state machines runs from an ISR. The loop() function is empty.

  • Real Time Operating System -- game implemented under FreeRTOS. Potentially the easiest approach but requires drivers in the library to yield the processor when they block.

What Arduino functions blocK? Well here are some: analogRead, pulseIn, shiftIn, delay, many Stream and Serial functions, especially if used carelessly, SPI, SoftwareSerial, and many more. Almost all of these could have non-blocking alternatives.

Look at the innocent appearing analogRead. When you call it, you have to wait for the ADC to perform a conversion, which takes 112µs. If instead the command started a read and then you could check for a result later, or have a callback function get called upon completion, then other tasks could be performed at the same time.

2 Likes

@almytom
I agree with every word!

I write non-blocking code as much as possible, but sometimes the choice is between library code (simple but blocking) and writing my own, non-blocking code. I can be a pain sometimes.

1 Like

@almytom: it sounds like it will be a fascinating book. I would love to buy a copy when it's done. Do you plan to announce its publication in this forum?

Also, I'd like to take a look at your previous books - where can I find them?

But @GoForSmoke, it's only a "poor" approach if you have something else that needs those 480000 clock cycles, as @UKHeliBob has already said. If you haven't, then it's a really good approach. Certainly it's simpler and less bug-prone than building yourself a millis()-based FSM, which would then spend those 30ms whizzing round loop() instead.

I can almost hear you saying that it wouldn't sit whizzing around loop(); it would be doing other useful things. At which point I would reply "Exactly! If there's other stuff to do then don't use delay(), as we've said from the beginning. If there isn't, then use delay() because it's simpler." :grinning:

We also agree that a program which is expected to grow beyond a simple linear application should probably be structured from the beginning to support multi-tasking.

A simple millis() based timer to wrap around some code that needs to do something at some particular interval takes no time to type in, probably less time than this reply, so I see no benefit in not using one. As for bugs what bugs can there be in such a thing?