Arduino UNO Q - Blink LED Without Delay

When your Arduino UNO Q needs to do two things at once — like blink an LED and read a button — the delay() function becomes a problem. It freezes the MCU and causes missed events. In this tutorial, you will learn how to blink an LED without delay() using millis(), so the Arduino UNO Q can multitask smoothly.

※ NOTE THAT:

  • This method does more than just make an LED blink and check button status. It allows the Arduino UNO Q to perform multiple tasks simultaneously without interruption.

In this tutorial, you will learn:

Arduino UNO Q - LED - Blink Without Delay

Hardware Preparation

1×Arduino UNO Q
1×USB Cable for Arduino Uno Q
1×LED Kit
1×LED (red)
1×LED Module
1×220Ω Resistor
1×Breadboard-mount Button with Cap
1×Breadboard
1×Jumper Wires
1×Recommended: Screw Terminal Block Shield for Arduino Uno
1×Recommended: Sensors/Servo Expansion Shield for Arduino Uno
1×Recommended: Breadboard Shield for Arduino Uno
1×Recommended: Enclosure for Arduino Uno
1×Recommended: Prototyping Base Plate & Breadboard Kit for Arduino UNO

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Buy Note: Use the LED Module for easier wiring. It includes an integrated resistor.

Overview of LED and Button

Learn about the LED and button (pinout, how they work, how to program) in these tutorials:

Wiring Diagram

The wiring diagram between Arduino UNO Q Button LED

This image is created using Fritzing. Click to enlarge image

MCU Code — With delay() (Problem Demo)

The Arduino UNO Q has two processors: the STM32 MCU (handles real-time hardware control) and the Qualcomm MPU (runs Debian Linux). In this section, only the STM32 MCU is programmed. A later section will show how both processors work together.

This first example uses delay() to blink the LED — and demonstrates why this is a problem:

  • The LED blinks every 1 second using delay(1000)
  • While waiting in delay(), the MCU is completely frozen — it cannot detect button presses
  • Press the button several times and observe that many presses are missed
/* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-blink-led-without-delay */ #define LED_PIN 3 // The Arduino UNO Q pin connected to the LED #define BUTTON_PIN 7 // The Arduino UNO Q pin connected to the button #define BLINK_INTERVAL 1000 // interval at which to blink LED (milliseconds) int led_state = LOW; // led_state used to set the LED int prev_button_state = LOW; // will store last button state void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { // if the LED is off turn it on and vice-versa led_state = (led_state == LOW) ? HIGH : LOW; // set the LED with the led_state of the variable digitalWrite(LED_PIN, led_state); delay(BLINK_INTERVAL); // If button is pressed during this time, Arduino CANNOT detect int button_state = digitalRead(BUTTON_PIN); if (button_state != prev_button_state) { // button state changed — but delay may have caused us to miss some presses prev_button_state = button_state; } }

Detailed Instructions

  • First time with Arduino UNO Q? Follow the Getting Started with Arduino UNO Q tutorial to get your development environment ready before proceeding.
  • Wire the components: Connect the LED (with 220Ω resistor) to pin 3 and the button to pin 7 according to the wiring diagram.
  • Connect: Plug the Arduino UNO Q into your computer with a USB-C cable.
  • Open Arduino App Lab: Launch Arduino App Lab and wait until it detects your Arduino UNO Q — this can take several minutes on first launch.
  • Create a new App: Click the Create New App button.
Create New App in Arduino App Lab on Arduino UNO Q
  • Give the App a name, for example: DIYables_BlinkDelay
  • Click Create to confirm.
  • You will see a set of folders and files generated inside your new App.
Arduino App Lab App folders and files on Arduino UNO Q
  • Find the sketch/sketch.ino file — this is where you will paste the MCU sketch.
  • Paste the sketch: Copy the MCU code above and paste it into that sketch file. Keep other files as default.
    • Install the library: Click the Add sketch library button (the open book icon with a + sign) in the left sidebar.
    Add sketch library in Arduino App Lab on Arduino UNO Q
    • Search for Arduino_RouterBridge created by Arduino and click the Install button.
    My Apps / DIYables Apps
    Run
    Bricks
    No bricks added...
    Sketch Libraries
    No sketch libra...
    Files
    python
    sketch
    .gitignore
    README.md
    app.yaml
    sketch.ino
    Add sketch library
    Arduino_RouterBridge Arduino

    This library provides a simple RPC bridge for Arduino UNO Q boards, allowing communication between the board and other devices using MsgPack serialization.

    0.4.1
    Install
    More Info
    • Upload: Click the Run button in Arduino App Lab to compile and upload to the STM32.
    Click Run button in Arduino App Lab on Arduino UNO Q
    • Test: Press the button multiple times quickly — notice that many presses are ignored because delay() blocks the MCU.
    • Pro Tip: This is the problem that millis() solves — see the next example.

    MCU Code — Without delay() (Solution)

    This example uses millis() to blink the LED without blocking — the MCU checks the elapsed time and acts only when needed, so it can still detect every button press:

    • Uses millis() and prev_millis to track when to toggle the LED
    • Never calls delay() — the MCU is always free to do other tasks
    • Press the button and observe that every press is detected, even while the LED is blinking
    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-blink-led-without-delay */ #define LED_PIN 3 // The Arduino UNO Q pin connected to the LED #define BUTTON_PIN 7 // The Arduino UNO Q pin connected to the button #define BLINK_INTERVAL 1000 // interval at which to blink LED (milliseconds) int led_state = LOW; // led_state used to set the LED int prev_button_state = LOW; // will store last button state unsigned long prev_millis = 0; // will store last time LED was updated void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { unsigned long current_millis = millis(); // check to see if it's time to blink the LED if (current_millis - prev_millis >= BLINK_INTERVAL) { // if the LED is off turn it on and vice-versa: led_state = (led_state == LOW) ? HIGH : LOW; // set the LED with the led_state of the variable: digitalWrite(LED_PIN, led_state); // save the last time you blinked the LED prev_millis = current_millis; } // check button state's change — never missed because no blocking delay int button_state = digitalRead(BUTTON_PIN); if (button_state != prev_button_state) { // save the last state of button prev_button_state = button_state; } // DO OTHER WORKS HERE }

    Detailed Instructions

    • Upload this sketch the same way as above (create a new App or replace the sketch in the existing one).
    • Press the button multiple times quickly — every press is detected without interruption.
    • Pro Tip: Add more tasks inside // DO OTHER WORKS HERE — the LED will keep blinking while those tasks run.

    Adding More Tasks — Two LEDs Blinking at Different Speeds

    This example blinks two LEDs at different intervals while still detecting button presses — all without any delay():

    • LED 1 blinks every 1000ms
    • LED 2 blinks every 500ms
    • Both run independently using separate prev_millis variables
    • Button presses are never missed
    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-blink-led-without-delay */ #define LED_PIN_1 3 // The Arduino UNO Q pin connected to LED 1 #define LED_PIN_2 4 // The Arduino UNO Q pin connected to LED 2 #define BUTTON_PIN 7 // The Arduino UNO Q pin connected to the button #define BLINK_INTERVAL_1 1000 // interval at which to blink LED 1 (milliseconds) #define BLINK_INTERVAL_2 500 // interval at which to blink LED 2 (milliseconds) int led_state_1 = LOW; // led_state used to set LED 1 int led_state_2 = LOW; // led_state used to set LED 2 int prev_button_state = LOW; // will store last button state unsigned long prev_millis_1 = 0; // will store last time LED 1 was updated unsigned long prev_millis_2 = 0; // will store last time LED 2 was updated void setup() { pinMode(LED_PIN_1, OUTPUT); pinMode(LED_PIN_2, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { unsigned long current_millis = millis(); // check to see if it's time to blink LED 1 if (current_millis - prev_millis_1 >= BLINK_INTERVAL_1) { led_state_1 = (led_state_1 == LOW) ? HIGH : LOW; digitalWrite(LED_PIN_1, led_state_1); prev_millis_1 = current_millis; } // check to see if it's time to blink LED 2 if (current_millis - prev_millis_2 >= BLINK_INTERVAL_2) { led_state_2 = (led_state_2 == LOW) ? HIGH : LOW; digitalWrite(LED_PIN_2, led_state_2); prev_millis_2 = current_millis; } // check button state's change int button_state = digitalRead(BUTTON_PIN); if (button_state != prev_button_state) { prev_button_state = button_state; } // DO OTHER WORKS HERE }

    Detailed Instructions

    • Add a second LED (with 220Ω resistor) to pin 4.
    • Upload this sketch — both LEDs will blink at their own independent rates.
    • Pro Tip: Add more LEDs with their own intervals by adding more prev_millis_N variables and if blocks.

    Linux + MCU Bridge Programming

    The Arduino UNO Q has two processors that work together: the MPU (Qualcomm, runs Debian Linux) and the MCU (STM32, runs Zephyr OS with your Arduino sketch). They communicate using RPC via the Arduino_RouterBridge library — never via raw serial ports.

    • The LED is connected to the MCU (STM32) — wired to a digital pin on the STM32. The MCU blinks it using a non-blocking millis() loop.
    • The MPU cannot control the LED directly — it sends commands to the MCU via Bridge.call(). The MCU executes the registered Bridge.provide_safe() function and acts on the LED.
    • The MPU has Wi-Fi — it can connect to the Internet and do things the MCU cannot: receive Telegram commands, control blink speed remotely, and more.
    • Communication: Bridge.call() on the Linux side invokes Bridge.provide_safe() functions on the MCU side
    • ⚠️ Reserved: /dev/ttyHS1 (Linux) and Serial1 (MCU) are used by the Arduino Router — never open them directly

    In short: MPU sends the interval command → MCU receives it → MCU adjusts LED blink speed in real time.

    MCU sketch — non-blocking LED blink with remote speed control:

    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-blink-led-without-delay */ #include "Arduino_RouterBridge.h" #define LED_PIN 3 #define BLINK_INTERVAL_DEFAULT 1000 int led_state = LOW; unsigned long prev_millis = 0; unsigned long blink_interval = BLINK_INTERVAL_DEFAULT; bool blinking = true; void setup() { Bridge.begin(); Monitor.begin(); pinMode(LED_PIN, OUTPUT); Bridge.provide_safe("set_interval", set_interval); Bridge.provide_safe("blink_start", blink_start); Bridge.provide_safe("blink_stop", blink_stop); Monitor.println("Blink Bridge ready"); } void loop() { if (!blinking) return; unsigned long current_millis = millis(); if (current_millis - prev_millis >= blink_interval) { led_state = (led_state == LOW) ? HIGH : LOW; digitalWrite(LED_PIN, led_state); prev_millis = current_millis; } } void set_interval(int ms) { blink_interval = ms; } void blink_start() { blinking = true; } void blink_stop() { blinking = false; digitalWrite(LED_PIN, LOW); }

    Python script (Arduino App Lab) — control blink speed from Linux:

    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-blink-led-without-delay */ from arduino.app_utils import * import time def loop(): print("Setting blink interval to 200ms (fast)") Bridge.call("set_interval", 200) time.sleep(3) print("Setting blink interval to 1000ms (slow)") Bridge.call("set_interval", 1000) time.sleep(3) print("Stopping blink") Bridge.call("blink_stop") time.sleep(2) print("Starting blink again") Bridge.call("blink_start") time.sleep(3) App.run(user_loop=loop)
    • Note: Make sure Bridge.begin() is called in the MCU sketch and the sketch is uploaded before running the Python script on the Linux side.
    • ⚠️ Warning: Never directly open /dev/ttyHS1 (on Linux) or use Serial1 (on MCU) in your code — these are reserved by the Arduino Router and accessing them will break the Bridge.

    Detailed Instructions

    • Upload the MCU sketch: Open Arduino App Lab, create a new App, paste the Bridge MCU sketch above into sketch/sketch.ino, and click Run.
    • Add the Python script: Paste the Python code above into the Python tab of the same App.
    • Run the App: Click Run — the LED starts blinking. The Python side will change the speed automatically every few seconds.
    • Check the console: Open the Console tab → Python Console subtab to see speed change messages.
    • Pro Tip: Call Bridge.call("blink_stop") from Python to stop the LED, then Bridge.call("blink_start") to resume — the MCU handles it instantly.

    App Lab Console Output

    DIYables_Apps
    Stop
    sketch.ino
    1#include "Arduino_RouterBridge.h"
    Serial Monitor
    Python
    Setting blink interval to 200ms (fast) Setting blink interval to 1000ms (slow) Stopping blink Starting blink again

    Telegram Integration

    You can control the LED blink speed remotely over Telegram — send a command from anywhere and the LED responds instantly.

    If you do not have a Telegram bot yet, see How to Create a Telegram Bot to get your bot token before continuing.

    This section covers:

    • Running a Python script on the Linux side of Arduino UNO Q to listen for Telegram messages
    • Forwarding blink speed or start/stop commands to the MCU side via Bridge.call()
    • Sending a confirmation reply back to Telegram

    MCU sketch: Keep the same MCU sketch from the previous Bridge section — no changes needed. Make sure it is already uploaded and running on the STM32 before proceeding.

    Python script (Arduino App Lab) — Telegram bot for LED blink control:

    /* * This Arduino UNO Q code was developed by newbiely.com * * This Arduino UNO Q code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-uno-q/arduino-uno-q-blink-led-without-delay */ from arduino.app_utils import * import requests import time BOT_TOKEN = "YOUR_BOT_TOKEN" API_URL = f"https://api.telegram.org/bot{BOT_TOKEN}" last_update_id = 0 def send_message(chat_id, text): requests.post(f"{API_URL}/sendMessage", json={"chat_id": chat_id, "text": text}) def get_updates(): global last_update_id resp = requests.get(f"{API_URL}/getUpdates", params={"offset": last_update_id + 1, "timeout": 5}) return resp.json().get("result", []) def loop(): global last_update_id updates = get_updates() for update in updates: last_update_id = update["update_id"] msg = update.get("message", {}) chat_id = msg.get("chat", {}).get("id") text = msg.get("text", "").strip() if text.startswith("/blink "): try: ms = int(text.split()[1]) Bridge.call("set_interval", ms) Bridge.call("blink_start") send_message(chat_id, f"Blinking every {ms}ms") except ValueError: send_message(chat_id, "Usage: /blink <milliseconds>") elif text == "/stop": Bridge.call("blink_stop") send_message(chat_id, "LED stopped") elif text == "/start": Bridge.call("blink_start") send_message(chat_id, "LED blinking") else: send_message(chat_id, "Commands:\n/blink <ms> — set blink interval\n/stop — stop blinking\n/start — start blinking") time.sleep(1) App.run(user_loop=loop)
    • Note: Replace YOUR_BOT_TOKEN with the token obtained from @BotFather on Telegram.
    • Send /blink 200 to make the LED blink fast. Send /blink 2000 to blink slow.
    • Send /stop to stop blinking. Send /start to resume.

    Detailed Instructions

    • Upload the MCU sketch: Use the Bridge MCU sketch from the previous section (upload it first if not already done).
    • Paste the Telegram script: Copy the Python code above into the Python tab of your App in Arduino App Lab.
    • Set your token: Replace YOUR_BOT_TOKEN in the script with your actual bot token.
    • Run the App: Click Run — the bot starts listening for Telegram messages immediately.
    • Test it: Send /blink 100 for super-fast blinking, or /stop to freeze the LED.
    • Pro Tip: Try /blink 50 for a very fast blink that looks like a dim glow.

    App Lab Console Output

    DIYables_Apps
    Stop
    sketch.ino
    1#include "Arduino_RouterBridge.h"
    Serial Monitor
    Python
    [2026-04-29 11:00:05] Telegram: /blink 200 [2026-04-29 11:00:05] Blinking every 200ms [2026-04-29 11:03:10] Telegram: /stop [2026-04-29 11:03:10] LED stopped [2026-04-29 11:05:22] Telegram: /start [2026-04-29 11:05:22] LED blinking
    Telegram
    Telegram 12:45
    Welcome to Telegram!
    ArduinoBot 10:19
    Chatting with Arduino...
    telegram-botfather
    BotFather Yesterday
    Your bot has been created.

    ArduinoBot

    bot
    Today
    /blink 500
    10:15 AM ✓✓
    Blinking every 500ms
    10:16 AM
    /stop
    10:17 AM ✓✓
    LED stopped
    10:18 AM
    /start
    10:19 AM ✓✓
    LED blinking
    10:20 AM

    OpenClaw Integration

    OpenClaw integration for Arduino UNO Q with LED blink control is coming soon.

    • Coming Soon: OpenClaw support for controlling LED blink behavior on Arduino UNO Q will be covered in a future update.

    Application/Project Ideas

    Here are some project ideas using non-blocking LED blink on Arduino UNO Q:

    • Status indicator: Blink an LED at different speeds to indicate system states (slow = idle, fast = busy)
    • Telegram heartbeat: Blink an LED from the Python side to confirm the Linux App is running
    • Alert system: Trigger fast blinking via Telegram when a sensor threshold is exceeded on the Linux side
    • Multi-LED display: Run 4+ LEDs at independent rates to create a visual pattern or animation
    • Morse code sender: Encode a message as dots and dashes using timed millis() LED blinks

    Challenge Yourself

    Try these challenges with non-blocking LED blink and Arduino UNO Q:

    • Easy: Modify the two-LED sketch to add a third LED blinking at 250ms
    • Medium: Extend the Bridge sketch to also expose a function that returns the current blink interval so Python can read it back
    • Advanced: Build a Telegram bot that accepts a morse code string (e.g., /morse SOS) and blinks it out on the LED using the correct dot/dash timing

    ※ OUR MESSAGES

    • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
    • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!