Mạch Điện

Làm nhà thông minh với Arduino điều khiển quạt trần

IoT và tự động hóa gia đình đã trải qua một chặng đường dài kể từ khi chúng trở nên phổ biến lần đầu tiên vào năm 2014, nhờ sự ra mắt của vi mạchESP8266 của các hệ thống espressif. Ngày nay, chúng tôi biết nó là mô-đun nodeMCU và trong nhiều Project của chúng tôi, chúng tôi đã sử dụng vi mạch này để xây dựng nhiều Project Làm nhà thông minh với Arduino trong đó trọng tâm của chúng tôi là xây dựng hệ thống Điều khiển tốc độ động cơ AC hay điều khiển quạt trần hoặc Điều khiển góc pha. Nhưng một trong những vấn đề lớn mà chúng tôi gặp phải khi thực hiện nó là nhiễu mà nó tạo ra và độ rung của động cơ do các vấn đề về thời gian do bộ vi điều khiển đưa vào. Đó là lý do tại sao trong bài viết này, chúng tôi sẽ giải quyết vấn đề này bằng cách giới thiệu một bộ vi điều khiển thứ hai trong mạch của chúng tôi, đồng thời đảm bảo rằng BOM vẫn rẻ nhất có thể.  Hãy tham khảo với hocdientu nhé !

Mạch điều khiển quạt trần với Arduino hoạt dộng như thế nào ?

Trước khi chúng ta tiếp tục bài viết này, chúng ta hãy xem mạch này hoạt động như thế nào. Hoạt động của mạch rất đơn giản và dễ hiểu. Để giải quyết vấn đề nhiễu nói trên chúng ta đang sử dụng hai bộ vi điều khiển trong đó một bộ là vi điều khiển PIC và vi điều khiển còn lại là vi điều khiển ESP8266. ESP tạo ra tín hiệu PWM được lọc bởi mạng bộ lọc RC và được chuyển thành tín hiệu DC. Tín hiệu DC này được đưa đến ADC của vi điều khiển PIC và PIC điều khiển tốc độ của quạt trần bằng cách đọc giá trị ADC. Chúng tôi cũng có một cảm biến nhiệt độ trên bo mạch và một buzzer. Cảm biến nhiệt độ trên bo mạch được sử dụng để lấy dữ liệu nhiệt độ và còi kêu bíp mỗi khi người dùng tương tác với giao diện web.

Linh kiện Mạch điều khiển quạt trần với Arduino

Các linh kiện cần thiết để xây dựng hệ thống tự động hóa mô-đun dựa trên IoT được liệt kê dưới đây. Hầu hết các linh kiện là chung chung và có thể được tìm thấy trong bất kỳ cửa hàng trực tuyến nào, điều này làm cho quá trình sao chép rất dễ dàng.

  • Mô-đun Wifi ESP8266-01 – 1
  • Vi điều khiển PIC12F675 – 1
  • Cảm biến nhiệt độ và độ ẩm DHT11 – 1
  • Bộ chỉnh lưu cầu MB10S – 1
  • PC817 Optocoupler – 1
  • BT136 Triac – 1
  • Bộ điều khiển Triac MOC3021 – 1
  • HLK-PM03 Hi-Link – 3.3V – 1
  • Bóng bán dẫn MMBT2222A – 1
  • Buzzer 12mm – 1
  • Tụ điện 10uF – 1
  • Điện trở 1K – 1
  • Điện trở 47R – 2
  • Điện trở 470R – 1
  • 102pF, Tụ điện 2KV – 1
  • Điện trở 10K – 1
  • Điện trở 100K – 2

Sơ đồ Mạch điều khiển quạt trần với Arduino IOT

Sơ đồ mạch hoàn chỉnh của Mạch điều khiển quạt trần với Arduino IOT được hiển thị bên dưới.

Như bạn có thể thấy mạch rất đơn giản và không cần nhiều thành phần để xây dựng. Hãy bắt đầu phần giải thích của chúng tôi với mô-đun Wi-Fi ESP8266-01. Để lập trình mô-đun, trước tiên bạn cần flash firmware trên mô-đun ESP8266 và bạn cũng cần flash firmware  trên mô-đun PIC12F675 trước khi làm bất cứ điều gì.

Đầu tiên, chúng tôi có mô-đun cung cấp điện , chúng tôi đang sử dụng mô-đun cấp nguồn hylink 220V đến 3.3V để cấp điện cho toàn bộ Project.

Tiếp theo, chúng tôi có mạch phát hiện điểm 0 của chúng tôi . Mạch phát hiện điểm 0 được sử dụng để tạo ra ngắt, ngắt này được phát hiện bởi vi điều khiển PIC, sau đó nó được sử dụng để kích hoạt mạch triac.

Tiếp theo, chúng tôi có mạch kích cho TRIAC , toàn bộ hệ thống điều khiển góc pha được theo dõi và giám sát bởi vi điều khiển PIC này. Bộ điều khiển này điều khiển một trình điều khiển triac opto MOC3021 và điều đó sẽ điều khiển BT136 TRIAC. TRIAC này cũng có Điện trở và tụ điện như mạch snubber ngăn nhiễu do mạch điều khiển góc pha đưa vào.

Tiếp theo, là buzzer chúng tôi đang sử dụng một bóng bán dẫn MMB2222A để điều khiển buzzer và để hạn chế dòng điện qua chân B bóng bán dẫn, chúng tôi đang sử dụng một điện trở 1K.

Tiếp theo, chúng ta có mô-đun ESP8266-01 và Cảm biến nhiệt độ và độ ẩm DHT11 được kết nối với GPIO0 của Mô-đun ESP8266-01. Điều này có thể xảy ra vì chân của mô-đun esp luôn ở mức cao và chân của ESP GP0 nên được giữ ở mức cao để đặt thiết bị ở chế độ hoạt động bình thường.

Cuối cùng, chúng ta có một bộ lọc RC được kết nối từ ESP-01 đến vi điều khiển PIC. Bộ lọc này có nhiệm vụ chuyển đổi tín hiệu PWM do ESP tạo ra thành tín hiệu DC mượt mà mà vi điều khiển PIC sẽ đọc qua ADC.

Thiết kế PCB cho mạch điều khiển quạt trần với Arduino IOT

Như bạn có thể thấy trong hình trên, PCB được thiết kế bằng phần mềm thiết kế EAGLE PCB và nó có kích thước 70,5mm X 38mm.

Mặt trên của PCB Tự động hóa nhà mô-đun:

Mặt trên của PCB được hiển thị ở trên, đó là PCB hai lớp với sự cách ly thích hợp ở phía điện áp cao và điện áp thấp.

Mặt dưới của PCB Tự động hóa gia đình mô-đun:

Mặt dưới của PCB được hiển thị ở trên, như bạn cũng có thể thấy chúng tôi đã đặt một số thành phần SMD ở dưới cùng của PCB và chúng tôi đã sử dụng phương pháp Via Stitching thay cho TRIAC là T4 trên bo mạch. Chúng tôi đã làm như vậy để cải thiện nhiệt của PCB.

Sau khi đảm bảo các đường đi và dấu chân đã chính xác, tôi tiến hành lắp ráp PCB. Hình ảnh ở đây cho thấy bảng được hàn hoàn toàn trông như thế nào.

Như bạn có thể thấy trong hình ảnh, tất cả các thành phần được hàn đúng cách. Như đã đề cập trước đó, tất cả các thành phần cho Project này đều có sẵn dễ dàng nên Project nhân rộng là rất dễ dàng. Bạn cũng có thể tải xuống Tệp Gerber để có thể đặt mua PCB nếu cần.

Lập trình Vi điều khiển PIC12F675 tích hợp và Vi điều khiển ESP12-E

Phần Code cho Project này sẽ được chia thành ba phần vì chúng tôi đang sử dụng hai bộ vi điều khiển trong sơ đồ của mình, phần đầu tiên là vi điều khiển ESP8266 và phần thứ hai là vi điều khiển PIC như bạn có thể thấy từ sơ đồ. Vì vậy, Code cho hai bộ vi điều khiển đó sẽ khác nhau và sẽ có một phần khác, nơi chúng tôi sẽ giải thích tất cả các chi tiết về phần trang web.

Code cho Vi điều khiển PIC:

Trong phần này, chúng tôi sẽ giải thích cách hoạt động của Code cho vi điều khiển PIC. Chúng tôi bắt đầu Code của mình bằng cách bao gồm tất cả các thư viện bắt buộc, trong đó một số là thư viện nội trang và một số là thư viện tùy chỉnh. Chúng tôi cũng xác định tất cả các biến bắt buộc.

#include <xc.h>
#include "config.h"
#include "pinmanager.h"
#include "peripherals.h"
unsigned int ADC_AVG;

Tiếp theo, chúng tôi khai báo và xác định tất cả các chức năng cần thiết cần thiết để đoạn Code này hoạt động. Các hàm enable_interrupt (): được sử dụng để kích hoạt ngắt ngoài trong Vi điều khiển PIC. Chúng tôi cũng có disable_interrupt (): được sử dụng để vô hiệu hóa ngắt.

void enable_interrupt(){
    INTERRUPT_EDGE = FALLING;
    GLOBAL_INTERRUPT = ENABLE;
    EXTERNAL_INTERRUPT = ENABLE;
}
void disable_interrupt(){
    GLOBAL_INTERRUPT = DISABLE;
    EXTERNAL_INTERRUPT = DISABLE;
}

Tiếp theo, chúng ta có hàm ADCInit () được sử dụng để cấu hình ADC cho vi điều khiển PIC.

void ADCInit()
{
   ADCON0bits.ADFM = 0; // Right Justified bit 7
   ADCON0bits.VCFG = 0; // Voltage Reference VDD bit 6
   ADCON0bits.CHS1 = 1; //set AN3 as input
   ADCON0bits.CHS0 = 1;//set AN3 as input
   ADCON0bits.ADON = 1;
   ADC_PORT = INPUT;
   ANSELbits.ANS3 = 1;
}

Tiếp theo, chúng ta có hàm our __custom_delay(unsigned int delay_data) , trong vi điều khiển PIC với XC8, chúng ta không có tùy chọn để chuyển các biến với hàm delay tích hợp nên điều này trở nên cần thiết.

void __custom_delay(unsigned int delay_data){
    for(int i =0; i < delay_data; i++)
    {
        __delay_us(1);
    }
}

Tiếp theo, chúng tôi đã xác định chức năng mà thông qua đó chúng tôi đang xử lý dữ liệu ADC đến từ chân của bộ vi điều khiển và nó trả về dữ liệu ADC 8-bit.

unsigned int GetAdcvalue()
{
    ADCON0bits.GO = 1; //start the conversion
    __delay_us(200);
    while(ADCON0bits.GO==1){}; //wait for the conversion to end
    return ADRESH; //take the most significant bytes
}

Cuối cùng, chúng tôi có chức năng interrupt của chúng tôi , trong chức năng ngắt, toàn bộ điều khiển TRIAC sẽ xảy ra. Theo nguyên tắc chung, bạn không nên đặt bất kỳ Code nào bên trong chức năng ISR, nhưng thời gian của Điều khiển góc pha rất quan trọng nên bạn cần thực thi chức năng trong quy trình dịch vụ ngắt, nếu không sẽ có hiện tượng rung và chập chờn.

void __interrupt() my_isr(){
    if(EXTERNAL_INTERRUPT_FLAG)
    {
        disable_interrupt();
        EXTERNAL_INTERRUPT_FLAG =0;
        for(int j = 0; j<10; j++)
        {
            ADC_AVG = ADC_AVG + GetAdcvalue();
            __delay_us(50);
        }
        ADC_AVG = ADC_AVG / 10;     
        __custom_delay(ADC_AVG);
        TRIAC_PIN = HIGH;
        __delay_us(50);
        TRIAC_PIN = LOW;
        enable_interrupt();
   }
}

Tiếp theo, chúng ta có hàm chính, trong hàm chính, chúng ta gọi tất cả các hàm init và chúng ta thiết lập Ngắt GPIO và ADC. Và chúng tôi để trống vòng lặp while bên trong chính.

void main(void) {
    GP0_GP1_as_io();
    init();
    enable_interrupt();
    ADCInit();   
  while(1)
    ;
    return;
}

Điều này đánh dấu sự kết thúc Code của chúng ta cho phần vi điều khiển PIC và chúng ta có thể chuyển sang Code cho Bộ vi điều khiển ESP8266.

Code cho Bộ vi điều khiển ESP8266-01:

ESP8266 là bộ não của mạch và nó phục vụ nhiều mục đích. Nó phục vụ trang web, tạo tín hiệu PWM cho bộ vi điều khiển PIC và cấp nguồn cho buzzer để cho người dùng biết khi nhận được lệnh.

Chúng tôi bắt đầu Code của mình bằng cách bao gồm tất cả các thư viện được yêu cầu: ESP8266WiFi, ESP8266mDNS, ArduinoOTA, Adafruit_Sensor, DHT, ESPAsyncTCP và ESPAsyncWebServer và ESP_EEPROM.

// Import required libraries
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <Hash.h>
#define DHTPIN 0
#include <ESP_EEPROM.h>

Tiếp theo, chúng tôi đã xác định loại cảm biến DHT mà chúng tôi đang sử dụng cho việc này. Chúng tôi đang sử dụng cảm biến DHT11, vì vậy chúng tôi đã xác định điều đó.

#define DHTTYPE DHT11

Tiếp theo, chúng tôi đã xác định tất cả các biến bắt buộc trong Project này. Trong phần này, đầu tiên chúng ta đã xác định SSID và Mật khẩu, sau đó chúng ta xác định chân đầu ra pwm và chân DHT của cảm biến. Tiếp theo, chúng tôi xác định sliderValue và các biến cho nhiệt độ và độ ẩm. Tiếp theo, chúng tôi khai báo ba biến temp_low , temp_high và temp_range sẽ được sử dụng để lưu trữ dữ liệu đầu vào của người dùng. Tiếp theo, chúng tôi có ba biến của chúng tôi, một trong số chúng là auto_manual_mode lưu dữ liệu chế độ của mô-đun và hai biến cuối cùng được sử dụng để điều khiển buzzer trong mạch.

float t = 0.0;
unsigned long previousMillis = 0;
const long interval = 5000;
const char* ssid = "Fan Speed Controller";
//const char* password = "12345678";
const char* password = "12345678";
const int output_pin = 2;
String sliderValue = "0";
String temp_min, temp_max;
const char* PARAM_INPUT = "value";
const char* Temp_Min = "tempMin";
const char* Temp_Max = "tempMax";
float temp_range;
bool auto_manual_mode = 0; // 1 is auto mode o is manual mode
int tmp_mode, tmp_slider = 0;

Tiếp theo, chúng tôi khởi tạo cá thể DHT và chuyển vào chân DHT và kiểu DHT mà chúng tôi đã khai báo ở đầu Code, sau đó chúng tôi cũng khởi tạo cá thể máy chủ AsyncWebServer (80) trên cổng 80.

 DHT dht(DHTPIN, DHTTYPE);
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

Tiếp theo, chúng tôi có chức năng thiết lập của mình , trong chức năng thiết lập lúc đầu, chúng tôi đặt chân TX của ESP là IO và chúng tôi đặt nó làm đầu ra và đặt thành LOW để còi sẽ không phát ra tiếng bíp ngay lập tức khi ESP khởi động. Tiếp theo, chúng tôi khởi tạo nối tiếp để gỡ lỗi và chúng tôi cũng bắt đầu EEPROM. Tiếp theo, chúng tôi gọi phương thức EEPROM.get . Ý tưởng là trong thời gian bị cắt điện, mô-đun sẽ hoạt động trở lại.

 // Serial port for debugging purposes
  pinMode(1, FUNCTION_3);
  pinMode(3, FUNCTION_3);
  pinMode(1, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(1, HIGH);
  Serial.begin(115200);
  EEPROM.begin(30);
  EEPROM.get(0, auto_manual_mode);
  float a, b;
  int c;
  EEPROM.get(4, a);
  EEPROM.get(12, b);
  EEPROM.get(20, c);
  temp_min = String(a);
  temp_max = String(b);
  sliderValue = String(c);
//  Serial.println("\n");
//  delay(2000);
//  Serial.println(auto_manual_mode);
//  Serial.println(temp_min);
//  Serial.println(temp_max);
//  Serial.println(sliderValue);

Tiếp theo, chúng tôi áp dụng các thay đổi bằng cách gọi hàm main_loop () và chúng tôi thiết lập ESP làm chế độ điểm truy cập. Tiếp theo, chúng tôi khởi tạo tất cả các máy chủ trên các phiên bản của ESP. Với sự trợ giúp của điều này, chúng tôi sẽ điều khiển thanh trượt, lấy dữ liệu từ biểu mẫu và chúng tôi cũng sẽ hiển thị kết quả đọc nhiệt độ trên trang web.

 main_loop();
  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, password); / Set access point
  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/html", index_html, processor);
  });
  // Send a GET request to <ESP_IP>/slider?value=<inputMessage>
  server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest * request) {
    String inputMessage;
    // GET input1 value on <ESP_IP>/slider?value=<inputMessage>
    if (request->hasParam(PARAM_INPUT)) {
      inputMessage = request->getParam(PARAM_INPUT)->value();
      sliderValue = inputMessage;
      auto_manual_mode = 0; // set to manual mode
      EEPROM.put(0, auto_manual_mode);
      EEPROM.put(20, sliderValue.toInt());
      Serial.println(auto_manual_mode);
      boolean ok2 = EEPROM.commit();
      Serial.println((ok2) ? "Second commit OK" : "Commit failed");
    }
    else {
      inputMessage = "No message sent";
    }
    Serial.println(inputMessage);
    request->send(200, "text/plain", "OK");
  });
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/plain", String(t).c_str());
  });
  // Send a GET request to <ESP_IP>/get?inputString=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest * request) {
    String inputMessage;
    // GET inputString value on <ESP_IP>/get?inputString=<inputMessage>
    if (request->hasParam(Temp_Min)) {
      inputMessage = request->getParam(Temp_Min)->value();
      temp_min = inputMessage;
      EEPROM.put(4, temp_min.toFloat());
      EEPROM.commit();
      Serial.println(temp_min);
      //writeFile(SPIFFS, "/inputString.txt", inputMessage.c_str());
    }
    // GET inputInt value on <ESP_IP>/get?inputInt=<inputMessage>
    if (request->hasParam(Temp_Max)) {
      inputMessage = request->getParam(Temp_Max)->value();
      temp_max = inputMessage;
      EEPROM.put(12, temp_max.toFloat());
      EEPROM.commit();
      Serial.println(temp_max);
      // writeFile(SPIFFS, "/inputInt.txt", inputMessage.c_str());
    }
    // GET inputFloat value on <ESP_IP>/get?inputFloat=<inputMessage>
    else {
      inputMessage = "No message sent";
    }
    //Serial.println(inputMessage);
    //request->send(200, "text/text", "<html><body><h3>Data Set to ESP</h3></body></html>");
    auto_manual_mode = 1; // set to auto mode
    EEPROM.put(0, auto_manual_mode);
    Serial.println(auto_manual_mode);
    boolean ok1 = EEPROM.commit();
    Serial.println((ok1) ? "First commit OK" : "Commit failed");
  });
  // Start server
  server.begin();
}

Tiếp theo, chúng ta có hàm loop , trong hàm loop đầu tiên chúng ta gọi hàm main_loop () . Chúng tôi đặt chân TX của thiết bị ở mức Thấp để buzzer không phát ra âm thanh. Tiếp theo, chúng tôi kiểm tra cờ chế độ thủ công tự động và kiểm tra nó với giá trị trước đó, điều này được thực hiện để chúng tôi có thể phát hiện bất kỳ thay đổi nào xảy ra và nếu chúng tôi phát hiện bất kỳ thay đổi nào, chúng tôi sẽ phát ra tiếng bíp. Nếu chúng tôi phát hiện chế độ tự động do người dùng kích hoạt, chúng tôi sẽ phát ra tiếng bíp của buzzer hai lần.

void loop() {
  main_loop();
  digitalWrite(1, HIGH);
  if (auto_manual_mode != tmp_mode) {
    if (auto_manual_mode == 1) {
      digitalWrite(1, LOW);
      delay(500);
      digitalWrite(1, HIGH);
      delay(500);
      digitalWrite(1, LOW);
      delay(500);
      digitalWrite(1, HIGH);
      delay(500);
    }
    tmp_mode = auto_manual_mode;
  }
  if (sliderValue.toInt() != tmp_slider)
  {
    digitalWrite(1, LOW);
    delay(500);
    digitalWrite(1, HIGH);
    tmp_slider = sliderValue.toInt();
  }
}

Tiếp theo, chúng ta có hàm main loop , bên trong hàm này, trước tiên chúng ta lấy giá trị bộ đếm thời gian hiện tại bằng hàm mills () và kiểm tra xem bộ đếm thời gian có vượt quá giá trị khoảng thời gian hay không. Nếu vậy, chúng tôi đặt giá trị beforeMillis thành currentMillis  lấy dữ liệu nhiệt độ từ cảm biến DHT11.

Trang web được tạo bằng HTML và CSS:

Chúng tôi đang sử dụng một trang web được tạo bằng HTML và CSS để tạo giao diện web mà qua đó chúng tôi có thể kiểm soát tất cả các tính năng của thiết bị tự động hóa nhà dạng mô-đun. Bên trong tệp index_html.h , chúng tôi sẽ xác định tất cả CSS cần thiết để làm cho trang web trông sạch sẽ và chúng tôi sẽ giải thích Code html tiếp theo.

Chúng tôi bắt đầu Code của mình bằng lập chỉ mục html và sau đó, chúng tôi sử dụng thẻ <meta> để làm cho trang web của bạn phản hồi trong bất kỳ trình duyệt nào.

<meta name="viewport" content="width=device-width, initial-scale=1">
Between the <style></style> tags, we add some CSS to style the web page.
body{
  margin:0;
  padding: 0;
  color:#1c1c1c;
  font-family: roboto;
  position: relative;
  text-align:center;
}
p{margin:0;padding:0;}
.clr{
  clear:both;
}
@font-face {
  font-family: quartz;
  src: url(fonts/quartz.ttf);
}
#bg_mob{
  background-color: #f4f4f4;
  max-width: 540px;
  margin:0 auto;
  height:100vh;
}
.mob_inner{
  padding: 15px;
}
#espRange {
  -webkit-appearance: none;
  width: 100%;
  height: 15px;
  border-radius: 5px;
  background: #0e3d79;
  outline: none;
}
.slideresp:hover {
  opacity: 1;
}
.slideresp::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #00acec;
  cursor: pointer;
}
.slideresp::-moz-range-thumb {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #00acec;
  cursor: pointer;
}
.value{
    width: 100px;
    background: #ff7700;
    margin: 0 auto;
    padding: 5px;
    margin-top: 10px;
    color: white;
}
#temperature_sec{margin: 30px 0;}
.form_max-min input
    padding: 6px 4px;
    border: 1px solid #c8c8c8;
}
#esp-submit{
    background-color: #ff7700;
    color: white;
    border: none;
    padding: 5px 10px;
    font-size: 16px;
}
.form_max-min{margin:35px 0;}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
  -webkit-appearance: none;
}
  </style>

Bên trong này, chúng tôi tùy chỉnh thanh trượt, chúng tôi đặt hộp hiển thị nhiệt độ và đặt biểu mẫu như chúng tôi mong muốn và chúng tôi cũng đặt tất cả các thông số về màu sắc, chiều cao, chiều rộng và phần đệm.

Bên trong các thẻ <body> </body> , chúng tôi thêm nội dung cho trang web của mình. Hai thẻ div cung cấp cho phần nội dung một id và một lớp mà qua đó chúng ta có thể triển khai kiểu cho toàn bộ phần nội dung của trang web. Các thẻ <h2> </h2> thêm một tiêu đề vào trang web. Trong trường hợp này, văn bản ” ESP Fan Speed Controller “,

<div id="bg_mob">
    <div class="mob_inner">
      <div class="slidecontainer">
        <h2>ESP Fan Speed Controller</h2>

Tiếp theo, chúng ta tạo một thanh trượt, Để tạo một thanh trượt trong HTML, bạn sử dụng thẻ <input> . Thẻ <input> chỉ định một trường mà người dùng có thể nhập dữ liệu. Nếu bạn đang tìm kiếm các kiểu đầu vào, có nhiều kiểu đầu vào để tạo thanh trượt, bạn cần sử dụng thuộc tính type với giá trị phạm vi. Trong thanh trượt, bạn cũng cần xác định phạm vi tối thiểu và tối đa của thanh trượt. Đối với trường hợp của chúng tôi, nó là 0 đến 100. Ngoài ra, bạn cần chỉ định ID, lớp, thay đổi và hơn thế nữa. Loại onchange được sử dụng để gọi một hàm để chúng tôi có thể xác nhận các thay đổi trong esp.

<input type="range" onchange="updateSliderPWM(this)" id="espRange" min="0" max="100" value="%SLIDERVALUE%" step="1" class="slideresp" style="height:18px;width:290px; border-radius:5px;background:#0e3d79;outline:none;">

Tiếp theo, chúng ta có thẻ đoạn văn sẽ hiển thị giá trị thanh trượt khi người dùng thay đổi thanh trượt trong thời gian thực.

<p style="width: 60px;background: #ff7700;margin: 0 auto;padding: 6px 12px;color: white;"><span id="textSliderValue">%SLIDERVALUE%</span></p>

Như vậy, chúng ta làm tương tự để hiển thị nhiệt độ và chúng ta cũng làm tương tự để thiết lập biểu mẫu.

 </div>
      <hr style="margin-top: 35px;border: 1px solid #e6e5e5;">
      <div id="temperature_sec">
        <div>
          <h2><i class="fa fa-thermometer-half" style="color: #ec5a00;margin-right: 10px;"></i>Room Temperature <span id="temperature" style="background:#dddddd;padding: 3px 12px;">%TEMPERATURE%<sup class="units">&deg;C</sup></span></h2>
        </div>
      </div>
      <hr style="margin-top: 35px;border: 1px solid #e6e5e5;">
      <form action="/get" class="form_max-min">
       <label><b>Min:&nbsp;&nbsp;&nbsp;</b> </label>
       <input type="number" id="quantity" min="10" placeholder="Min 10" name="tempMin"><br><br>
        <label><b>Max:&nbsp;&nbsp;&nbsp;</b> </label>
        <input type="number" id="quantity"  max="60" placeholder="Max 60" name="tempMax"><br><br>
        <input type="submit" id="esp-submit" value="Enable Auto Mode" onclick="submitMessage()">
      </form>
      <p style="text-align: left;background: #e8e8e8;padding: 10px;font-size: 14px;line-height: 22px;color: black;"><b>Note :</b> This device features an auto and manual mode function; users can enable auto speed control mode by inputting the desired temperature range(Min and Max Value) and clicking on the Enable Auto Mode button. If the slider is moved while auto mode is enabled the device automatically reverts back to manual speed control mode.</p>
    </div>
  </div>

Cuối cùng, chúng tôi thực hiện tất cả các hàm được định nghĩa bên trong phần thân của tệp html và chúng tôi thực hiện một yêu cầu nhận bằng cách sử dụng XMLHttpRequest mới (); hàm số.

<script>
function updateSliderPWM(element) {
  var sliderValue = document.getElementById("espRange").value;
  document.getElementById("textSliderValue").innerHTML = sliderValue;
  console.log(sliderValue);
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/slider?value="+sliderValue, true);
  xhr.send();
}
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("temperature").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/temperature", true);
  xhttp.send();
}, 5000 ) ;
function submitMessage() {
      alert("Saved value to ESP SPIFFS");
      setTimeout(function(){ document.location.reload(false); }, 500);  
    }
</script>
</body>
</html>
)rawliteral";

Bằng cách này, khi ESP8266 nhận được yêu cầu GET, nó có thể truy xuất tham số giá trị trong URL và điều khiển tín hiệu PWM tương ứng như chúng ta sẽ thấy trong các phần tiếp theo.

Kiểm tra mạch điều khiển quạt trần

Khi PCB được hoàn thành, chúng tôi đã tải lên Code cho cả vi điều khiển PIC và vi điều khiển ESP8266 và chúng tôi bắt đầu kiểm tra PCB. Đối với thử nghiệm đầu tiên của chúng tôi, chúng tôi đã kết nối bóng đèn 100Watt nối tiếp với mạch để nếu có bất kỳ sự cố nào, bóng đèn sẽ bảo vệ mạch.

Tiếp theo, chúng tôi ngắt kết nối bóng đèn nối tiếp và kiểm tra mạch xem nó có hoạt động tốt hay không và chắc chắn rằng mạch đã hoạt động tốt.

Sau đó, chúng tôi đã kiểm tra chức năng chế độ tự động và thủ công của mạch và nó cũng hoạt động bình thường.

Code Full :

// Import required libraries
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <Hash.h>
#define DHTPIN 0
#include <ESP_EEPROM.h>
#include"index_html.h"
#define DHTTYPE    DHT11
float t = 0.0;
unsigned long previousMillis = 0;
const long interval = 3000;
const char* ssid = "Fan Speed Controller";
const char* password = "12345678";
const int output_pin = 2;
String sliderValue = "0";
String temp_min, temp_max;
const char* PARAM_INPUT = "value";
const char* Temp_Min = "tempMin";
const char* Temp_Max = "tempMax";
float temp_range;
bool auto_manual_mode = 0; // 1 is auto mode o is manual mode
int tmp_mode, tmp_slider = 0;
DHT dht(DHTPIN, DHTTYPE);
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
String processor(const String& var) {
  //Serial.println(var);
  if (var == "SLIDERVALUE") {
    return sliderValue;
  }
  else if (var == "TEMPERATURE") {
    return String(t);
  }
  else if (var == "tempMin") {
    return temp_min;
  }
  else if (var == "tempMax") {
    return temp_max ;
  }
  return String();
}
void main_loop();
void setup() {
  // Serial port for debugging purposes
  pinMode(1, FUNCTION_3);
  pinMode(3, FUNCTION_3);
  pinMode(1, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(1, HIGH);
  dht.begin();
  Serial.begin(115200);
  EEPROM.begin(30);
  EEPROM.get(0, auto_manual_mode);
  float a, b;
  int c;
  EEPROM.get(4, a);
  EEPROM.get(12, b);
  EEPROM.get(20, c);
  temp_min = String(a);
  temp_max = String(b);
  sliderValue = String(c);
  //  Serial.println("\n");
  //  delay(2000);
  //  Serial.println(auto_manual_mode);
  //  Serial.println(temp_min);
  //  Serial.println(temp_max);
  //  Serial.println(sliderValue);
  main_loop();
  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, password);
  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/html", index_html, processor);
  });
  // Send a GET request to <ESP_IP>/slider?value=<inputMessage>
  server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest * request) {
    String inputMessage;
    // GET input1 value on <ESP_IP>/slider?value=<inputMessage>
    if (request->hasParam(PARAM_INPUT)) {
      inputMessage = request->getParam(PARAM_INPUT)->value();
      sliderValue = inputMessage;
      auto_manual_mode = 0; // set to manual mode
      EEPROM.put(0, auto_manual_mode);
      EEPROM.put(20, sliderValue.toInt());
      Serial.println(auto_manual_mode);
      boolean ok2 = EEPROM.commit();
      Serial.println((ok2) ? "Second commit OK" : "Commit failed");
    }
    else {
      inputMessage = "No message sent";
    }
    Serial.println(inputMessage);
    request->send(200, "text/plain", "OK");
  });
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/plain", String(t).c_str());
  });
  // Send a GET request to <ESP_IP>/get?inputString=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest * request) {
    String inputMessage;
    // GET inputString value on <ESP_IP>/get?inputString=<inputMessage>
    if (request->hasParam(Temp_Min)) {
      inputMessage = request->getParam(Temp_Min)->value();
      temp_min = inputMessage;
      EEPROM.put(4, temp_min.toFloat());
      EEPROM.commit();
      Serial.println(temp_min);
      //writeFile(SPIFFS, "/inputString.txt", inputMessage.c_str());
    }
    // GET inputInt value on <ESP_IP>/get?inputInt=<inputMessage>
    if (request->hasParam(Temp_Max)) {
      inputMessage = request->getParam(Temp_Max)->value();
      temp_max = inputMessage;
      EEPROM.put(12, temp_max.toFloat());
      EEPROM.commit();
      Serial.println(temp_max);
      // writeFile(SPIFFS, "/inputInt.txt", inputMessage.c_str());
    }
    // GET inputFloat value on <ESP_IP>/get?inputFloat=<inputMessage>
    else {
      inputMessage = "No message sent";
    }
    //Serial.println(inputMessage);
    //request->send(200, "text/text", "<html><body><h3>Data Set to ESP</h3></body></html>");
    auto_manual_mode = 1; // set to auto mode
    EEPROM.put(0, auto_manual_mode);
    Serial.println(auto_manual_mode);
    boolean ok1 = EEPROM.commit();
  });
  // Start server
  server.begin();
}
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // save the last time you updated the DHT values
    previousMillis = currentMillis;
    // Read temperature as Celsius (the default)
    // float temp_tmp = dht.readTemperature();
    t = dht.readTemperature();
  }
  main_loop();
  pinMode(1, FUNCTION_3);
  pinMode(3, FUNCTION_3);
  pinMode(1, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(1, HIGH);
  if (auto_manual_mode != tmp_mode) {
    if (auto_manual_mode == 1) {
      digitalWrite(1, LOW);
      delay(500);
      digitalWrite(1, HIGH);
      delay(500);
      digitalWrite(1, LOW);
      delay(500);
      digitalWrite(1, HIGH);
      delay(500);
    }
    tmp_mode = auto_manual_mode;
  }
  if (sliderValue.toInt() != tmp_slider)
  {
    digitalWrite(1, LOW);
    delay(500);
    digitalWrite(1, HIGH);
    tmp_slider = sliderValue.toInt();
  }
}
void main_loop()
{
  if (auto_manual_mode == 0) // thi is manual mode the value is 0
  {
    int val = map(sliderValue.toInt(), 0, 100, 255, 0);
    analogWrite(output_pin, val);
  }
  if (auto_manual_mode) // auto mode
  {
    temp_range = (temp_max.toFloat() - temp_min.toFloat()) / 10;
    if (temp_max.toFloat() <= t)
    {
      analogWrite(output_pin, 25);
    }
    else if ((temp_min.toFloat() + (temp_range * 9)) <= t)
    {
      analogWrite(output_pin, 50);
    }
    else if ((temp_min.toFloat() + (temp_range * 8)) <= t)
    {
      analogWrite(output_pin, 100);
    }
    else if ((temp_min.toFloat() + (temp_range * 7)) <= t)
    {
      analogWrite(output_pin, 125);
    }
    else if ((temp_min.toFloat() + (temp_range * 6)) <= t)
    {
      analogWrite(output_pin, 150);
    }
    else if ((temp_min.toFloat() + (temp_range * 5)) <= t)
    {
      analogWrite(output_pin, 175);
    }
    else if ((temp_min.toFloat() + (temp_range * 4)) <= t)
    {
      analogWrite(output_pin, 200);
    }
    else if ((temp_min.toFloat() + (temp_range * 3)) <= t)
    {
      analogWrite(output_pin, 225);
    }
    else if ((temp_min.toFloat() + (temp_range * 2)) <= t)
    {
      analogWrite(output_pin, 250);
    }
    else if ((temp_min.toFloat() + (temp_range * 1)) <= t)
    {
      analogWrite(output_pin, 255);
    }
  }
}

Đỗ Thủy Học Điện Tử

Tôi một người đam mê cung cấp kiến thức cuộc sống và kiến thức giáo dục văn học , vật lý , điện tử đến cho mọi người hãy cùng tôi tiếp nhận kiến thức mới nhé !

Trả lời

Email của bạn sẽ không được hiển thị công khai.

Back to top button