coffee/barista/heater.c
Rodrigo Arias Mallo 8502ee3c5c Implement PID thremostat controller
For now only the proportional (Kp) and derivative (Kd) components are
used, the integral term is 0.
2025-11-02 19:24:02 +01:00

71 lines
1.3 KiB
C

/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "heater.h"
#define HEATER_MIN 500UL /* ms */
#define HEATER_MAX 2000UL /* ms */
#define HEATER_PERIOD 5000UL /* ms */
void
heater_on(struct heater *h, unsigned long t_ms, float duty)
{
unsigned long dt_on = duty * HEATER_MAX;
if (dt_on < HEATER_MIN)
dt_on = 0;
else if (dt_on > HEATER_MAX)
dt_on = HEATER_MAX;
h->next_on_dt = dt_on;
if (h->st == HEATER_OFF) {
h->st = HEATER_ON;
h->t0_on = t_ms;
h->t0_off = t_ms + h->next_on_dt;
h->cycle = CYCLE_ON;
}
}
void
heater_off(struct heater *h)
{
h->st = HEATER_OFF;
}
int
heater_state(struct heater *h, unsigned long t_ms)
{
if (h->st == HEATER_OFF)
return 0;
/* Switch state if current time exceeds time limit
* in the current state */
/* FIXME: Integer overflow can cause the heater to turn on forever */
while (1) {
int changed = 0;
if (h->cycle == CYCLE_ON) {
if (t_ms >= h->t0_off) {
h->cycle = CYCLE_OFF;
h->t0_on += HEATER_PERIOD;
changed = 1;
}
} else if (h->cycle == CYCLE_OFF) {
if (t_ms >= h->t0_on) {
/* Compute current cycle t0_off */
h->cycle = CYCLE_ON;
h->t0_off = h->t0_on + h->next_on_dt;
changed = 1;
}
}
if (!changed)
break;
}
if (h->cycle == CYCLE_ON)
return 1;
return 0;
}