This project simulates a parking lot system on an Arduino UNO using FreeRTOS counting semaphores.
It demonstrates how multiple tasks can safely share a limited resource—parking spaces—without race conditions or conflicts.
Each car is represented by a FreeRTOS task that must acquire a semaphore before parking and release it when exiting.
Project OverviewIn real-time systems, resources are often limited. FreeRTOS counting semaphores provide a clean solution to control how many tasks can access a resource simultaneously.
In this project:
- Parking spaces are limited to two
- Multiple “car” tasks attempt to park
- Tasks block automatically when no space is available
- A manual override button can free a space
Semaphore support is enabled with:
#include <Arduino_FreeRTOS.h>
#include <semphr.h>Hardware Setup✅ The exit button uses INPUT_PULLUP (pressed = LOW).
Semaphore Design- Type: Counting Semaphore
- Max Count: 2 (number of parking spaces)
- Initial Count: 2
🧠 Conceptual Model:
The semaphore acts like a parking ticket dispenser.
A car must take a ticket (semaphore) to park.
If no ticket is available, the car waits.
Car Task Behavior
Car Task 1
This task attempts to park, occupies a slot, waits, and then exits.
void CarTask1(void *pvParameters) {
while (1) {
if (xSemaphoreTake(xParkingSemaphore, portMAX_DELAY) == pdTRUE) {
digitalWrite(parkingLEDs[0], HIGH);
digitalWrite(ENTRY_GATE_LED, HIGH);
vTaskDelay(pdMS_TO_TICKS(200));
digitalWrite(ENTRY_GATE_LED, LOW);
Serial.print("Car 1: Parked. Spaces left: ");
Serial.println(uxSemaphoreGetCount(xParkingSemaphore));
vTaskDelay(pdMS_TO_TICKS(3000));
digitalWrite(parkingLEDs[0], LOW);
digitalWrite(EXIT_GATE_LED, HIGH);
vTaskDelay(pdMS_TO_TICKS(200));
digitalWrite(EXIT_GATE_LED, LOW);
xSemaphoreGive(xParkingSemaphore);
Serial.println("Car 1: Left parking");
}
}
}Car Task 2
Similar to Car 1, but starts slightly later to show task staggering.
void CarTask2(void *pvParameters) {
vTaskDelay(pdMS_TO_TICKS(1000)); // Stagger start
while (1) {
if (xSemaphoreTake(xParkingSemaphore, portMAX_DELAY) == pdTRUE) {
digitalWrite(parkingLEDs[1], HIGH);
vTaskDelay(pdMS_TO_TICKS(4000)); // Simulate parking time
digitalWrite(parkingLEDs[1], LOW);
xSemaphoreGive(xParkingSemaphore);
Serial.println("Car 2: Left parking");
}
}
}Manual Exit Override Task
This task monitors a button and forces a parking space to be released if pressed.
void ExitButtonTask(void *pvParameters) {
while (1) {
if (digitalRead(EXIT_BUTTON) == LOW) {
if (uxSemaphoreGetCount(xParkingSemaphore) < TOTAL_PARKING_SPACES) {
xSemaphoreGive(xParkingSemaphore);
digitalWrite(OVERRIDE_LED, HIGH);
Serial.println("Override: Manual exit triggered");
vTaskDelay(pdMS_TO_TICKS(500));
digitalWrite(OVERRIDE_LED, LOW);
}
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}Task Creation and Scheduler Control
All tasks and the counting semaphore are created in setup().
xParkingSemaphore = xSemaphoreCreateCounting(
TOTAL_PARKING_SPACES,
TOTAL_PARKING_SPACES
);
xTaskCreate(CarTask1, "Car1", 128, NULL, 1, NULL);
xTaskCreate(CarTask2, "Car2", 128, NULL, 1, NULL);
xTaskCreate(ExitButtonTask, "Exit", 128, NULL, 2, NULL);The loop()
function remains empty because FreeRTOS manages execution:
void loop() {}LED Behavior Summary- Counting semaphores manage limited resources
- Tasks automatically block when resources are unavailable
- Semaphore count directly represents system capacity
- Manual overrides can safely interact with semaphore logic
- Understand counting vs binary semaphores
- Learn how task blocking works in FreeRTOS
- Design scalable systems with shared resource limits
This project provides a clear, real-world visualization of counting semaphores, a critical concept in professional real-time embedded systems design.
That's all!If you have any questions or suggestions, don’t hesitate to leave a comment below.


_ztBMuBhMHo.jpg?auto=compress%2Cformat&w=48&h=48&fit=fill&bg=ffffff)

Comments