#include <Arduino_FreeRTOS.
h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <queue.h> // thêm để dùng Queue
// LCD I2C
LiquidCrystal_I2C lcd(0x27, 16, 2);
// DS18B20
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Relay
#define RELAY_FAN 3
#define RELAY_LIGHT 4
// Cấu trúc lưu trạng thái relay
struct RelayState {
bool fan;
bool light;
};
volatile RelayState relayState = {false, false}; // giá trị logic mong muốn
// Queue lưu nhiệt độ
QueueHandle_t tempQueue;
// Handle cho các task
TaskHandle_t readTaskHandle = NULL;
TaskHandle_t lcdTaskHandle = NULL;
TaskHandle_t uartTaskHandle = NULL;
TaskHandle_t relayTaskHandle = NULL;
// Prototype các task
void taskReadTemperature(void *pvParameters);
void taskDisplayLCD(void *pvParameters);
void taskUARTComm(void *pvParameters);
void taskRelayControl(void *pvParameters);
void setup() {
Serial.begin(9600);
sensors.begin();
pinMode(RELAY_FAN, OUTPUT);
pinMode(RELAY_LIGHT, OUTPUT);
digitalWrite(RELAY_FAN, LOW);
digitalWrite(RELAY_LIGHT, LOW);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("System Boot...");
// Tạo queue chứa nhiệt độ (kiểu float)
tempQueue = xQueueCreate(1, sizeof(float));
// Tạo task
xTaskCreate(taskReadTemperature, "ReadTemp", 96, NULL, 3, &readTaskHandle);
xTaskCreate(taskDisplayLCD, "DisplayLCD", 96, NULL, 1, &lcdTaskHandle);
xTaskCreate(taskUARTComm, "UARTComm", 96, NULL, 2, &uartTaskHandle);
xTaskCreate(taskRelayControl, "RelayCtrl", 96, NULL, 2, &relayTaskHandle);
}
void loop() {
// FreeRTOS không dùng loop
}
// ===== Task đọc nhiệt độ =====
void taskReadTemperature(void *pvParameters) {
float temp = 0.0;
while (1) {
sensors.requestTemperatures();
temp = sensors.getTempCByIndex(0);
xQueueOverwrite(tempQueue, &temp);
// Gửi notify để kích hoạt task LCD
xTaskNotifyGive(lcdTaskHandle);
// Dừng chờ đến khi task relay thông báo xong
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// ===== Task hiển thị LCD =====
void taskDisplayLCD(void *pvParameters) {
float temp = 0.0;
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
xQueuePeek(tempQueue, &temp, 0);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temp, 1);
lcd.print(" C");
lcd.setCursor(0, 1);
lcd.print("F:");
lcd.print(relayState.fan ? "ON " : "OFF");
lcd.print(" L:");
lcd.print(relayState.light ? "ON" : "OFF");
xTaskNotifyGive(uartTaskHandle);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
}
// ===== Task UART gửi / nhận =====
void taskUARTComm(void *pvParameters) {
float temp = 0.0;
String input = "";
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
xQueuePeek(tempQueue, &temp, 0);
// Gửi dữ liệu qua UART
Serial.print("Temp:");
Serial.println(temp);
Serial.print("FAN:");
Serial.println(relayState.fan ? 1 : 0);
Serial.print("LIGHT:");
Serial.println(relayState.light ? 1 : 0);
// Nhận lệnh UART
while (Serial.available()) {
char ch = Serial.read();
if (ch == '\n') {
input.trim();
if (input.startsWith("FAN:")) {
relayState.fan = input.endsWith("1");
} else if (input.startsWith("LIGHT:")) {
relayState.light = input.endsWith("1");
}
input = "";
} else {
input += ch;
}
}
xTaskNotifyGive(relayTaskHandle);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
}
// ===== Task điều khiển Relay =====
void taskRelayControl(void *pvParameters) {
float temp = 0.0;
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
xQueuePeek(tempQueue, &temp, 0);
// Quyết định fan dựa trên nhiệt độ hoặc lệnh
bool fanControl = relayState.fan;
if (temp > 30.0) fanControl = true;
bool lightControl = relayState.light;
// Chỉ cập nhật relay khi có thay đổi
if (digitalRead(RELAY_FAN) != (fanControl ? HIGH : LOW)) {
digitalWrite(RELAY_FAN, fanControl ? HIGH : LOW);
}
if (digitalRead(RELAY_LIGHT) != (lightControl ? HIGH : LOW)) {
digitalWrite(RELAY_LIGHT, lightControl ? HIGH : LOW);
}
// Cập nhật trạng thái thật sự
relayState.fan = fanControl;
relayState.light = lightControl;
// Quay lại task đọc
xTaskNotifyGive(readTaskHandle);
}
}