// Các thư viện cần thiết
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <Arduino.h>
#include "FreeRTOSConfig.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <esp_task_wdt.h>
#include <Buzzer.h>
#define CHAN_DHT22 25 // Chân dữ liệu của DHT
#define CHAN_LED_XANH 18 // Chân LED xanh
#define CHAN_LED_VANG 19 // Chân LED vàng
#define NUT_TAT 34 // Chân cho nút TẮT của LED xanh
#define NUT_BAT 35 // Chân cho nút BẬT của LED xanh
#define NUT_CAP_SEMA 32 // Chân để dùng cho nút nhấn cấp semaphore
#define DIA_CHI_I2C 0x27 // Địa chỉ của màn hình LCD
Buzzer coi_buzzer(26); // Số 26 là chân được gắn với esp32
// Khai báo LCD
LiquidCrystal_I2C LCD(0x27, 16, 2); // Đây là dòng khai báo lcd, 0x27 là địa chỉ màn hình LCD, 16 là số cột, 2 là số hàng
// Khai báo DHT22
DHT DHT_22(CHAN_DHT22, DHT22); // Khai báo DHT22, CHAN_DHT22 là số thứ tự chân gắn với esp32, DHT22 là kiểu DHT
// Biến toàn cục
float nhiet_do = 0;
float do_am = 0;
int bien_dem_semaphore = 0;
// Khai báo biến Mutex
SemaphoreHandle_t mutex_cam_bien;
// Khai báo biến Semaphore
SemaphoreHandle_t semaphore_led_vang;
// Khai báo các hàm
void doc_nhiet_do_do_am(void *);
void hien_thi_lcd(void *);
void chay_coi_buzzer(void *);
void nut_bat_tat(void *);
void cap_semaphore(void *);
void lay_bien_bao(void *);
// Khởi tạo ban đầu
void setup() {
Serial.begin(115200);
Wire.begin();
LCD.init();
LCD.backlight();
LCD.setCursor(0, 0); // đặt vị trí ban đầu cho con trỏ trong LCD
DHT_22.begin(); // khởi động DHT
esp_task_wdt_init(portMAX_DELAY, true);
// Cài đặt chức năng của các chân
pinMode(NUT_BAT, INPUT_PULLUP);
pinMode(NUT_TAT, INPUT_PULLUP);
pinMode(NUT_CAP_SEMA, INPUT_PULLUP);
pinMode(CHAN_LED_XANH, OUTPUT);
pinMode(CHAN_LED_VANG, OUTPUT);
// Tạo Mutex
mutex_cam_bien = xSemaphoreCreateMutex();
// Tạo Semaphore
semaphore_led_vang = xSemaphoreCreateCounting(5, 0); // Tạo counting semaphore, số 5 tức là cấp tối đa được 5 semaphore và số 0 là khởi tạo ban đầu bằng 0
// Tạo các Tasks
xTaskCreate(doc_nhiet_do_do_am, "nhietdodoam", 4096, NULL, 1, NULL);
xTaskCreate(hien_thi_lcd, "hienthi", 4096, NULL, 1, NULL);
xTaskCreate(nut_bat_tat, "nutonoff", 4096, NULL, 2, NULL);
xTaskCreate(chay_coi_buzzer, "buzzer", 4096, NULL, 1, NULL);
xTaskCreate(cap_semaphore, "nutsema", 1024, NULL, 1, NULL);
xTaskCreate(lay_bien_bao, "ghiSemaLed", 1024, NULL, 1, NULL);
}
void loop() {}
void doc_nhiet_do_do_am(void *) {
while (1) {
xSemaphoreTake(mutex_cam_bien, portMAX_DELAY); // Lấy mutex
nhiet_do = DHT_22.readTemperature();
do_am = DHT_22.readHumidity();
xSemaphoreGive(mutex_cam_bien); // Trả mutex
vTaskDelay(200); // Delay 0.2s
}
}
void hien_thi_lcd(void *) {
while (1) {
xSemaphoreTake(mutex_cam_bien, portMAX_DELAY); // Lấy mutex
LCD.setCursor(0, 0);
LCD.printf("Nhiet do: %.1fC", nhiet_do);
LCD.setCursor(0, 1);
LCD.printf("Do am :%.2f%%", do_am);
xSemaphoreGive(mutex_cam_bien); // Trả mutex
vTaskDelay(100); // Delay 0.1s
}
}
void nut_bat_tat(void *) {
while (1) {
static int gia_tri_nut_bat_truoc = 0;
static int gia_tri_nut_tat_truoc = 0;
int gia_tri_nut_bat = digitalRead(NUT_BAT);
int gia_tri_nut_tat = digitalRead(NUT_TAT);
if (gia_tri_nut_bat == LOW && gia_tri_nut_bat_truoc == HIGH) {
digitalWrite(CHAN_LED_XANH, HIGH); // Bật LED xanh
}
if (gia_tri_nut_tat == LOW && gia_tri_nut_tat_truoc == HIGH) {
digitalWrite(CHAN_LED_XANH, LOW); // Tắt LED xanh
}
gia_tri_nut_bat_truoc = gia_tri_nut_bat; // Lưu trạng thái mới cho lần sau
gia_tri_nut_tat_truoc = gia_tri_nut_tat; // Lưu trạng thái mới cho lần sau
vTaskDelay(20); // Delay 0.2s
}
}
void cap_semaphore(void *) {
while (1) {
int gia_tri_nut_semaphore = digitalRead(NUT_CAP_SEMA); // khai báo biến gia_tri_nut_semaphore đọc trạng thái của NUT_CAP_SEMA
static int gia_tri_nut_semaphore_truoc = 0; // Khai báo 1 biến tĩnh gia_tri_nut_semaphore_truoc = 0
// Kiểm tra trạng thái gia_tri_nut_semaphore và gia_tri_nut_semaphore_truoc để thực hiện nhiệm vụ
if (gia_tri_nut_semaphore == LOW && gia_tri_nut_semaphore_truoc == HIGH) {
xSemaphoreGive(semaphore_led_vang); // cấp semaphore
bien_dem_semaphore += 1; // tăng biến đếm lên 1
}
gia_tri_nut_semaphore_truoc = gia_tri_nut_semaphore; // lưu trạng thái hiện tại vào biến gia_tri_nut_semaphore_truoc
vTaskDelay(20); // Delay 0.2s
}
}
void lay_bien_bao(void *) {
while (1) {
// Kiểm tra xem có semaphore để lấy hay không và biến bien_dem_semaphore <= 5 hay không
if (xSemaphoreTake(semaphore_led_vang, portMAX_DELAY) == pdTRUE && bien_dem_semaphore <= 5) {
// Vòng lặp để chóp tắt led 3 lần
for (int i = 0; i < 3; i++) {
digitalWrite(CHAN_LED_VANG, HIGH);
delay(500);
digitalWrite(CHAN_LED_VANG, LOW);
delay(500);
}
}
}
vTaskDelay(20);
}
void chay_coi_buzzer(void *) {
while (1) {
coi_buzzer.begin(10); // khởi động buzzer
// Nốt nhạc và thời gian phát
coi_buzzer.sound(NOTE_C5, 80);
coi_buzzer.sound(NOTE_F5, 80);
coi_buzzer.sound(0, 40);
coi_buzzer.sound(NOTE_F5, 160);
coi_buzzer.sound(0, 40);
coi_buzzer.sound(NOTE_G5, 160);
coi_buzzer.sound(NOTE_F5, 160);
coi_buzzer.sound(NOTE_E5, 160);
coi_buzzer.sound(NOTE_D5, 80);
coi_buzzer.sound(0, 40);
coi_buzzer.sound(NOTE_D5, 80);
coi_buzzer.sound(0, 100);
coi_buzzer.sound(NOTE_D5, 80);
coi_buzzer.sound(NOTE_G5, 80);
coi_buzzer.sound(0, 40);
coi_buzzer.sound(NOTE_G5, 160);
coi_buzzer.sound(0, 40);
coi_buzzer.sound(NOTE_A5, 160);
coi_buzzer.sound(NOTE_G5, 160);
coi_buzzer.sound(NOTE_F5, 160);
coi_buzzer.sound(NOTE_E5, 80);
coi_buzzer.sound(NOTE_C5, 80);
coi_buzzer.sound(0, 100);
coi_buzzer.sound(NOTE_C5, 80);
coi_buzzer.sound(NOTE_A5, 80);
coi_buzzer.sound(0, 40);
coi_buzzer.sound(NOTE_A5, 160);
coi_buzzer.sound(0, 40);
coi_buzzer.sound(NOTE_AS5, 160);
coi_buzzer.sound(NOTE_A5, 160);
coi_buzzer.sound(NOTE_G5, 160);
coi_buzzer.sound(NOTE_F5, 80);
coi_buzzer.sound(NOTE_D5, 80);
coi_buzzer.sound(0, 100);
coi_buzzer.sound(NOTE_C5, 160);
coi_buzzer.sound(0, 30);
coi_buzzer.sound(NOTE_C5, 160);
coi_buzzer.sound(0, 40);
coi_buzzer.sound(NOTE_D5, 80);
coi_buzzer.sound(NOTE_G5, 80);
coi_buzzer.sound(NOTE_E5, 80);
coi_buzzer.sound(NOTE_F5, 80);
coi_buzzer.end(1000);
}
}