Getting a loop to execute in a defined amount of time

If time2-time1 is greater than 1000, the time slice has been overrun.

As I noted, any solution will do something in that case - either what you plan or what just happens.

a7

I guess it depends on how long the code in question takes to run, no? If you have a timer of one seconds before it enters an if block, then the code takes 200ms to run then the update frequency is then 1200millis. Not the 1000millis required from the OP.

So... Any thoughts on something like this where it times how long the code took to run each time, and offsets the amount required before it enters the code-block again?

#define UPDATE_FREQ 1000

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  static unsigned long timeToComplete;
  static unsigned long timeCapture;

  if ((millis()-timeCapture) > (UPDATE_FREQ - timeToComplete)) {
    timeCapture = millis();
    
    unsigned long startTime = millis(); // Start the timer before your code

    // Do your code here
    delay(250); // Delay only to simulate your code
    ////////////////////

    timeToComplete = millis() - startTime;  // End the timer after your code
  }
}

If the code that needs to be executed exceeds the allowed time interval there is going to be problems no matter which method you use. In the best case the code will then execute at an interval limited by its own execution time, with no additional delays needed, in a worse case where the integer overflow affects the delay there may be a 49 day wait time. If there is a watchdog timer running there may even be a processor reset.

And with millis() you are only going to get about 5ms resolution.

unsigned long a = millis();
insiigned long b = millis();

Serial.println( b-a );

millis() is not that accurate for what the OP seems to require.

Self adjusting millis code, remember its going to be about 5ms off on a Uno.

Interesting to know

Resolution isn't too bad, millis() will occasionally jump by 2, mostly by 1.

But yes the accuracy on the Uno is crippled by its ceramic resonator with its 0.5% or so basic accuracy.

BTW:

Prints zero except very very occasionally.

Please check your facts, this is not true (and certainly not possible).

The Uno and similar have an interrupt running every 1024µs, and use timer0 to trigger this and to count multiples of 4µs (timer0 also handles PWM for pins 3 and 11, is 8-bit and clocked at 250kHz on a 16MHz ATmega328, which is prescale factor of 64. Timer0 is run in fast PWM mode which rolls over every 256 prescaled clocks, hence the 1024µs interrupt period.

Because of this the millis counter only updates at a rate of 976.5625Hz (assuming the 16MHz clock is accurate, which it isn't at all!), which is why it has to jump by 2 occasionally.

You could rewrite millis() to be more like micros() and update at the correct rate, but I guess it was thought unnecessary. If you want more accurate timing micros() is the way to go in the first place.

BTW the code for this is in wiring.c in hardware/arduino/avr/cores/arduino/ (well in older versions of the IDE at least). You can find the source inside your install or at GitHub and see exactly how it works if you want, it can be instructive.

I don't know what I was thinking when I wrote that. The only thing that I said that was correct is the 4µs resolution of micros. I've deleted my earlier post!

Why 1 second? Is that the max reading frequency for your PV input?

Without knowing your system and its components ... I'm thinking an alternate approach might be to use an interrupt triggered by a zero-cross detector. If your line frequency is 60Hz and your sensor can send new readings (PV) quicker than 16.7 ms or if If your line frequency is 50Hz and your sensor can send new readings (PV) quicker than 20 ms, then the interrupt timing could be your PID sample time.

With this method, If you're using a zero cross type SSR, the period of AC power control would be consistent. If you need precisely 1 second, could use a counter in the ISR to trigger the SSR every 50 or 60 counts.

it is unclear what you want to do in the end. What is the real-purpose of the system?
(laconic answer POSIWID purpose of a system is what it does)

details versus overview:
We are talking about details. Please give an overview over your whole project.
in mimimum 70% of all cases knowing the whole thing offers completely different and much better working solutions.

This is like

here is an analogon that shall show what can happen if just ask for details:

Newbee: "I want to do better cutting please help me sharpening. "
Expert: Sure I can help you. What kind of cutting-tool are you using?
Newbee: a scissor.
Expert: OK take this sharpening tool
Newbee: Yea works great Next question How can I make it cut faster I need to finish faster.
expert: Motorised scissors.
newbee Yea works great though still not fast enough.

expert: Ok can you give an overview about what you are cutting.
newbee: the green of a football-arena.
expert: Oha! take a big mowing tractor with a seven boom spindel-mower and GPS-steering

In the beginning the newbee always just told details.
The expert was assuming the newbee knows that his basic approach is well suited.
which turns out to be very bad suited
that's the reason why it is always a good idea to give an overview and to explain what shall happen in the end.

best regards Stefan