-1

Just asking if the for-loop function used as a timer instead of a delay, is also causing an unwanted disturbance in the main loop for other code lines.

void okLED() {
  for (long i = 0; i < 150000; i++) {
    digitalWrite(LED_BUILTIN, HIGH);
  }
  for (long j = 0; j < 150000; j++) {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

void slowLED() {
  for (long i = 0; i < 25000; i++) {
    digitalWrite(LED_BUILTIN, HIGH);
  }
  for (long j = 0; j < 20000; j++) {
    digitalWrite(LED_BUILTIN, LOW);
  }
  for (long k = 0; k < 25000; k++) {
    digitalWrite(LED_BUILTIN, HIGH);
  }
  for (long l = 0; l < 110000; l++) {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

Something like this.

I want to build a rear light system based on an Arduino interconnected with the throttle signal from the RC control.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Pertev
  • 3
  • 3
  • Please provide a [mre] and provide details on "causing an unwanted disturbance", "for-loop function", "other code lines", "main loop".... Pretty much everything. Try for [ask]. – Yunnosch Jun 15 '23 at 06:16
  • 4
    Don't write to the digital output every iteration of the loop. Setting the output *once* should be enough. But then you have to make sure that the compiler doesn't optimize out the loops because they have no side-effects. – Some programmer dude Jun 15 '23 at 06:17
  • 1
    Also remember that as long as you're looping, no other (non-interrupt) code will run. – Some programmer dude Jun 15 '23 at 06:18
  • It is called 'busy waiting' – and precision depends entirely on CPU clock. Usually there are better ways to do so, like timer interrupts (not sure, Arduino might not have...), checking a dedicated quartz with a predefined frequency, ... Somehting like: `nextCheck = quartz.ticks + offset; /* other work */ if(nextCheck - quarts.ticks > offset) { doSomething(); nextCheck += offset; } ` – the difference is robust against the counters wrapping around; `> offset` assumes unsigned and offset being reasonably small. – Aconcagua Jun 15 '23 at 06:34
  • 1
    Actually I indeed did something similar for some high precision timing on an Arduino once myself, though not toggling the outputs (as @Someprogrammerdude hinted to already), instead something like `for(unsigned int n = 0; n < SomeLimit; ++n) { asm ("nop;nop;nop");}` – interesting about: there were two controllers doing the same job, but one was slightly slower than the other an required one `nop` less to achieve the same timing… Note, though, that both MCU were intended for just this single task, the wouldn't have been able to yet perform something else any more. – Aconcagua Jun 15 '23 at 06:38

2 Answers2

4

Real embedded systems outside the artificial world of Arduino pretty much never use busy-delays/busy-wait loops as a means to control timing. Such busy-waits are deeply problematic since they stall program execution and cause 100% CPU utilization with 100% current consumption, for no good reasons.

Alternatives used in a professional context involve hardware timers. Either the dedicated timer hardware peripherals, or a dedicated real-time clock hardware peripheral. These can be used either by polling a flag or by interrupts.

For controlling LEDs specifically, "output compare" features of a timer peripheral can be used to automatically activate/deactivate a GPIO pin when a timer runs out. PWM features are also very common, particularly for reducing current consumption or to enable multiple colors in case of RGB.

In either case, any of these various hardware features allow the LED to be controlled in a concurrent manner at the side of the main program.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Usually, at least – had once a scenario where these means just hadn't been precise enough on an Ardiuno, see my comment to question ;) – Aconcagua Jun 15 '23 at 06:43
  • @Aconcagua Sounds like you didn't use external quartz or something. Though I don't remember what the AVR ISA guarantees in terms of NOP. Some ISA allows the CPU to literally execute no code during zero ticks when encountering NOP. Others guarantee 1 tick. – Lundin Jun 15 '23 at 06:46
  • Indeed, no external quartz; the MCU where intended as a quick (and cheap…) test tool for LED stripes produced by the company I used to work for those days. Time dependent protocol on one single pin with timing fast enough that it could only be observed with an oscilloscope – well, clock differences between the CPU where noticable already (trying to recall I think the `nop`s even didn't run in a loop at all, in contrast to what I presented in the comment – these two Arduinos were really close to their limits). – Aconcagua Jun 15 '23 at 06:57
  • @Aconcagua Any RC oscillator relies on manual trimming so that would explain individual differences. Hooking up a crystal instead would have meant a massive improvement in real-time reliability. – Lundin Jun 15 '23 at 06:58
  • Indeed... But those two arduinos just had been by hand already (wasn't my decision to use them; but we'd have needed to order further hardware first otherwise), and actually they did their job pretty well, once adjusted correctly ;) – Aconcagua Jun 15 '23 at 07:02
1

Whether you're using a busy for loop or the busy-wait delay() function, both are bad.

Study Blink without delay: https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay

For more advanced cooperative multitasking techniques, see my answer here: How to do high-resolution, timestamp-based, non-blocking, single-threaded cooperative multi-tasking

For reading the RC PWM control signal, that's complicated, but I have an old example here: https://github.com/ElectricRCAircraftGuy/PWM_Reader2_WORKS_PERFECTLY_Hayden_car_lights.

Here's the core code. It blinks an LED at a rate proportional to the throttle setting.

YouTube video:

enter image description here

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265