Files
2026-08-07 17:36:15 +02:00

111 lines
4.8 KiB
C

#pragma once
// ---------------------------------------------------------------------------
// I2C — Nano default: A4 (SDA), A5 (SCL). Wire handles pin assignment.
// ---------------------------------------------------------------------------
static const uint8_t TCA9548A_ADDRESS = 0x70;
// Four SHT31 sensors on TCA9548A channels 2, 3, 4, 5
static const uint8_t SENSOR_CHANNELS[] = {2, 3, 4, 5};
static const uint8_t SENSOR_COUNT = sizeof(SENSOR_CHANNELS) / sizeof(SENSOR_CHANNELS[0]);
// SHT31 I2C address (ADDR pin low → 0x44, high → 0x45)
static const uint8_t SHT31_ADDRESS = 0x44;
// Bus timeout (Wire.setWireTimeout) — bounds a stuck I2C transaction so a
// glitch resets the TWI hardware instead of hanging the whole sketch.
static const uint32_t I2C_TIMEOUT_US = 25000UL;
// ---------------------------------------------------------------------------
// Outputs — D5 has hardware PWM; heater on A2 uses burst control (SSR-friendly)
// ---------------------------------------------------------------------------
static const uint8_t FAN_PIN = 5; // D5 — 24 V fan via N-channel MOSFET
static const uint8_t HEATER_PIN = A2; // heater via solid-state relay
// ---------------------------------------------------------------------------
// Temperature control
// ---------------------------------------------------------------------------
static const float TARGET_TEMP_C = 0.0f;
static const float AUTOTUNE_DEFAULT_TEMP_C = 40.0f;
static const float TARGET_MIN_C = 0.0f;
static const float TARGET_MAX_C = 80.0f;
// Hard ceiling (sensor / enclosure limit). Cutoff when regulating = target + CUTOFF_ABOVE_TARGET_C.
static const float EMERGENCY_ABSOLUTE_MAX_C = 95.0f;
static const float CUTOFF_ABOVE_TARGET_C = 12.0f;
static const float CUTOFF_RECOVERY_BAND_C = 5.0f;
static const float CORNER_STOP_MARGIN_C = 5.0f;
inline float emergencyCutoffForTarget(float targetC) {
if (targetC <= 0.0f) {
return EMERGENCY_ABSOLUTE_MAX_C;
}
float cutoff = targetC + CUTOFF_ABOVE_TARGET_C;
if (cutoff > EMERGENCY_ABSOLUTE_MAX_C) {
cutoff = EMERGENCY_ABSOLUTE_MAX_C;
}
return cutoff;
}
// Heat PI on average temp (no D term)
static const float HEAT_PI_KP = 4.0f;
static const float HEAT_PI_KI = 0.05f;
// Fixed circulation fan (~70%, fanchars winner); override with "fan <pwm>" when regulating
static const uint8_t FAN_STIR_PWM = 178;
// Legacy aliases for autotuner relay math only
static const float PID_KP = HEAT_PI_KP;
static const float PID_KI = HEAT_PI_KI;
static const float PID_KD = 0.0f;
static const float GOOD_SPREAD_C = 5.0f;
// Corner taper when avg is near target — keeps hottest sensor below emergency
static const float CORNER_LIMIT_BAND_C = 2.0f;
static const float MAX_TEMP_HEADROOM_C = 15.0f;
static const uint16_t HEATER_CYCLE_MS = 3000;
// Fan PWM — stir speed when target > 0; off below 40°C only when idle (target 0)
static const uint8_t FAN_IDLE_PWM = 77;
static const float IDLE_AUTO_FAN_OFF_TEMP_C = 40.0f;
static const uint8_t FAN_MAX_PWM = 255;
static const bool FAN_PWM_INVERT = true;
static const float SPREAD_EMA_ALPHA = 0.45f;
// PID auto-tune (relay method) — heat PI only
static const float AUTOTUNE_HYSTERESIS_C = 0.4f;
static const float AUTOTUNE_PREHEAT_BAND_C = 3.0f;
static const float AUTOTUNE_PREHEAT_DUTY = 100.0f;
static const uint8_t AUTOTUNE_PREHEAT_FAN_PWM = 0;
static const uint8_t AUTOTUNE_CYCLES_REQUIRED = 5;
static const uint32_t AUTOTUNE_PREHEAT_TIMEOUT_MS = 1200000UL;
static const uint32_t AUTOTUNE_RELAY_STALL_MS = 1500000UL;
static const uint32_t AUTOTUNE_SESSION_TIMEOUT_MS = 3600000UL;
static const uint32_t AUTOTUNE_RELAY_PERIOD_MAX_MS = 2400000UL;
// Fan characterize — fixed heater, sweep fan PWMs, pick lowest spread
static const float FANCHARS_MAX_CORNER_C = 60.0f;
static const float FANCHARS_COOL_AVG_C = 40.0f;
static const float FANCHARS_PRECOOL_MARGIN_C = 2.0f;
static const float FANCHARS_HEATER_PCT = 100.0f;
// Coarse sweep order: 30%, 100%, 60%, 80% fan
static const uint8_t FANCHARS_COARSE_PWM[] = {77, 255, 153, 204};
static const uint8_t FANCHARS_COARSE_COUNT =
sizeof(FANCHARS_COARSE_PWM) / sizeof(FANCHARS_COARSE_PWM[0]);
static const uint8_t FANCHARS_LIMIT_LOW_PWM = 77;
static const uint8_t FANCHARS_LIMIT_HIGH_PWM = 255;
static const uint8_t FANCHARS_MAX_RESULTS = FANCHARS_COARSE_COUNT + 1;
static const uint32_t FANCHARS_HOLD_MS = 60000UL;
static const uint32_t FANCHARS_HEAT_TIMEOUT_MS = 2700000UL;
static const uint32_t FANCHARS_COOLDOWN_TIMEOUT_MS = 2700000UL;
static const uint32_t FANCHARS_LOG_INTERVAL_MS = 1000UL;
// ---------------------------------------------------------------------------
// Timing
// ---------------------------------------------------------------------------
static const uint32_t SENSOR_READ_INTERVAL_MS = 1000;
static const uint32_t CONTROL_INTERVAL_MS = 500;
static const uint32_t SERIAL_REPORT_INTERVAL_MS = 2000;
static const bool LOG_CSV_DEFAULT = false;