#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h> // For binary semaphore to signal high priority task
// --- Pin Definitions ---
const int redLedPin = 7; // Red LED
const int greenLedPin = 6; // Green LED
const int yellowLedPin = 5; // Yellow LED
const int buttonPin = 8; // Push Button
// --- Task Priorities ---
// Higher number means higher priority
#define PRIORITY_RED_LED_TASK 3
#define PRIORITY_GREEN_LED_TASK 2
#define PRIORITY_YELLOW_LED_TASK 1 // Lowest priority
// --- Synchronization for Button Interrupt ---
// Binary semaphore to signal the Red LED task from the ISR
SemaphoreHandle_t xRedLedSignalSemaphore;
// --- Interrupt Service Routine (ISR) for Button ---
// This ISR will simply give a semaphore, signaling the Red LED task.
// This is the correct way to communicate from an ISR to a task.
void IRAM_ATTR buttonISR() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// Give the semaphore, waking up the Red LED task if it's waiting
xSemaphoreGiveFromISR(xRedLedSignalSemaphore, &xHigherPriorityTaskWoken);
// If giving the semaphore caused a higher priority task to become ready,
// request a context switch.
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
// --- Task 1: Red LED Task (High Priority, Event-Driven) ---
// This task waits for a signal (from the button ISR) and then performs a burst blink.
void redLedTask(void *parameter) {
pinMode(redLedPin, OUTPUT);
digitalWrite(redLedPin, LOW); // Start off
for (;;) {
// Wait indefinitely for the semaphore from the ISR
if (xSemaphoreTake(xRedLedSignalSemaphore, portMAX_DELAY) == pdTRUE) {
Serial.println(">>> Red LED Task: Signaled by button! Performing critical operation...");
// Simulate a critical, burst operation (blinking quickly)
for (int i = 0; i < 5; i++) {
digitalWrite(redLedPin, HIGH);
vTaskDelay(pdMS_TO_TICKS(50)); // Very short delay
digitalWrite(redLedPin, LOW);
vTaskDelay(pdMS_TO_TICKS(50));
}
Serial.println("<<< Red LED Task: Critical operation complete. Going to sleep.");
}
// After the burst, the task will go back to waiting for the semaphore,
// allowing lower priority tasks to run.
}
}
// --- Task 2: Green LED Task (Medium Priority, Periodic) ---
void greenLedTask(void *parameter) {
pinMode(greenLedPin, OUTPUT);
digitalWrite(greenLedPin, LOW); // Start off
const long blinkInterval = 500; // 0.5 seconds
for (;;) {
digitalWrite(greenLedPin, HIGH);
Serial.println(" Green LED Task: ON");
vTaskDelay(pdMS_TO_TICKS(blinkInterval));
digitalWrite(greenLedPin, LOW);
Serial.println(" Green LED Task: OFF");
vTaskDelay(pdMS_TO_TICKS(blinkInterval));
}
}
// --- Task 3: Yellow LED Task (Low Priority, Periodic) ---
void yellowLedTask(void *parameter) {
pinMode(yellowLedPin, OUTPUT);
digitalWrite(yellowLedPin, LOW); // Start off
const long blinkInterval = 1000; // 1 second
for (;;) {
digitalWrite(yellowLedPin, HIGH);
Serial.println(" Yellow LED Task: ON");
vTaskDelay(pdMS_TO_TICKS(blinkInterval));
digitalWrite(yellowLedPin, LOW);
Serial.println(" Yellow LED Task: OFF");
vTaskDelay(pdMS_TO_TICKS(blinkInterval));
}
}
void setup() {
Serial.begin(115200);
Serial.println("--- FreeRTOS Task Scheduling Demo ---");
// --- Initialize Pins ---
pinMode(redLedPin, OUTPUT);
pinMode(greenLedPin, OUTPUT);
pinMode(yellowLedPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP); // Use internal pull-up for the button
// --- Create Binary Semaphore for ISR to Task Communication ---
xRedLedSignalSemaphore = xSemaphoreCreateBinary();
if (xRedLedSignalSemaphore == NULL) {
Serial.println("Error: Failed to create Red LED signal semaphore!");
while (true); // Halt on error
}
// --- Attach Interrupt ---
attachInterrupt(digitalPinToInterrupt(buttonPin), buttonISR, FALLING);
// --- Create FreeRTOS Tasks ---
// xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask)
xTaskCreate(
redLedTask,
"Red_LED_Task",
2048, // Stack size
NULL, // No parameters
PRIORITY_RED_LED_TASK, // High priority
NULL // No task handle needed
);
xTaskCreate(
greenLedTask,
"Green_LED_Task",
2048, // Stack size
NULL,
PRIORITY_GREEN_LED_TASK, // Medium priority
NULL
);
xTaskCreate(
yellowLedTask,
"Yellow_LED_Task",
2048, // Stack size
NULL,
PRIORITY_YELLOW_LED_TASK, // Low priority
NULL
);
Serial.println("Tasks created. Scheduler starting...");
// The scheduler automatically starts after setup() completes if tasks are created.
}
void loop() {
// In FreeRTOS applications, loop() is often empty as tasks handle main logic.
// We add a tiny delay to yield control back to the scheduler.
// This prevents the loop from consuming 100% CPU if no other tasks are ready.
vTaskDelay(pdMS_TO_TICKS(10));
}