Xây dựng hệ thống nhà thông minh điều khiển qua WiFi sử dụng vi điều khiển 8051

Giới thiệu tổng quan về kiến trúc hệ thống Bài viết này trình bày giải pháp thiết kế một hệ thống giám sát và điều khiển môi trường sống tự động, lấy cảm hứng từ các nguyên lý cơ bản của IoT (Internet of Things) nhưng được triển khai trên nền tảng phần cứng truyền thống. Trung tâm xử lý của hệ thống là vi điều khiển dòng STC89C51/STC89C52 (kiến trúc 8051), đóng vai trò là bộ não điều phối dữ liệu giữa các ngoại vi. Hệ thống tích hợp module giao tiếp không dây ESP8266 để kết nối với mạng Internet cục bộ, cho phép người dùng tương tác từ xa thông qua ứng dụng di động hoặc trình duyệt web.

Các chức năng cốt lõi bao gồm:

  • Giao tiếp từ xa: Nhận lệnh điều khiển bật/tắt thiết bị điện (đèn, quạt, máy lạnh) thông qua chuẩn TCP/IP hoặc HTTP đơn giản hóa.
  • Thu thập dữ liệu cảm biến: Đo lường nhiệt độ và độ ẩm thời gian thực bằng cảm biến DHT11, hiển thị kết quả lên màn hình LCD 16x2 ký tự.
  • Lưu trữ tham số: Sử dụng chip EEPROM AT24C02 để ghi nhớ các ngưỡng cảnh báo do người dùng thiết lập, đảm bảo dữ liệu không bị mất khi mất nguồn.
  • Cơ chế an toàn: Kích hoạt cảnh báo âm thanh và ánh sáng khi các chỉ số môi trường vượt quá giới hạn đã định.

Phân tích sơ đồ khối và thiết kế phần cứng Hệ thống được chia thành các phân khu chức năng độc lập nhưng liên kết chặt chẽ thông qua bus dữ liệu và tín hiệu điều khiển.

  1. Khối xử lý trung tâm (MCU) Vi điều khiển STC89C52 được lựa chọn nhờ tính ổn định cao, chi phí thấp và tài nguyên thư viện phát triển phong phú. Các chân I/O được phân bổ như sau:
  • P0: Kết nối với bus dữ liệu 8-bit của LCD1602 (chế độ 4-bit hoặc 8-bit).
  • P1: Điều khiển các chân trạng thái của module Relay và chân Data của cảm biến DHT11.
  • P2: Kết nối với các chân SCL, SDA của bus I2C để giao tiếp với AT24C02 và các chân điều khiển RS, EN của LCD.
  • TXD/RXD (P3.0/P3.1): Cổng UART nối tiếp với module ESP8266.
  1. Module truyền thông không dây (ESP8266) Module ESP8266-01 hoặc ESP8266-12F hoạt động ở chế độ STA (Station), kết nối vào Access Point gia đình. Giao thức truyền tin dựa trên chuỗi ký tự ASCII gửi qua cổng Serial. Để đơn giản hóa việc demo, cấu hình mặc định thường gán SSID là "SmartHome_AP" và mật khẩu "password123". Bảng mã lệnh điều khiển (Command Set): | Mã lệnh gửi đi | Hành động tương ứng | |---|---| | RELAY_ON_1 | Đóng công tắc Relay 1 (Bật thiết bị 1) | | RELAY_OFF_1 | Mở công tắc Relay 1 (Tắt thiết bị 1) | | RELAY_ON_2 | Đóng công tắc Relay 2 (Bật thiết bị 2) | | GET_ENV_DATA | Yêu cầu trả về dữ liệu Nhiệt độ & Độ ẩm hiện tại |

  2. Cảm biến môi trường (DHT11) DHT11 sử dụng giao thức Single-Bus (một dây). Vi điều khiển phải tuân thủ nghiêm ngặt biểu đồ thời gian (timing diagram) để tránh lỗi đọc dữ liệu. Phạm vi đo hữu ích: Nhiệt độ 0-50°C, Độ ẩm 20-90% RH. Tín hiệu đầu ra là kỹ thuật số, dễ dàng ghép nối trực tiếp với chân GPIO mà không cần mạch chuyển đổi ADC phức tạp.

  3. Mạch chấp hành và Cảnh báo

  • Relay: Sử dụng relay 5V có cách ly quang hoặc transistor driver (như ULN2003 hoặc BC547) để tách biệt mạch điều khiển áp thấp khỏi mạch tải cao áp (220V AC).
  • Cảnh báo: Buzzer (loa còi) và LED đỏ được kích hoạt khi logic so sánh ngưỡng trong chương trình trả về giá trị TRUE.

Triển khai phần mềm nhúng Chương trình được viết bằng ngôn ngữ C, biên dịch bởi Keil C51. Cấu trúc code theo mô hình vòng lặp chính (Main Loop) kết hợp với ngắt (Interrupt) cho UART để đảm bảo tốc độ phản hồi lệnh.

  1. Khởi tạo hệ thống và Vòng lặp chính Thay vì gọi tuần tự tất cả các hàm gây chậm trễ, chúng ta sử dụng cơ chế Timer để quản lý thời gian cập nhật cảm biến và hiển thị, trong khi vẫn ưu tiên xử lý lệnh từ WiFi.
#include <reg52.h>
#include <string.h>

// Khai báo các biến toàn cục
unsigned char temp_val = 0;
unsigned char humi_val = 0;
unsigned char alarm_limit_t = 40; // Ngưỡng nhiệt độ mặc định
unsigned char alarm_limit_h = 80; // Ngưỡng độ ẩm mặc định
bit flag_update_lcd = 0;
bit flag_read_sensor = 0;

void System_Init(void);
void Process_UART_Commands(void);
void Update_Display(void);
void Check_Alarm_Condition(void);

void main() {
    System_Init();
    
    while(1) {
        // Xử lý các lệnh nhận được từ ESP8266
        Process_UART_Commands();
        
        // Cập nhật màn hình nếu có yêu cầu mới
        if(flag_update_lcd) {
            Update_Display();
            flag_update_lcd = 0;
        }
        
        // Kiểm tra điều kiện cảnh báo
        Check_Alarm_Condition();
    }
}
  1. Xử lý giao tiếp Serial (UART) Chức năng này lắng nghe luồng dữ liệu từ ESP8266. Khi nhận đủ một gói tin (kết thúc bằng ký tự xuống dòng hoặc độ dài cố định), chương trình sẽ so khớp chuỗi lệnh.
char rx_buffer[30];
int rx_index = 0;

void UART_ISR() interrupt 4 {
    unsigned char received_byte;
    if(RI) {
        RI = 0;
        received_byte = SBUF;
        
        if(received_byte == '\n' || rx_index >= 29) {
            rx_buffer[rx_index] = '\0'; // Kết thúc chuỗi
            // Lệnh được xử lý trong vòng lặp chính để tránh delay trong ISR
            rx_index = 0; 
        } else {
            rx_buffer[rx_index++] = received_byte;
        }
    }
}

void Process_UART_Commands() {
    if(rx_buffer[0] != '\0') {
        if(strcmp(rx_buffer, "RELAY_ON_1") == 0) {
            P1_0 = 0; // Giả sử Active Low cho Relay
        } 
        else if(strcmp(rx_buffer, "RELAY_OFF_1") == 0) {
            P1_0 = 1;
        }
        else if(strcmp(rx_buffer, "GET_ENV_DATA") == 0) {
            Send_Data_To_WiFi(temp_val, humi_val);
        }
        rx_buffer[0] = '\0'; // Xóa buffer sau khi xử lý
    }
}
  1. Thuật toán đọc cảm biến DHT11 Việc đọc DHT11 đòi hỏi sự chính xác về micro-giây. Dưới đây là logic rút gọn cho việc khởi tạo và đọc byte dữ liệu.
#define DHT_PIN P1_1 // Chân kết nối Data của DHT11

void Delay_us(unsigned int t) {
    while(t--);
}

unsigned char Read_DHT11_Bit(void) {
    unsigned char i = 0;
    while(DHT_PIN == 0 && i < 100) i++; // Chờ mức cao bắt đầu
    Delay_us(40); // Chờ 40us để xác định bit 0 hay 1
    return (DHT_PIN == 1) ? 1 : 0;
}

void Read_DHT11_Data(void) {
    // Logic khởi tạo bắt buộc (Start Signal)
    DHT_PIN = 0;
    Delay_us(200);
    DHT_PIN = 1;
    Delay_us(40);
    
    if(DHT_PIN == 0) {
        // Đọc 40 bit dữ liệu (Humidity Int, Hum Dec, Temp Int, Temp Dec, Checksum)
        // ... (Code chi tiết giải mã từng byte)
        temp_val = /* Giá trị nhiệt độ trích xuất */;
        humi_val = /* Giá trị độ ẩm trích xuất */;
        flag_update_lcd = 1; // Đánh dấu cần cập nhật màn hình
    }
}
  1. Quản lý lưu trữ EEPROM (I2C) Sử dụng thư viện I2C phần mềm (Bit-banging) để ghi các ngưỡng cảnh báo vào địa chỉ cụ thể của AT24C02. Điều này cho phép người dùng thay đổi mức báo động mà không cần nạp lại firmware.
void Save_Config_To_EEPROM(unsigned char addr, unsigned char data) {
    I2C_Start();
    I2C_SendByte(0xA0 + ((addr >> 8) << 1)); // Device Address + Page Select
    I2C_SendByte(addr & 0xFF);               // Memory Address
    I2C_SendByte(data);                      // Data to write
    I2C_Stop();
}

void Load_Config_From_EEPROM() {
    alarm_limit_t = I2C_ReadByte(0x00); // Địa chỉ lưu ngưỡng nhiệt
    alarm_limit_h = I2C_ReadByte(0x01); // Địa chỉ lưu ngưỡng ẩm
}
  1. Logic kiểm soát cảnh báo Hàm này so sánh dữ liệu cảm biến với ngưỡng đã lưu. Nếu vượt quá, nó sẽ kích hoạt chân điều khiển Buzzer và LED.
void Check_Alarm_Condition() {
    if((temp_val > alarm_limit_t) || (humi_val > alarm_limit_h)) {
        P2_7 = 0; // Bật Buzzer (Active Low)
        P2_6 = 1; // Bật LED cảnh báo
    } else {
        P2_7 = 1; // Tắt Buzzer
        P2_6 = 0; // Tắt LED
    }
}

Hệ thống hoàn chỉnh cho phép người dùng trải nghiệm quy trình khép kín: từ việc thiết lập tham số qua phím bấm vật lý hoặc lệnh từ xa, lưu trữ vào EEPROM, đến việc thu thập dữ liệu cảm biến liên tục và phản hồi trạng thái lên cả màn hình cục bộ lẫn thiết bị di động.

Thẻ: STC89C52 ESP8266 DHT11 LCD1602 I2C

Đăng vào ngày 25 tháng 9 lúc 08:07