#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <Arduino_FreeRTOS.h>
#include <task.h>
#include <semphr.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const uint8_t LED_R_PIN = PB5; // Red LED pin for manual mode
const uint8_t LED_G_PIN = PB4; // Green LED pin for automatic mode
const uint8_t BUTTON_PIN = PD2; // Button pin for toggling modes
const uint8_t PIR_PIN = PD0; // PIR motion sensor pin for motion detection
const uint8_t SWITCH_PIN = PD6; // Switch pin for manual mode control
const uint8_t LCD_ADDR = 0x27; // I2C address of the LCD
const uint8_t LCD_COLS = 16; // Number of LCD columns
const uint8_t LCD_ROWS = 2; // Number of LCD rows
volatile bool manualMode = true;
SemaphoreHandle_t xMutexLCD;
QueueHandle_t xButtonQueue;
LiquidCrystal_I2C lcd(LCD_ADDR, LCD_COLS, LCD_ROWS);
ISR(INT0_vect) {
// Minimal ISR; processing is handled in tasks
}
void setup() {
DDRB |= (1 << LED_R_PIN) | (1 << LED_G_PIN);
PORTB &= ~((1 << LED_R_PIN) | (1 << LED_G_PIN));
DDRD &= ~((1 << BUTTON_PIN) | (1 << PIR_PIN) | (1 << SWITCH_PIN));
PORTD |= (1 << BUTTON_PIN) | (1 << PIR_PIN) | (1 << SWITCH_PIN);
EICRA |= (1 << ISC01);
EIMSK |= (1 << INT0);
sei();
lcd.begin(LCD_COLS, LCD_ROWS);
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Manual Mode");
xMutexLCD = xSemaphoreCreateMutex();
if (xMutexLCD == NULL) {
while (1);
}
// Create Queue for Button Events
xButtonQueue = xQueueCreate(5, sizeof(bool));
if (xButtonQueue == NULL) {
while (1);
}
xTaskCreate(vModeManagerTask, "Mode Manager", 128, NULL, 2, NULL);
xTaskCreate(vLEDControlTask, "LED Control", 128, NULL, 1, NULL);
xTaskCreate(vButtonHandlerTask, "Button Handler", 128, NULL, 3, NULL);
}
void loop() {//The Arduino loop is unused as FreeRTOS manages task scheduling.
}
void vModeManagerTask(void *pvParameters) {
bool buttonEvent;
while (1) {
if (xQueueReceive(xButtonQueue, &buttonEvent, portMAX_DELAY) == pdTRUE) {
manualMode = !manualMode; // Toggle mode
if (xSemaphoreTake(xMutexLCD, portMAX_DELAY)) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(manualMode ? "Manual Mode" : "Automatic Mode");
xSemaphoreGive(xMutexLCD);
}
}
}
}
void vLEDControlTask(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();
while (1) {
if (manualMode) {
PORTB |= (1 << LED_R_PIN);
if (PIND & (1 << SWITCH_PIN)) {
PORTB |= (1 << LED_G_PIN);
} else {
PORTB &= ~(1 << LED_G_PIN);
}
} else {
PORTB &= ~(1 << LED_R_PIN);
if (PIND & (1 << PIR_PIN)) {
PORTB |= (1 << LED_G_PIN);
} else {
PORTB &= ~(1 << LED_G_PIN);
}
}
vTaskDelayUntil(&xLastWakeTime, 50 / portTICK_PERIOD_MS);
}
}
void vButtonHandlerTask(void *pvParameters) {
bool buttonEvent = true;
while (1) {
if (!(PIND & (1 << BUTTON_PIN))) {
_delay_ms(20);
if (!(PIND & (1 << BUTTON_PIN))) {
xQueueSend(xButtonQueue, &buttonEvent, portMAX_DELAY);
while (!(PIND & (1 << BUTTON_PIN)));
}
}
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}