#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_NeoPixel.h>
#define DHTPIN 2
#define DHTTYPE DHT22
#define BTN_PLUS 3
#define BTN_MINUS 4
#define LED_PIN 6
#define NUMPIXELS 4
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Adafruit_NeoPixel pixels(NUMPIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);
float desiredTemp = 28.0;
// Hàm tam giác
float trimf(float x, float a, float b, float c) {
if (x <= a || x >= c) return 0;
if (x == b) return 1;
if (x > a && x < b) return (x - a) / (b - a);
return (c - x) / (c - b);
}
// Bộ điều khiển logic mờ
int fuzzyControl(float error) {
float largeNegative = trimf(error, -10, -7, -3); // LN
float smallNegative = trimf(error, -5, -2, 0); // SN
float zeroError = trimf(error, -1, 0, 1); // ZE
float smallPositive = trimf(error, 0, 2, 5); // SP
float largePositive = trimf(error, 3, 7, 10); // LP
float numerator =
largeNegative * 255 +
smallNegative * 192 +
zeroError * 128 +
smallPositive * 64 +
largePositive * 0;
float denominator =
largeNegative +
smallNegative +
zeroError +
smallPositive +
largePositive;
if (denominator == 0) return 0;
return numerator / denominator;
}
int toDiscretePWM(int pwm) {
if (pwm <= 0) return 0;
else if (pwm <= 64) return 64;
else if (pwm <= 128) return 128;
else if (pwm <= 192) return 192;
else return 255;
}
int pwmToLevel(int pwm) {
if (pwm == 0) return 0; // OFF
else if (pwm == 64) return 1; // LOW
else if (pwm == 128) return 2; // MEDIUM
else if (pwm == 192) return 3; // HIGH
else return 4; // MAX
}
void updateStrip(int pwm) {
int level = pwmToLevel(pwm);
pixels.clear();
for (int i = 0; i < level; i++) {
if (level == 1) {
pixels.setPixelColor(i, pixels.Color(0, 255, 0));
}
else if (level == 2) {
pixels.setPixelColor(i, pixels.Color(255, 255, 0));
}
else if (level == 3) {
pixels.setPixelColor(i, pixels.Color(255, 120, 0));
}
else if (level == 4) {
pixels.setPixelColor(i, pixels.Color(255, 0, 0));
}
}
pixels.show();
}
void setup() {
Serial.begin(9600);
dht.begin();
lcd.init();
lcd.backlight();
pixels.begin();
pixels.clear();
pixels.show();
pinMode(BTN_PLUS, INPUT_PULLUP);
pinMode(BTN_MINUS, INPUT_PULLUP);
lcd.setCursor(0, 0);
lcd.print("Fuzzy Temp");
lcd.setCursor(0, 1);
lcd.print("Controller");
delay(1500);
lcd.clear();
}
void loop() {
float currentTemp = dht.readTemperature();
if (isnan(currentTemp)) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DHT Error!");
delay(1000);
return;
}
if (digitalRead(BTN_PLUS) == LOW) {
desiredTemp += 0.5;
delay(250);
}
if (digitalRead(BTN_MINUS) == LOW) {
desiredTemp -= 0.5;
delay(250);
}
float error = desiredTemp - currentTemp;
int fuzzyPWM = fuzzyControl(error);
int pwmValue = toDiscretePWM(fuzzyPWM);
int level = pwmToLevel(pwmValue);
updateStrip(pwmValue);
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(currentTemp, 1);
lcd.print(" Set:");
lcd.print(desiredTemp, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print("PWM:");
lcd.print(pwmValue);
lcd.print(" Lv:");
lcd.print(level);
lcd.print(" ");
Serial.print("Temp=");
Serial.print(currentTemp);
Serial.print(" | Set=");
Serial.print(desiredTemp);
Serial.print(" | Error=");
Serial.print(error);
Serial.print(" | FuzzyPWM=");
Serial.print(fuzzyPWM);
Serial.print(" | DiscretePWM=");
Serial.print(pwmValue);
Serial.print(" | Level=");
Serial.println(level);
delay(1000);
}