BlockNot
BlockNot is a library that creates non-blocking timers with simplicity.
Install / Use
/learn @EasyG0ing1/BlockNotREADME
BlockNot Arduino Library
This library enables you to create non-blocking timers using simple, common sense terms which simplifies the reading and writing of your code. It offers, among several things, convenient timer functionality, but most of all ... it gets you away from blocking methods - like delay() - as a means of managing events in your code.
Non-Blocking is the proper way to implement timing events in Arduino code and BlockNot makes it easy!
*** If you are updating to this new version (2.4.0), READ THIS so that your code doesn't stop working.
*** If you are noticing unwanted rapid succession triggering on high speed microcontrollers, READ THIS
Table of Contents
<!-- TOC -->- Quick Start
- Theory behind BlockNot
- How To Use BlockNot
- Examples
- Library
- Discussion
- Version Update Notes
- Suggestions
Quick Start
Here is an example of BlockNot's easiest and most common usage:
First, you crate the timer:
#include <BlockNot.h>
BlockNot helloTimer(1300); //In Milliseconds
OR optionally
#include <BlockNot.h>
BlockNot helloTimer(15, SECONDS); //Whole Seconds timer
BlockNot helloTimer(120000, MICROSECONDS); //Microseconds timer
Then, you just test it to see if it triggered.
if (helloTimer.TRIGGERED) {
Serial.println("Hello World!");
}
Every time the TRIGGERED call returns true, the timer is reset and it wont trigger again until the duration time has elapsed (all behaviors can be changed based on your needs).
That is all you need to start using BlockNot. Keep reading to learn about other features of the library.
Theory behind BlockNot
This is a traditional non-blockling timer:
long someDuration = 1300;
long startTime = millis();
if (millis() - startTime >= someDuration) {
//Code to run after someDuration has passed.
}
This does the same thing, only with much simpler code!
if (myTimer.TRIGGERED) {
//Code to run after timer has triggered.
}
The idea behind BlockNot is very simple. You create the timer, setting its duration when you declare it, then check on the timer in your looping code to see if it TRIGGERED. Or, you can check for other information such as how long until it will trigger, or how much time has passed since it last triggered or you can ask it what the current duration is, which might be useful in scenarios where you change the duration based on dynamic criteria.
For example, if you wanted to see if the timers duration has come to pass, but you don't want to reset the timer, you can use this method:
if (myTimer.triggered(NO_RESET)) {}
OR, you can do it like this:
if (myTimer.HAS_TRIGGERED) {}
They both do the same thing, but in terms of readability, the second example is the obvious choice. BlockNot has several easy to understand commands that make it very 'user-friendly' and make your code much more readable.
Here is a simple graph showing you how BlockNot timers work. What's important here is to realize that your code never stops executing while the timer is passing time.

How To Use BlockNot
The Trigger
BlockNot is all about the trigger event. When runners line up to start a race, it is a traditional practice for someone to stand next to the line and hold a gun in the air and pull the trigger when the race starts. That is the idea behind the TRIGGERED event in BlockNot. If your timer is set, for example, to 1300 milliseconds, it will return true when you call the TRIGGERED event on or after 1300 milliseconds have passed ... there are exceptions, however, as you will see which can be useful.
if (voltageReadTimer.TRIGGERED) {
readVoltage();
}
One Time Trigger
I have personally found it quite handy in some scenarios, to be able to get a boolean true response after the timer has triggered, but only once, so that the code which executes after getting a true response only executes once and when the test comes up again in the loop, a response of false will be given until the timer has been manually reset. The false response can be changed to true if you desire, by running this method:
myTimer.setFirstTriggerResponse(true);
This kind of trigger is called FIRST_TRIGGER and you use it like this:
if (myTimer.FIRST_TRIGGER) { my code }
That method will return true ONLY ONE TIME after the timer's duration has passed, but subsequent calls to that method will return false until you manually reset the timer like this:
myTimer.RESET;
Why would you need to do that? There are countless scenarios where that would be immediately useful. I have used it with stepper motor projects where I want an idle stepper motor to be completely cut off from any voltage when it has been idle for a certain length of time ... lets say 25 seconds.
So first, we define the timer
BlockNot stepperSleepTimer (25, SECONDS);
Then, we reset the timer every time we use the motor:
stepperSleepTimer.RESET;
Then, in your loop, you would put something like this:
if (stepperSleepTimer.FIRST_TRIGGER) {
sleepStepper();
}
So that if the stepper hasn't moved in the last 25 seconds, it will be put to sleep and that sleep routine won't execute over and over again each time the loop encounters the check. Yet when the stepper is engaged again, the sleep timer is reset and when it becomes idle again for 25 seconds, it is put to sleep. This helps efficiency in your program, and it conserves valuable CPU time.
Trigger Next
This allows you to signal the timer to trigger the next time it is checked regardless of whether or not the duration time has passed.
I have found situations where I am using more than one timer to accomplish some purpose where I need a dependent timer
to
trigger the next time it is checked depending on the situation. For example: When using a WiFi module in a project, I
often use a timer to periodically check to make sure WiFi is connected. If not, then I reset the module so that it makes
a clean effort to re-connect to the access point. But lets say that I have another method that will do something like
sync a local Real Time Clock with an Internet Network Time Protocol (NTP) server but I only want to run this method once
the
WiFi has connected. Lets also say that I prefer to re-run the time sync method every few days to mitigate time drift in
the local RealTimeClock. So I have a timer called resyncTimeTimer but its duration is set to execute every three days.
In that case, I want resyncTimeTimer to trigger the next time it is checked once the WiFi module has connected to the
local access point, so my code would look something like this:
#include <BlockNot.h>
enum UpDown {
UP,
DOWN
}
UpDown wifiState = DOWN;
void getWifiState() {
wifiState = WiFi.status() == WL_CONNECTED ? UP : DOWN;
}
void connectWifi() {
BlockNot delay(25, SECONDS);
Serial.println("Attempting to connect to Wifi...");
WiFi.disconnect();
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
getWifiState();
// This while loop will wait for the WiFi to connect for 25 seconds
// If the Wifi connects OR 25 seconds pass, the loop exits.
while (wifiState == DOWN and !delay.TRIGGERED) {
getWifiState();
}
}
void loop() {
static BlockNot checkWifiTimer(60, SECONDS);
static BlockNot resyncTimeTimer(4320, MINUTES); // 72 hours (60 * 72)
if (checkWifiTimer.TRIGGERED) {
getWifiState();
if (wifiState == DOWN) {
connectWifi();
resyncTimeTimer.TRIGGER_NEXT;
}
}
if (resyncTimeTimer.TRIGGERED and wifiState == UP) {
syncRTCTime();
}
}
Using the TRIGGER_NEXT macro on the re-sync timer lets me use the code that the time holds in the situation where I need that code to run immediately instead of waiting for the timer to trigger. After it runs, the timer will not trigger again until its duration has passed (three days in this example).
Code like this works especially well on a micro controller like the Pi Pico, where it can be run in a loop in a separate thread in the second core of
Related Skills
node-connect
354.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
112.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
354.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
354.3kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
