I gave it a try and wrote the code it’s working for me I don’t see any issues so far. I used this link/reference [ https://www.freertos.org/Documentation/02-Kernel/04-API-references/10-Semaphore-and-Mutexes/12-xSemaphoreTake ] as a starting point and also checked a few other resources online to make sure I understood the semaphore and FreeRTOS task flow correctly.
#include <Arduino.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
// NS traffic light pins
const int R1_pin = 15;
const int G1_pin = 2;
const int Y1_pin = 4;
// EW traffic light pins
const int R2_pin = 18;
const int G2_pin = 19;
const int Y2_pin = 21;
// Binary semaphore ensures only one direction can be active at a time
SemaphoreHandle_t trafficSemaphore;
// functions: separate "what each light state means"
void NS_Green() {
digitalWrite(G1_pin, HIGH);
digitalWrite(Y1_pin, LOW);
digitalWrite(R1_pin, LOW);
}
void NS_Yellow() {
digitalWrite(G1_pin, LOW);
digitalWrite(Y1_pin, HIGH);
digitalWrite(R1_pin, LOW);
}
void NS_Red() {
digitalWrite(G1_pin, LOW);
digitalWrite(Y1_pin, LOW);
digitalWrite(R1_pin, HIGH);
}
void EW_Green() {
digitalWrite(G2_pin, HIGH);
digitalWrite(Y2_pin, LOW);
digitalWrite(R2_pin, LOW);
}
void EW_Yellow() {
digitalWrite(G2_pin, LOW);
digitalWrite(Y2_pin, HIGH);
digitalWrite(R2_pin, LOW);
}
void EW_Red() {
digitalWrite(G2_pin, LOW);
digitalWrite(Y2_pin, LOW);
digitalWrite(R2_pin, HIGH);
}
// NS Task: acquires semaphore before turning Green, releases after complete cycle
void NS_Task(void *pvParameters) {
while (1) {
// Ensure NS does not conflict with EW: only proceed when semaphore is available
if (xSemaphoreTake(trafficSemaphore, portMAX_DELAY) == pdTRUE) {
NS_Green(); // NS goes Green because it acquired semaphore
vTaskDelay(pdMS_TO_TICKS(50000)); // stay Green for 50 seconds per traffic rules
NS_Yellow(); // Transition to Yellow: warning phase
vTaskDelay(pdMS_TO_TICKS(10000)); // stay Yellow for 10 seconds
NS_Red(); // NS goes Red: now safe for EW to go Green
// Release semaphore for EW: only after NS completed full cycle
xSemaphoreGive(trafficSemaphore);
}
}
}
// EW Task: symmetric logic to NS Task
void EW_Task(void *pvParameters) {
while (1) {
// Ensure EW does not conflict with NS: only proceed when semaphore is available
if (xSemaphoreTake(trafficSemaphore, portMAX_DELAY) == pdTRUE) {
EW_Green(); // EW goes Green after acquiring semaphore
vTaskDelay(pdMS_TO_TICKS(50000)); // Maintain Green for 50 seconds
EW_Yellow(); // Transition to Yellow
vTaskDelay(pdMS_TO_TICKS(10000)); // Maintain Yellow for 10 seconds
EW_Red(); // EW goes Red: handover back to NS
// Release semaphore for NS
xSemaphoreGive(trafficSemaphore);
}
}
}
void setup() {
// Initialize all traffic light pins as outputs
pinMode(R1_pin, OUTPUT); pinMode(G1_pin, OUTPUT); pinMode(Y1_pin, OUTPUT);
pinMode(R2_pin, OUTPUT); pinMode(G2_pin, OUTPUT); pinMode(Y2_pin, OUTPUT);
// Start both directions Red initially: safe default state
NS_Red();
EW_Red();
// Create binary semaphore: initially available to whichever task runs first
trafficSemaphore = xSemaphoreCreateBinary();
xSemaphoreGive(trafficSemaphore);
// Create FreeRTOS tasks with equal priority
xTaskCreate(NS_Task, "NS_Task", 2048, NULL, 1, NULL);
xTaskCreate(EW_Task, "EW_Task", 2048, NULL, 1, NULL);
}
void loop() {
// Empty because FreeRTOS tasks control all traffic light behavior.
// loop() is not needed; the scheduler manages task execution.
}