My first embedded project was simple: read a temperature sensor every second and display it on an LCD. A basic while loop worked perfectly.
Then the project grew. I needed to read the sensor every second, update the display, check for button presses, communicate over WiFi, and log data to an SD card. Suddenly the while loop was a mess of timing calculations and everything was interfering with everything else.
That is when I learned about RTOS.
What is an RTOS?
An RTOS (Real-Time Operating System) is a tiny operating system designed for microcontrollers. Unlike Windows or Linux, it is not for running apps. It does one thing: let you run multiple tasks at the same time with precise timing control.
The "real-time" part means it can guarantee that a task will run within a specific time window. If a sensor needs to be read every 100 milliseconds, an RTOS can guarantee that happens — even if other tasks are running.
The core concept: tasks
In an RTOS, you split your program into tasks. Each task is a function that runs independently, like a mini-program. Each task has its own priority.
// Task 1: Read sensor every 100ms
void vSensorTask(void *pvParameters) {
for (;;) {
float temp = ReadTemperature();
xQueueSend(xTempQueue, &temp, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(100)); // wait 100ms
}
}
// Task 2: Update display every 500ms
void vDisplayTask(void *pvParameters) {
float temp;
for (;;) {
if (xQueueReceive(xTempQueue, &temp, portMAX_DELAY)) {
UpdateDisplay(temp);
}
}
}
// In main, create the tasks
xTaskCreate(vSensorTask, "Sensor", 256, NULL, 2, NULL);
xTaskCreate(vDisplayTask, "Display", 512, NULL, 1, NULL);
vTaskStartScheduler();The RTOS scheduler runs the highest-priority task that is ready. When a task calls vTaskDelay(), it goes to sleep and the scheduler runs another task. This is how multiple things happen "at the same time" on a single-core processor.
Queues: how tasks share data safely
Tasks need to share data. But if two tasks access the same variable at the same time, you get corrupted data. Queues solve this:
// Sensor task sends data
xQueueSend(xTempQueue, &temperature, portMAX_DELAY);
// Display task receives data
float temp;
xQueueReceive(xTempQueue, &temp, portMAX_DELAY);Queues are thread-safe. The RTOS handles the synchronization for you.
FreeRTOS: the one everyone uses
FreeRTOS is the most popular RTOS for microcontrollers. It is free, open-source, and runs on hundreds of different chips. The ESP32 (used in most WiFi IoT projects) runs FreeRTOS by default. STM32, NXP, and most other ARM chips support it.
Do you actually need an RTOS?
Not always. For simple projects, a well-structured while loop is easier to understand and debug. An RTOS adds complexity.
You need an RTOS when:
- You have multiple independent tasks with different timing requirements
- You need to guarantee response times
- Your while loop has become too complex to manage
For a simple sensor that reads data and sends it over serial, a while loop is fine. For a device that reads sensors, manages a display, handles user input, and communicates over WiFi simultaneously — use an RTOS.




