I am trying to make a simple program to run on a raspberry pi pico in C on the Arduino IDE that can track soil and air properties around plants (which I have done) and blink a led continuously if certain thresholds are violated (where I am struggling). (I can make the led blink, but then I cant also continue the measurements).
The goal is that when soil is too dry, or other measurements indicate the conditions are outside desired thresholds, a led would begin blinking and continue blinking, while the program would continue running and taking its readings. So I need the constant blinking to be handled concurrently with the main objective of taking measurements not impacted. I am not sure if I need multi-threading for this (it seems to have it's own issues) or if there is a simpler way to achieve my goal?
Most of my research has seemed to return answers only for micropython or requiring adoption of another IDE which i would like to avoid if possible. Mostly just looking for a direction to research in or an example of a similar project I can study. Thanks all.
millis() provides the time in milliseconds since the processor started running. It overflows in 49 days.
a timestamp can be captured at some point in time.
within loop() the timestamp can be subtracted from the current time and compared (>=) to some period (e.g. 500 msec), and when true, perform some action
the timestamp can be reset to the current value of millis() to perform some periodic action.
of course there can be multiple timestamps and period to invoke a various actions, either periodic or aperiodic
Demo-Code that shows how to do "blink" without blocking other functionality.
This is called non-blocking timing.
explaining non-blocking timing
I want to comment on the basic blink_without_delay example-code.
The basic basic blink_without_delay example-code makes understanding non-blocking timing harder than it must be for multiple reasons:
It starts with postings that have sentences like "use function millis() instead of delay()"
There is a pretty high danger that this sentence creates a totally wrong picture of how non-blocking timing works.
Such a sentence initiates a wrong picture of
replace delay() with millis() and you are done.
non-blocking timing requires more than a simple replacing.
the blink without delay-example does NOT mention that there is a fundamental difference
between delay() and non-blocking timing
Without explicitly explaining this difference newcomers are in danger to see a delay()-similar-Thing
And trying to see a delay()-similar thing will cause extra confusion because there is NO similarity!
a part of the variable-names is badly chosen.
the demo-code distributes the variables to mutliple places
The variable-distribution makes it harder to understand the basic principle.
I suggest that you watch this video as the introduction to non-blocking timing
It will guide you on the right track and explain it step by step
My recommendation:
A timer function based on the millis() function is actually always required in every project.
The timer function can be easily derived from the BLINKWITHOUTDELAY example, the mother of all Arduino timers, in the IDE.
What does the timer function do?
The timer function provides time slots in which actions are executed without blocking the programme as with the delay() function.
The timer function should be scalable and offer the following services:
make()
start()
stop()
isExpired()
isRunning()
Try it out and programme your own timer function first.
static const int blinkSpeed = 200; // speed of blink
static const int LEDPin = LED_BUILTIN; // which LED
void blinkLED() {
static uint32_t lastBlink; // time at which the last LED state change occurred
uint32_t now = millis(); // time it is NOW.
if (now - lastBlink > blinkSpeed) { // now - lastblink is elapsed time
digitalWrite(LEDPin, digitalRead(LEDPin) == HIGH ? LOW : HIGH); // toggle LED
lastBlink = now; // update time of state change
}
}
(This is essentially, the "Blink without Delay" example, only ... all encapsulated with locally meaningful names and such.)