I'm building a scale which reads a value (from a load cell) and outputs it on a LED screen.

There is a function for the scale, read which will read the value from the scale. However this is not instantaneous - it uses the yield function to wait until the scale is ready.

The LED screen has a function, display which will display an integer on the screen with no delay. However, this lasts barely a fraction of a second, so it must be repeatedly called.

These functions as is are called one after another inside loop(), but it causes only a quick flash of the LED screen followed by a half second of reading.

How would I allow the LED screen to keep displaying a value while the scale reads? I know there's BlinkWithoutDelay - but I'm not using specific times. There is no instance of the function delay anywhere in the program. I also am not going to edit the library which reads the load cell.

  • 4
    What LED screen are you using, and how have you connected it? – Dampmaskin Jan 18 '17 at 15:50
  • 2
    Which libraries are you using and how does your code look like? – gre_gor Jan 18 '17 at 16:35
  • You should post a more complete code, since to make a sort of "multithread" you need to make non-blocking functions. But I think that the problem is not multithreading, but the fact that in the display function you mistakenly reset the display... – frarugi87 Jan 18 '17 at 19:27
  • @frarugi OP stated that the display is LED (matrix?) and not LCD, and seems it is dynamically driven (have no reset) - so frequently updating it is important. – Flanker Jan 18 '17 at 19:41
  • @Flanker yeah, the only way to have that behavior is through a LED matrix; since I never used them I did not think about that. Maybe it is a couple of 7-segment displays... – frarugi87 Jan 18 '17 at 20:43

There is similar questions answered a day ago - Multithreading with Arduino. What your are asking is multitasking or multithreading. Tasks have own loop and task scheduler stops and switches tasks periodically so they appear as if running simultaneously. Task scheduler in turn is usually driver by timer ISR, for AVR a 50-100Hz scheduler timer tick frequency is reasonable.

If there are 2 tasks with same priority (given task scheduler supports priority), they will spare MCU time ~ 50% / 50%. So if timer is 100Hz, each task runs 5ms and interrupted.

Surely task scheduler have overhead, but for small frequency it is negligible, less than 1%. There is no need to modify existing code/library, time sharing is organized transparently.

There are rules to follow when doing multitasking: for example when the scale related function is writing measured value of double type into some variable, this task might be interrupted (by scheduler) during the writing (when only half of the values is written) - and another task will see an incorrect value. The easiest way would be disabling the interrupts during such shared variable update. Google for "race condition", atomic operation, synchronization.

  • IMHO this is not the best solution, since it can break timings... The best solution is to look at the code and rewrite it in order to get a non-blocking function, so you can switch actions at predefined times without the so-called preemption – frarugi87 Jan 18 '17 at 19:30
  • @frarugi87 maybe for this particular case updating the the display from timer ISR would be a better solution. To make a cooperative multitasking, OP has to rewrite the scale library code, which OP doesn't want to – Flanker Jan 18 '17 at 19:49
  • I used a timer interrupt, which works fine. However, when I implemented the solution and uploaded it to the arduino, I became unable to upload sketches to the arduino anymore. – Brandon Ellis Jan 24 '17 at 15:43
  • Since it is unrelated issue, you shall create a new question (describe the problem, steps you made etc) – Flanker Jan 24 '17 at 16:04

There is only one execution unit in this MCU so you can not truly run multiple tasks concurrently.

However, you can achieve the appearance of concurrency by running a higher priority task through an interrupt. For example, you cannot afford to have flickering disspplay. So set up a timer that invokees the display routine periodically. If you set the timer interrupt sufficiently small (over 25hz for example), the display will not flicker.

Your other routines can be run in other isr or in the main loop so they are interrupted by the display routine periodically. In a way that's fully transparent to you.

  • This solution is only applicable when the display set function is relatively fast, otherwise you can get problems in other parts of the program – frarugi87 Jan 18 '17 at 19:32

Here is sketch in pseudo-code that can keep your display going and still make frequent weight measurements, without having to do any multi-threading or similar. The value of 'if a measurement is ready' (below) may come from a status bit in the scale, or simply a time difference using the millis() function; I don't know the specifics of your hardware. I showed weight being an integer. Again, you may need to adapt this to your own hardware. But it is an uncomplicated process for displaying frequently to maintain the display, and reading whenever data is available so the display updates as you get new data, no concurrency required.

void setup()
   // initialize everything;
   // start the first measurement;

void loop()
   static int16_t weight = 0;

   // if a measurement is ready,
      // read the value and store it in 'weight;'
      // start a new measurement
   // endif

   // display 'weight' on the LCD;

Put the value variable outside the loop (as a global variable).

Then, call the display function BEFORE the read function.

This is not the best, but if should work fine.

  • And why should this help with the issue he has? void loop() { read(); display(); } and void loop() { display(); read(); } behave (almost) identically, at least in normal usage – frarugi87 Jan 18 '17 at 19:25

Not the answer you're looking for? Browse other questions tagged or ask your own question.