#include <Arduino.h>
#include <LiquidCrystal.h>
#include <Arduino_FreeRTOS.h>
#include <semphr.h>
// LCD pins (adapt to your wiring)
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
// LEDs
#define LED1 2
#define LED2 3
// Buttons
#define BTN_TOGGLE 4
#define BTN_INC 5
#define BTN_DEC 6
// ---------------- Global Variables ----------------
// Global variable used for LED1 state, updated by
// ButtonLedTask and read by ReportTask.
volatile bool led1State = false;
// Global variable used to store blinking delay time
// in milliseconds, modified by ControlTask.
volatile int blinkDelay = 500;
// Global variable used as a signal when a button
// event occurs, consumed by ReportTask.
volatile bool buttonEvent = false;
// Global semaphore used for provider/consumer
// synchronization between tasks.
SemaphoreHandle_t xSemaphore;
// ---------------- TASK 1 ----------------
// Toggle LED1 state when button is pressed.
void ButtonLedTask(void *pvParameters) {
(void) pvParameters;
for (;;) {
if (digitalRead(BTN_TOGGLE) == LOW) {
led1State = !led1State;
digitalWrite(LED1, led1State);
buttonEvent = true;
xSemaphoreGive(xSemaphore);
vTaskDelay(pdMS_TO_TICKS(300)); // debounce
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
// ---------------- TASK 2 ----------------
// Blink LED2 only when LED1 is turned off.
void LedBlinkTask(void *pvParameters) {
(void) pvParameters;
for (;;) {
if (!led1State) {
digitalWrite(LED2, HIGH);
vTaskDelay(pdMS_TO_TICKS(blinkDelay));
digitalWrite(LED2, LOW);
vTaskDelay(pdMS_TO_TICKS(blinkDelay));
} else {
digitalWrite(LED2, LOW);
vTaskDelay(pdMS_TO_TICKS(200));
}
}
}
// ---------------- TASK 3 ----------------
// Increase or decrease blinking delay with buttons.
void ControlTask(void *pvParameters) {
(void) pvParameters;
for (;;) {
if (digitalRead(BTN_INC) == LOW) {
blinkDelay += 100;
if (blinkDelay > 2000) {
blinkDelay = 2000;
}
buttonEvent = true;
xSemaphoreGive(xSemaphore);
vTaskDelay(pdMS_TO_TICKS(300));
}
if (digitalRead(BTN_DEC) == LOW) {
blinkDelay -= 100;
if (blinkDelay < 100) {
blinkDelay = 100;
}
buttonEvent = true;
xSemaphoreGive(xSemaphore);
vTaskDelay(pdMS_TO_TICKS(300));
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
// ---------------- TASK 4 ----------------
// Report current system state to LCD and Serial.
void ReportTask(void *pvParameters) {
(void) pvParameters;
for (;;) {
if (xSemaphoreTake(xSemaphore, portMAX_DELAY)
== pdTRUE) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("LED1: ");
lcd.print(led1State ? "ON " : "OFF");
lcd.setCursor(0, 1);
lcd.print("BlinkDelay:");
lcd.print(blinkDelay);
if (buttonEvent) {
Serial.println("Button pressed -> event logged!");
buttonEvent = false;
}
}
vTaskDelay(pdMS_TO_TICKS(200));
}
}
// ---------------- SETUP ----------------
void setup(void) {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(BTN_TOGGLE, INPUT_PULLUP);
pinMode(BTN_INC, INPUT_PULLUP);
pinMode(BTN_DEC, INPUT_PULLUP);
Serial.begin(9600);
lcd.begin(16, 2);
xSemaphore = xSemaphoreCreateBinary();
xTaskCreate(ButtonLedTask, "BtnLED", 128, NULL, 1, NULL);
xTaskCreate(LedBlinkTask, "LedBlink", 128, NULL, 1, NULL);
xTaskCreate(ControlTask, "Control", 128, NULL, 1, NULL);
xTaskCreate(ReportTask, "Report", 256, NULL, 1, NULL);
vTaskStartScheduler();
}
// ---------------- LOOP ----------------
void loop(void) {
// Not used in FreeRTOS applications.
}