#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define KEY_MODE PA1
#define KEY_PUMP PA2
#define KEY_FAN PA3
#define KEY_LIGHT PA6
#define KEY_CURTAIN PA7
#define KEY_RESET PB5
#define RELAY_PUMP PB3
#define RELAY_FAN PB10
#define RELAY_LIGHT PB1
#define RELAY_CURTAIN PB4
#define DHT22_PIN PA4
#define DS18B20_PIN PA5
#define SOIL_MOIST PA9
#define LIGHT_PIN PA8
#define CO2_PIN PA0
#define LED_ALARM PB0
#define BUZZER_PIN PB11
#define OLED_SDA PB7
#define OLED_SCL PB6
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
DHT dht(DHT22_PIN, DHT22);
OneWire oneWire(DS18B20_PIN);
DallasTemperature sensors(&oneWire);
uint8_t work_mode = 0;
bool pump = false, fan = false, light = false, curtain = false;
unsigned long last_key_time = 0;
#define DEBOUNCE 200
const float T_opt_min = 18, T_opt_max = 28;
const float H_opt_min = 60, H_opt_max = 85;
const int L_opt_min = 1000, L_opt_max = 3000;
const int CO2_opt_min = 300, CO2_opt_max = 800;
const int SW_opt_min = 2000, SW_opt_max = 3200;
int scoreT(float t) {
if (t >= T_opt_min && t <= T_opt_max) return 100;
return t < T_opt_min ? constrain(map(t, 0, T_opt_min, 0, 100), 0, 100) : constrain(map(t, T_opt_max, 40, 100, 0), 0, 100);
}
int scoreH(float h) {
if (h >= H_opt_min && h <= H_opt_max) return 100;
return h < H_opt_min ? constrain(map(h, 0, H_opt_min, 0, 100), 0, 100) : constrain(map(h, H_opt_max, 100, 100, 0), 0, 100);
}
int scoreL(int l) {
if (l >= L_opt_min && l <= L_opt_max) return 100;
return l < L_opt_min ? constrain(map(l, 0, L_opt_min, 0, 100), 0, 100) : constrain(map(l, L_opt_max, 4095, 100, 0), 0, 100);
}
int scoreCO2(int c) {
if (c >= CO2_opt_min && c <= CO2_opt_max) return 100;
return c < CO2_opt_min ? constrain(map(c, 0, CO2_opt_min, 0, 100), 0, 100) : constrain(map(c, CO2_opt_max, 2000, 100, 0), 0, 100);
}
int scoreSW(int sw) {
if (sw >= SW_opt_min && sw <= SW_opt_max) return 100;
return sw < SW_opt_min ? constrain(map(sw, 0, SW_opt_min, 0, 100), 0, 100) : constrain(map(sw, SW_opt_max, 4095, 100, 0), 0, 100);
}
float calcScore(int ST, int SL, int SH, int SC, int SW) {
return 0.3*ST + 0.25*SL + 0.20*SH + 0.15*SC + 0.10*SW;
}
void setup() {
Serial.begin(115200);
pinMode(KEY_MODE, INPUT_PULLUP);
pinMode(KEY_PUMP, INPUT_PULLUP);
pinMode(KEY_FAN, INPUT_PULLUP);
pinMode(KEY_LIGHT, INPUT_PULLUP);
pinMode(KEY_CURTAIN, INPUT_PULLUP);
pinMode(KEY_RESET, INPUT_PULLUP);
pinMode(RELAY_PUMP, OUTPUT);
pinMode(RELAY_FAN, OUTPUT);
pinMode(RELAY_LIGHT, OUTPUT);
pinMode(RELAY_CURTAIN, OUTPUT);
pinMode(LED_ALARM, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(RELAY_PUMP, HIGH);
digitalWrite(RELAY_FAN, HIGH);
digitalWrite(RELAY_LIGHT, HIGH);
digitalWrite(RELAY_CURTAIN, HIGH);
digitalWrite(LED_ALARM, LOW);
digitalWrite(BUZZER_PIN, LOW);
dht.begin();
sensors.begin();
Wire.setSDA(PB7);
Wire.setSCL(PB6);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
}
void handleKeys() {
if (millis() - last_key_time < DEBOUNCE) return;
last_key_time = millis();
if (digitalRead(KEY_RESET) == LOW) {
work_mode = 0; pump = fan = light = curtain = false;
digitalWrite(RELAY_PUMP, HIGH);
digitalWrite(RELAY_FAN, HIGH);
digitalWrite(RELAY_LIGHT, HIGH);
digitalWrite(RELAY_CURTAIN, HIGH);
return;
}
if (digitalRead(KEY_MODE) == LOW) {
work_mode = !work_mode;
pump = fan = light = curtain = false;
digitalWrite(RELAY_PUMP, HIGH);
digitalWrite(RELAY_FAN, HIGH);
digitalWrite(RELAY_LIGHT, HIGH);
digitalWrite(RELAY_CURTAIN, HIGH);
}
if (work_mode == 1) {
if (digitalRead(KEY_PUMP) == LOW) { pump = !pump; digitalWrite(RELAY_PUMP, !pump); }
if (digitalRead(KEY_FAN) == LOW) { fan = !fan; digitalWrite(RELAY_FAN, !fan); }
if (digitalRead(KEY_LIGHT) == LOW) { light = !light; digitalWrite(RELAY_LIGHT, !light); }
if (digitalRead(KEY_CURTAIN) == LOW) { curtain = !curtain; digitalWrite(RELAY_CURTAIN, !curtain); }
}
}
void adaptiveControl(float S, float t, int l, int co2, int sw) {
if (work_mode == 1) return;
if (S < 70) {
fan = (t > T_opt_max);
light = (l < L_opt_min);
pump = (sw < SW_opt_min);
curtain = (co2 > CO2_opt_max);
} else if (S <= 85) {
fan = (t > 26);
light = (l < 1200);
pump = (sw < 2200);
curtain = (co2 > 800);
} else {
fan = (t > 28);
light = false;
pump = (sw < 2000);
curtain = false;
}
digitalWrite(RELAY_FAN, !fan);
digitalWrite(RELAY_LIGHT, !light);
digitalWrite(RELAY_PUMP, !pump);
digitalWrite(RELAY_CURTAIN, !curtain);
}
void alarm(float S) {
bool alarm = (S < 70);
digitalWrite(LED_ALARM, alarm);
digitalWrite(BUZZER_PIN, alarm);
}
// ===================== 无乱码极简显示(Wokwi完美支持) =====================
void showDisplay(float t, float h, int l, float S) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// 第1行:综合评分(核心)
display.setCursor(0, 0);
display.print("Score: ");
display.print(S, 1);
display.print("%");
// 第2行:温湿度+光照
display.setCursor(0, 16);
display.print("T:"); display.print(t, 1);
display.print(" H:"); display.print(h, 1);
display.print(" L:"); display.print(l);
// 第3行:模式
display.setCursor(0, 32);
display.print("Mode: ");
display.print(work_mode ? "Manual" : "Auto");
// 第4行:三级状态
display.setCursor(0, 48);
if (S < 70) display.print("State: ALARM");
else if (S <= 85) display.print("State: NORMAL");
else display.print("State: SAVING");
display.display();
}
void serialPrint(float t, float h, int l, float S) {
Serial.print("T:"); Serial.print(t, 1);
Serial.print(" H:"); Serial.print(h, 1);
Serial.print(" L:"); Serial.print(l);
Serial.print(" | Score: "); Serial.print(S, 1); Serial.print("%");
Serial.print(" | ");
if (S < 70) Serial.println("ALARM");
else if (S <= 85) Serial.println("NORMAL");
else Serial.println("SAVING");
}
void loop() {
float t = dht.readTemperature();
float h = dht.readHumidity();
sensors.requestTemperatures();
int sw = analogRead(SOIL_MOIST);
int co2 = analogRead(CO2_PIN);
int l = analogRead(LIGHT_PIN);
int ST = scoreT(t);
int SH = scoreH(h);
int SL = scoreL(l);
int SC = scoreCO2(co2);
int SW = scoreSW(sw);
float S = calcScore(ST, SL, SH, SC, SW);
handleKeys();
adaptiveControl(S, t, l, co2, sw);
alarm(S);
showDisplay(t, h, l, S);
serialPrint(t, h, l, S);
delay(200);
}Loading
stm32-bluepill
stm32-bluepill