// Smart Thermostat - Slice 4: CLI User Interface (DEBUG)
// Platform: STM32F103C8T6 Blue Pill (Wokwi)
// NTC → A0 | Heater LED → A1 | UART → A9/A10
// ─── Config ───
#define NTC_PIN A0
#define HEATER_PIN A1
#define BAUD_RATE 115200
#define PID_INTERVAL 1000
// ─── PID Parameters ───
#define KP 2.0
#define KI 0.5
#define KD 0.1
#define INTEGRAL_MAX 50.0
#define INTEGRAL_MIN -50.0
// ─── PID State ───
float setpoint = 25.0;
float integral = 0.0;
float lastError = 0.0;
float pidOutput = 0.0;
unsigned long lastPidTime = 0;
// ─── CLI State ───
String inputBuffer = "";
// ─── Temperature ───
float readTemperature() {
int raw = analogRead(NTC_PIN);
return 50.0 - (raw / 1023.0) * 60.0;
}
// ─── PID ───
float computePID(float current, float target, float dt) {
float error = target - current;
integral += error * dt;
if (integral > INTEGRAL_MAX) integral = INTEGRAL_MAX;
if (integral < INTEGRAL_MIN) integral = INTEGRAL_MIN;
float derivative = (error - lastError) / dt;
lastError = error;
float output = KP * error + KI * integral + KD * derivative;
if (output > 100.0) output = 100.0;
if (output < 0.0) output = 0.0;
return output;
}
// ─── CLI Command Handler ───
void processCommand(String cmd) {
cmd.trim();
if (cmd.length() == 0) return;
if (cmd.startsWith("SET_TEMP ")) {
String valStr = cmd.substring(9);
float val = valStr.toFloat();
if (val == 0.0 && valStr != "0" && valStr != "0.0") {
Serial.println("ERROR: Invalid temperature value");
return;
}
if (val < -10.0 || val > 50.0) {
Serial.println("ERROR: Temperature out of range (-10 ~ 50)");
return;
}
setpoint = val;
Serial.print("OK: Target set to ");
Serial.print(setpoint, 1);
Serial.println(" C");
} else if (cmd == "STATUS") {
float temp = readTemperature();
Serial.print("Temp: ");
Serial.print(temp, 1);
Serial.print(" C | Target: ");
Serial.print(setpoint, 1);
Serial.print(" C | PID: ");
Serial.print(pidOutput, 1);
Serial.println("%");
} else if (cmd == "HELP") {
Serial.println("Commands:");
Serial.println(" SET_TEMP <value> Set target temperature (-10~50)");
Serial.println(" STATUS Show current state");
Serial.println(" HELP Show this help");
} else {
Serial.print("ERROR: Unknown command '");
Serial.print(cmd);
Serial.println("'");
}
}
// ─── Serial RX (DEBUG VERSION) ───
void readSerial() {
while (Serial.available()) {
char c = (char)Serial.read();
Serial.print("[RX:");
Serial.print(c);
Serial.println("]");
if (c == '\n' || c == '\r') {
if (inputBuffer.length() > 0) {
processCommand(inputBuffer);
inputBuffer = "";
}
} else {
if (inputBuffer.length() < 64) {
inputBuffer += c;
}
}
}
}
// ─── Setup ───
void setup() {
Serial.begin(BAUD_RATE);
delay(100);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(HEATER_PIN, OUTPUT);
Serial.println("System OK");
Serial.println("Type HELP for commands");
}
// ─── Main Loop ───
void loop() {
readSerial();
unsigned long now = millis();
if (now - lastPidTime >= PID_INTERVAL) {
float dt = (now - lastPidTime) / 1000.0;
lastPidTime = now;
float temp = readTemperature();
pidOutput = computePID(temp, setpoint, dt);
int pwmVal = (int)(pidOutput * 255.0 / 100.0);
analogWrite(HEATER_PIN, pwmVal);
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Serial.print("Temp: ");
Serial.print(temp, 1);
Serial.print(" C | Target: ");
Serial.print(setpoint, 1);
Serial.print(" C | PID: ");
Serial.print(pidOutput, 1);
Serial.println("%");
}
}Loading
stm32-bluepill
stm32-bluepill