#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <esp_task_wdt.h>
#include <BH1750.h>
/* Gán chân */
#define DHT11_PIN 19 // Chân đọc giá trị DHT là 19
#define YELLOW_LED_PIN 33 // Chân điều khiển LED vàng là 33
#define WHITE_LED_PIN 32 // Chân điều khiển LED trắng là 32
#define BUTTON_ON 26 // Chân 26 lấy tín hiệu nút ON
#define BUTTON_OFF 25 // Chân 25 lấy tín hiệu nút OFF
#define BUTTON_SEMA 27 // Chân 27 lấy tín hiệu cấp SEMA
#define BUZZER_PIN 23 // Chân 23 điều khiển Buzzer
#define I2C_ADDR 0x27 // Địa chỉ của màn hình LCD I2C
#define LCD_COLS 16 // Số cột của màn hình LCD
#define LCD_ROWS 2 // Số hàng của màn hình LCD
/* Cảm biến ánh sáng */
BH1750 lightSensor;
/* LCD */
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLS, LCD_ROWS);
/* DHT22 */
DHT dht(DHT11_PIN, DHT11);
/* Biến toàn cục */
int temperature = 0; // biến lưu nhiệt độ
int humidity = 0; // biến lưu độ ẩm
float lightStrength = 0; // biến lưu ánh sáng
SemaphoreHandle_t sensorMutex; // Tạo biến Mutex
SemaphoreHandle_t countingSemaLed5; // Tạo biến Semaphore đếm
/* Task Functions */
void getTemperatureAndHumidity(void *); // Đọc giá trị DHT
void displayLCD(void *); // Hiển thị trên LCD
void getLight(void *); // Đọc giá trị cảm biến ánh sáng
void readOnOffButton(void *); // Đọc tín hiệu từ nút ON, OFF
void readSemaButton(void *); // Đọc tín hiệu nút SEMA
void writeSemaLed(void *); // Xuất tín hiệu từ nút SEMA ra LED
void buzzerControl(void *); // Buzzer chạy thụ động
void setup() {
Serial.begin(115200); // Khởi tạo Serial với baund rate 115200
Wire.begin(); // Khởi tạo thư viện Wire để giao tiếp I2C
Serial.println("Khoi Tao Cam Bien");
lightSensor.begin(); // Khởi tạo cảm biến ánh sáng
lcd.init(); // Khởi tạo LCD
lcd.backlight(); // Đảm bảo đèn nền LCD được bật
lcd.setCursor(0, 0); // Con trỏ LCD ở hàng 0 cột 0
dht.begin(); // Khởi tọa cảm biến DHT
/* Khởi tạo bộ watchdog timer giúp hệ thống không bị treo */
esp_task_wdt_init(portMAX_DELAY, true); // Watchdog timer sẽ được chạy gần như mãi mãi, có nghĩa là hệ thống sẽ không bị time out
/* Thiết lập chế độ chân */
pinMode(BUTTON_ON, INPUT_PULLUP);
pinMode(BUTTON_OFF, INPUT_PULLUP);
pinMode(BUTTON_SEMA, INPUT_PULLUP);
pinMode(YELLOW_LED_PIN, OUTPUT);
pinMode(WHITE_LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
Serial.println("Khoi Tao thanh cong");
/* Mutex */
sensorMutex = xSemaphoreCreateMutex(); // Tạo Mutex, khởi tạo sensorMutex = 1
/* Semaphore */
countingSemaLed5 = xSemaphoreCreateCounting(5, 0); // Tạo Semaphore đếm được tối đa 5, khởi tạo countingSemaLed = 0
/* tạo RTOS Tasks */
/* xTaskCreate( TaskFunction_t pvTaskCode, // Hàm thực hiện nhiệm vụ
const char * const pcName, // Tên của task
unsigned short usStackDepth, // Kích thước stack
void *pvParameters, // Tham số truyền vào task
UBaseType_t uxPriority, // Độ ưu tiên của task
TaskHandle_t *pxCreatedTask ); // Handle của task
*/
xTaskCreate(getTemperatureAndHumidity, "nhietdodoam", 4096, NULL, 5, NULL);
xTaskCreate(displayLCD, "hienthi", 4096, NULL, 6, NULL);
xTaskCreate(readOnOffButton, "nutonoff", 4096, NULL, 7, NULL);
xTaskCreate(getLight, "light", 4096, NULL, 7, NULL);
xTaskCreate(readSemaButton, "nutsema", 1024, NULL, 5, NULL);
xTaskCreate(writeSemaLed, "ghiSemaLed", 1024, NULL, 5, NULL);
xTaskCreate(buzzerControl, "buzzer", 1024, NULL, 5, NULL);
}
void loop() {}
/* Đọc giá trị DHT */
void getTemperatureAndHumidity(void *) {
while (1) {
int tem = dht.readTemperature(); // Đọc giá trị nhiệt độ vào biến cục bộ tem
int hum = dht.readHumidity(); // Đọc giá trị độ ẩm vào biến cục bộ
xSemaphoreTake(sensorMutex, portMAX_DELAY); // Chờ sensorMutex = 1 gần như mãi mãi, sau đó sensorMutex = 0
temperature = tem; // lưu nhiệt độ vào biến toàn cục
humidity = hum; // lưu độ ẩm vào biến toàn cục
xSemaphoreGive(sensorMutex); // Trả lại sensorMutex = 1
delay(500); // Dừng 500ms rồi mới lặp
}
}
/* Hiển thị trên LCD */
void displayLCD(void *) {
while (1) {
xSemaphoreTake(sensorMutex, portMAX_DELAY); // Chờ sensorMutex = 1 gần như mãi mãi, sau đó sensorMutex = 0
lcd.setCursor(0, 0); // Con trỏ LCD ở hàng 0 cột 0
lcd.printf("Nhiet:%2dC Am:%2d%%", temperature,humidity); // Hiển thị Nhiet:<giá trị nhiệt độ>C, Am:<giá trị độ ẩm>%
lcd.setCursor(0, 1); // Con trỏ LCD ở hàng 1 cột 0
lcd.printf("Anh sang:%05dlx",(int)lightStrength); // Hiển thị Anh sang:<giá trị cường độ ánh sáng>lx
xSemaphoreGive(sensorMutex); // Trả lại sensorMutex = 1
delay(100);
}
}
/* Đọc tín hiệu từ nút ON, OFF */
void readOnOffButton(void *) {
while (1) {
static int prevOnValue = 0; // Tạo biến lưu trữ trạng thái trước đó của nút ON
static int prevOffValue = 0; // Tạo biến lưu trữ trạng thái trước đó của nút OFF
int onValue = digitalRead(BUTTON_ON); // Tạo biến đọc giá trị hiện tại của nút ON
int offValue = digitalRead(BUTTON_OFF); // Tạo biến đọc giá trị hiện tại của nút OFF
/* Kiểm tra xem nút ON có được nhấn không */
if (onValue == LOW && prevOnValue == HIGH) {
digitalWrite(YELLOW_LED_PIN, HIGH); // Nếu nút ON được nhấn, điều khiển đèn LED màu vàng bật
}
/* Kiểm tra xem nút OFF có được nhấn không */
if (offValue == LOW && prevOffValue == HIGH) {
digitalWrite(YELLOW_LED_PIN, LOW); // Nếu nút OFF được nhấn, điều khiển đèn LED màu vàng tắt
}
prevOnValue = onValue; // Lưu trạng thái hiện tại của nút ON để dùng trong vòng lặp tiếp theo
prevOffValue = offValue; // Lưu trạng thái hiện tại của nút OFF để dùng trong vòng lặp tiếp theo
delay(10);
}
}
/* Đọc giá trị cảm biến ánh sáng */
void getLight(void *) {
while (1) {
xSemaphoreTake(sensorMutex, portMAX_DELAY); // Chờ sensorMutex = 1 gần như mãi mãi, sau đó sensorMutex = 0
float lightData = lightSensor.readLightLevel(); // Đọc giá trị cường độ ánh sáng
lightStrength = lightData; // Lưu giá trị cường độ ánh sáng vào biến lightStrength
xSemaphoreGive(sensorMutex); // Trả lại sensorMutex = 1
delay(100);
}
}
/* Đọc tín hiệu nút SEMA */
void readSemaButton(void *) {
while (1) {
int buttonValue = digitalRead(BUTTON_SEMA); // Đọc tín hiệu só lưu vào biến buttonValue
static int prevButtonValue = 0; // Tạo biến đọc giá trị trước đó của nút SEMA
/* Kiểm tra xem nút OFF có được nhấn không */
if (buttonValue == LOW && prevButtonValue == HIGH) {
xSemaphoreGive(countingSemaLed5); // Nếu nút SEMA được nhấn, cho Sema đếm thêm 1 (countingSemaLed5++)
}
prevButtonValue = buttonValue; // Lưu trạng thái hiện tại của nút SEMA để dùng trong vòng lặp tiếp theo
delay(10);
}
}
/* Xuất tin hiệu từ nút SEMA ra LED */
void writeSemaLed(void *) {
while (1) {
// Kiểm tra xem semaphore có sẵn không (countingSemaLed5!=0)
if (xSemaphoreTake(countingSemaLed5, portMAX_DELAY) == pdTRUE) {
// Nếu có thì chớp tắt Led trắng
for (int i = 0; i < 3; i++) {
digitalWrite(WHITE_LED_PIN, HIGH); // Bật Led trắng
delay(100); // Dừng 100ms
digitalWrite(WHITE_LED_PIN, LOW); // Tắt Led trắng
delay(100); // Dừng 100ms
}
}
}
}
/* Hiện thị trên Serial Monitor, hàm này để debug thôi không quan trọng*/
void displaySerial() {
// Chờ sensorMutex = 1 gần như mãi mãi, sau đó sensorMutex = 0
if (xSemaphoreTake(sensorMutex, portMAX_DELAY) == pdTRUE) {
Serial.print("Nhiệt độ: ");
Serial.print(temperature);
Serial.println("°C");
Serial.print("Độ ẩm: ");
Serial.print(humidity);
Serial.println("%");
Serial.print("Light Strength: ");
Serial.print(lightStrength);
Serial.println(" lumen");
xSemaphoreGive(sensorMutex); // Trả lại sensorMutex = 1
}
}
/* Buzzer chạy thụ động */
void buzzerControl(void *) {
while (1) {
tone(BUZZER_PIN, 1000); // Kích hoạt âm thanh trên buzzer với tần số 1000Hz
delay(100); // Dừng trong 100ms
noTone(BUZZER_PIN); // Tắt âm thanh trên buzzer
delay(100); // Dừng trong 100ms
}
}