Compare commits
6 Commits
695aa4b3c2
...
90ea67cf08
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90ea67cf08 | ||
|
|
ebd47ee2c5 | ||
|
|
c2e823dfb5 | ||
|
|
2546447652 | ||
|
|
eaf4e9d814 | ||
|
|
9c114b136a |
2
barista/.gitignore
vendored
2
barista/.gitignore
vendored
@ -1 +1,3 @@
|
||||
build/
|
||||
test_ntc
|
||||
*.o
|
||||
|
||||
@ -1,17 +1,35 @@
|
||||
# Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
PORT=/dev/ttyUSB0
|
||||
FQBN=arduino:avr:atmega328bb
|
||||
OPTS=--no-color --log-level=info -v
|
||||
OPTS=--no-color --log-level=info
|
||||
#OPTS+=-v
|
||||
PROJ=barista
|
||||
BUILD=build/$(subst :,.,$(FQBN))
|
||||
HEX=$(BUILD)/$(PROJ).ino.hex
|
||||
|
||||
# For host test programs
|
||||
CPPFLAGS=-I.
|
||||
LIBS=-lm
|
||||
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): barista.ino
|
||||
$(HEX): barista.ino ntc.c ntc.h pinout.h
|
||||
arduino-cli compile $(OPTS) -e --fqbn $(FQBN)
|
||||
|
||||
upload: $(HEX)
|
||||
avrdude -vv -p atmega328p -c arduino -P $(PORT) -b 9600 -D -U flash:w:$(HEX):i
|
||||
|
||||
serial:
|
||||
picocom -b 115200 --lower-rts --lower-dtr /dev/ttyUSB0 --imap lfcrlf
|
||||
picocom -b 9600 --lower-rts --lower-dtr /dev/ttyUSB0 --imap lfcrlf
|
||||
|
||||
test: test_ntc
|
||||
|
||||
test_ntc: test/test_ntc.o ntc.o
|
||||
gcc $^ -o $@ $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f test/test_ntc.o ntc.o
|
||||
|
||||
.PHONY: test all clean
|
||||
|
||||
@ -1,64 +1,8 @@
|
||||
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
/*
|
||||
* ATmega328p
|
||||
* +---------+
|
||||
* (PCINT14/RESET) PC6 -|1 \_/ 28|- PC5 (ADC5/SCL/PCINT13)
|
||||
* (PCINT16/RXD) PD0 -|2 27|- PC4 (ADC4/SDA/PCINT12)
|
||||
* (PCINT17/TXD) PD1 -|3 26|- PC3 (ADC3/PCINT11)
|
||||
* (PCINT18/INT0) PD2 -|4 25|- PC2 (ADC2/PCINT10)
|
||||
* (PCINT19/OC2B/INT1) PD3 -|5 24|- PC1 (ADC1/PCINT9)
|
||||
* (PCINT20/XCK/T0) PD4 -|6 23|- PC0 (ADC0/PCINT8)
|
||||
* VCC -|7 22|- GND
|
||||
* GND -|8 21|- AREF
|
||||
* (PCINT6/XTAL1/TOSC1) PB6 -|9 20|- AVCC
|
||||
* (PCINT7/XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK/PCINT5)
|
||||
* (PCINT21/OC0B/T1) PD5 -|11 18|- PB4 (MISO/PCINT4)
|
||||
* (PCINT22/OC0A/AIN0) PD6 -|12 17|- PB3 (MOSI/OC2A/PCINT3)
|
||||
* (PCINT23/AIN1) PD7 -|13 16|- PB2 (SS/OC1B/PCINT2)
|
||||
* (PCINT0/CLKO/ICP1) PB0 -|14 15|- PB1 (OC1A/PCINT1)
|
||||
* +---------+
|
||||
*
|
||||
*
|
||||
* ATMEL ATMEGA8 & 168 / ARDUINO
|
||||
*
|
||||
* +-\/-+
|
||||
* PC6 1| |28 PC5 (AI 5)
|
||||
* (D 0) PD0 2| |27 PC4 (AI 4)
|
||||
* (D 1) PD1 3| |26 PC3 (AI 3)
|
||||
* (D 2) PD2 4| |25 PC2 (AI 2)
|
||||
* PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
|
||||
* (D 4) PD4 6| |23 PC0 (AI 0)
|
||||
* VCC 7| |22 GND
|
||||
* GND 8| |21 AREF
|
||||
* PB6 9| |20 AVCC
|
||||
* PB7 10| |19 PB5 (D 13)
|
||||
* PWM+ (D 5) PD5 11| |18 PB4 (D 12)
|
||||
* PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
|
||||
* (D 7) PD7 13| |16 PB2 (D 10) PWM
|
||||
* (D 8) PB0 14| |15 PB1 (D 9) PWM
|
||||
* +----+
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
enum pinout {
|
||||
/* Inputs */
|
||||
PIN_POWER_ON = 8,
|
||||
PIN_HOT = 9,
|
||||
//PIN_FLOW = PIN_D5,
|
||||
|
||||
/* Outputs */
|
||||
PIN_LED_GREEN = 5,
|
||||
PIN_LED_RED = 6,
|
||||
PIN_HEAT = 7,
|
||||
PIN_PUMP = 12,
|
||||
PIN_BUZZ = 10,
|
||||
|
||||
/* Analog */
|
||||
PIN_NTC = PIN_A0,
|
||||
};
|
||||
#include "ntc.h"
|
||||
#include "pinout.h"
|
||||
|
||||
enum logic {
|
||||
ON = 1,
|
||||
@ -66,13 +10,13 @@ enum logic {
|
||||
};
|
||||
|
||||
#define DEBOUNCE_TIME 20L /* ms */
|
||||
#define TEMP_MIN 600
|
||||
#define TEMP_MAX 700
|
||||
#define TEMP_MIN 40.0f /* C */
|
||||
#define TEMP_MAX 50.0f /* C */
|
||||
|
||||
#define LED_MIN_VALUE 0
|
||||
|
||||
enum state {
|
||||
SLEEPING,
|
||||
enum machine_state {
|
||||
SLEEPING = 0,
|
||||
DEBOUNCE,
|
||||
HEATING,
|
||||
HOT,
|
||||
@ -80,16 +24,15 @@ enum state {
|
||||
COOLING,
|
||||
};
|
||||
|
||||
long debounce_t0 = 0;
|
||||
int state = SLEEPING;
|
||||
//int state = SLEEPING;
|
||||
|
||||
enum button {
|
||||
BUTTON_ON = 0,
|
||||
BUTTON_HOT,
|
||||
MAX_BUTTON,
|
||||
enum btn_index {
|
||||
BTN_ON = 0,
|
||||
BTN_HOT,
|
||||
MAX_BTN,
|
||||
};
|
||||
|
||||
enum button_state {
|
||||
enum btn_state {
|
||||
RESTING = 0,
|
||||
PRESSING,
|
||||
PRESSED,
|
||||
@ -98,21 +41,48 @@ enum button_state {
|
||||
};
|
||||
|
||||
enum buzz_state {
|
||||
BUZZ_OFF = 0,
|
||||
BUZZ_HEY,
|
||||
BUZZ_STOP,
|
||||
BUZZ_OFF = 0,
|
||||
BUZZ_HEY,
|
||||
BUZZ_ACTIVE,
|
||||
};
|
||||
|
||||
int buzz_state;
|
||||
|
||||
int button_pin[MAX_BUTTON] = {
|
||||
[BUTTON_ON] = PIN_POWER_ON,
|
||||
[BUTTON_HOT] = PIN_HOT,
|
||||
int button_pin[MAX_BTN] = {
|
||||
[BTN_ON] = PIN_POWER_ON,
|
||||
[BTN_HOT] = PIN_HOT,
|
||||
};
|
||||
|
||||
int button_state[MAX_BUTTON];
|
||||
unsigned long button_press_t0[MAX_BUTTON];
|
||||
unsigned long button_release_t0[MAX_BUTTON];
|
||||
struct btn {
|
||||
enum btn_state state;
|
||||
unsigned long press_t0;
|
||||
unsigned long release_t0;
|
||||
};
|
||||
|
||||
struct input {
|
||||
unsigned long t_ms;
|
||||
int ntc_V;
|
||||
enum logic btn[MAX_BTN];
|
||||
} g_in;
|
||||
|
||||
#define MAX_SAMPLES 16
|
||||
|
||||
struct state {
|
||||
enum machine_state mstate;
|
||||
unsigned long brewing_t0;
|
||||
unsigned long cooling_t0;
|
||||
unsigned long heating_t0;
|
||||
unsigned long hot_t0;
|
||||
|
||||
int ntc_i; /* Next available place */
|
||||
float ntc_R;
|
||||
float ntc_last_T;
|
||||
float ntc_array_T[MAX_SAMPLES];
|
||||
float ntc_T; /* average */
|
||||
|
||||
struct btn btn[MAX_BTN];
|
||||
enum buzz_state buzz_state;
|
||||
unsigned long buzz_t0;
|
||||
} g_st;
|
||||
|
||||
int read_input(int pin)
|
||||
{
|
||||
@ -121,51 +91,79 @@ int read_input(int pin)
|
||||
|
||||
void relay(int pin, enum logic st)
|
||||
{
|
||||
/* Relays are active low */
|
||||
if (st == ON)
|
||||
digitalWrite(pin, 0);
|
||||
else
|
||||
digitalWrite(pin, 1);
|
||||
/* Relays are active low */
|
||||
if (st == ON)
|
||||
digitalWrite(pin, 0);
|
||||
else
|
||||
digitalWrite(pin, 1);
|
||||
}
|
||||
|
||||
void setled(int pin, enum logic st)
|
||||
{
|
||||
/* LEDs are active high */
|
||||
if (st == ON)
|
||||
digitalWrite(pin, 1);
|
||||
else
|
||||
digitalWrite(pin, 0);
|
||||
/* LEDs are active high */
|
||||
if (st == ON)
|
||||
digitalWrite(pin, 1);
|
||||
else
|
||||
digitalWrite(pin, 0);
|
||||
}
|
||||
|
||||
void update_buttons()
|
||||
void do_input(struct input *input)
|
||||
{
|
||||
for (int i = 0; i < MAX_BUTTON; i++) {
|
||||
int st = button_state[i];
|
||||
int pin = button_pin[i];
|
||||
if (st == RESTING) {
|
||||
if (read_input(pin) == ON) {
|
||||
button_state[i] = PRESSING;
|
||||
button_press_t0[i] = millis();
|
||||
input->t_ms = millis();
|
||||
|
||||
/* Read buttons */
|
||||
for (int i = 0; i < MAX_BTN; i++)
|
||||
input->btn[i] = read_input(button_pin[i]);
|
||||
|
||||
/* Read temperature sensor */
|
||||
input->ntc_V = analogRead(PIN_NTC);
|
||||
}
|
||||
|
||||
void proc_ntc(struct state *state, const struct input *input)
|
||||
{
|
||||
state->ntc_R = ntc_resistance(input->ntc_V);
|
||||
state->ntc_last_T = ntc_temp(state->ntc_R);
|
||||
state->ntc_array_T[state->ntc_i++] = state->ntc_last_T;
|
||||
if (state->ntc_i >= MAX_SAMPLES)
|
||||
state->ntc_i = 0;
|
||||
|
||||
float avg = 0;
|
||||
for (int i = 0; i < MAX_SAMPLES; i++)
|
||||
avg += state->ntc_array_T[i];
|
||||
|
||||
state->ntc_T = avg / MAX_SAMPLES;
|
||||
}
|
||||
|
||||
void proc_buttons(struct state *state, const struct input *input)
|
||||
{
|
||||
for (int i = 0; i < MAX_BTN; i++) {
|
||||
struct btn *btn = &state->btn[i];
|
||||
int v = input->btn[i];
|
||||
|
||||
if (btn->state == RESTING) {
|
||||
if (v == ON) {
|
||||
btn->state = PRESSING;
|
||||
btn->press_t0 = millis();
|
||||
}
|
||||
} else if (st == PRESSING) {
|
||||
if (read_input(pin) != ON) {
|
||||
button_state[i] = RESTING;
|
||||
} else if (millis() - button_press_t0[i] > DEBOUNCE_TIME) {
|
||||
button_state[i] = PRESSED;
|
||||
} else if (btn->state == PRESSING) {
|
||||
if (v != ON) {
|
||||
btn->state = RESTING;
|
||||
} else if (millis() - btn->press_t0 > DEBOUNCE_TIME) {
|
||||
btn->state = PRESSED;
|
||||
}
|
||||
} else if (st == PRESSED) {
|
||||
if (read_input(pin) != ON) {
|
||||
button_state[i] = RELEASING;
|
||||
button_release_t0[i] = millis();
|
||||
} else if (btn->state == PRESSED) {
|
||||
if (v != ON) {
|
||||
btn->state = RELEASING;
|
||||
btn->release_t0 = millis();
|
||||
}
|
||||
} else if (st == RELEASING) {
|
||||
if (read_input(pin) == ON) {
|
||||
button_state[i] = PRESSED;
|
||||
} else if (millis() - button_release_t0[i] > DEBOUNCE_TIME) {
|
||||
button_state[i] = RELEASED;
|
||||
} else if (btn->state == RELEASING) {
|
||||
if (v == ON) {
|
||||
btn->state = PRESSED;
|
||||
} else if (millis() - btn->release_t0 > DEBOUNCE_TIME) {
|
||||
btn->state = RELEASED;
|
||||
}
|
||||
} else if (st == RELEASED) {
|
||||
button_state[i] = RESTING;
|
||||
} else if (btn->state == RELEASED) {
|
||||
btn->state = RESTING;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,148 +172,156 @@ int red_min = 50;
|
||||
int red_state = red_min;
|
||||
unsigned long brewing_time = 3000UL; /* 3 seconds */
|
||||
unsigned long cooling_time = 3000UL; /* 3 seconds */
|
||||
unsigned long max_heating_time = 10000UL; /* 10 seconds */
|
||||
unsigned long max_heating_time = 60000UL; /* 60 seconds */
|
||||
unsigned long max_idle_time = 10000UL; /* 10 seconds */
|
||||
|
||||
void progress()
|
||||
void proc_machine(struct state *st)
|
||||
{
|
||||
int temp = analogRead(PIN_NTC);
|
||||
int on = (button_state[BUTTON_ON] == RELEASED);
|
||||
int hot = (button_state[BUTTON_HOT] == PRESSED);
|
||||
float temp = st->ntc_T;
|
||||
int on = (st->btn[BTN_ON].state == RELEASED);
|
||||
int hot = (st->btn[BTN_HOT].state == PRESSED);
|
||||
|
||||
static unsigned long brewing_t0 = 0;
|
||||
static unsigned long cooling_t0 = 0;
|
||||
static unsigned long heating_t0 = 0;
|
||||
static unsigned long hot_t0 = 0;
|
||||
|
||||
Serial.print("state=");
|
||||
Serial.print(state);
|
||||
Serial.print("t=");
|
||||
Serial.print(millis());
|
||||
Serial.print(" state=");
|
||||
Serial.print(st->mstate);
|
||||
Serial.print(" on=");
|
||||
Serial.print(on);
|
||||
Serial.print(" temp=");
|
||||
Serial.println(temp);
|
||||
Serial.print(temp);
|
||||
Serial.println(" C");
|
||||
|
||||
/* Pressing ON cancels any operation */
|
||||
if (state != SLEEPING && on) {
|
||||
state = SLEEPING;
|
||||
return;
|
||||
}
|
||||
/* Pressing ON cancels any operation */
|
||||
if (st->mstate != SLEEPING && on) {
|
||||
st->mstate = SLEEPING;
|
||||
st->buzz_state = BUZZ_OFF;
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == SLEEPING) {
|
||||
if (st->mstate == SLEEPING) {
|
||||
if (on) {
|
||||
state = HEATING;
|
||||
heating_t0 = millis();
|
||||
st->mstate = HEATING;
|
||||
st->heating_t0 = millis();
|
||||
Serial.println("heating");
|
||||
}
|
||||
} else if (state == HEATING) {
|
||||
if (temp > TEMP_MAX) {
|
||||
state = HOT;
|
||||
hot_t0 = millis();
|
||||
buzz_state = BUZZ_HEY;
|
||||
Serial.println("hot");
|
||||
} else if (millis() - heating_t0 > max_heating_time) {
|
||||
/* TODO: Add alarm state */
|
||||
state = SLEEPING;
|
||||
Serial.println("cannot heat, going to sleep");
|
||||
}
|
||||
} else if (state == HOT) {
|
||||
} else if (st->mstate == HEATING) {
|
||||
if (temp > TEMP_MAX) {
|
||||
st->mstate = HOT;
|
||||
st->hot_t0 = millis();
|
||||
st->buzz_state = BUZZ_HEY;
|
||||
Serial.println("hot");
|
||||
} else if (millis() - st->heating_t0 > max_heating_time) {
|
||||
/* TODO: Add alarm state */
|
||||
st->mstate = SLEEPING;
|
||||
Serial.println("cannot heat, going to sleep");
|
||||
}
|
||||
} else if (st->mstate == HOT) {
|
||||
if (hot) {
|
||||
state = BREWING;
|
||||
brewing_t0 = millis();
|
||||
Serial.println("brewing");
|
||||
} else if (millis() - hot_t0 > max_idle_time) {
|
||||
state = SLEEPING;
|
||||
Serial.println("idle timeout, going to sleep");
|
||||
}
|
||||
} else if (state == BREWING) {
|
||||
if (millis() - brewing_t0 > brewing_time) {
|
||||
state = COOLING;
|
||||
cooling_t0 = millis();
|
||||
Serial.println("cooling");
|
||||
}
|
||||
} else if (state == COOLING) {
|
||||
/* TODO: Wait a bit and go back to heating */
|
||||
if (millis() - cooling_t0 > cooling_time) {
|
||||
state = HEATING;
|
||||
heating_t0 = millis();
|
||||
Serial.println("heating");
|
||||
}
|
||||
}
|
||||
st->mstate = BREWING;
|
||||
st->brewing_t0 = millis();
|
||||
Serial.println("brewing");
|
||||
} else if (millis() - st->hot_t0 > max_idle_time) {
|
||||
st->mstate = SLEEPING;
|
||||
Serial.println("idle timeout, going to sleep");
|
||||
}
|
||||
} else if (st->mstate == BREWING) {
|
||||
if (millis() - st->brewing_t0 > brewing_time) {
|
||||
st->mstate = COOLING;
|
||||
st->cooling_t0 = millis();
|
||||
Serial.println("cooling");
|
||||
}
|
||||
} else if (st->mstate == COOLING) {
|
||||
/* TODO: Wait a bit and go back to heating */
|
||||
if (millis() - st->cooling_t0 > cooling_time) {
|
||||
st->mstate = HEATING;
|
||||
st->heating_t0 = millis();
|
||||
Serial.println("heating");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
update_leds()
|
||||
proc_buzz(struct state *st)
|
||||
{
|
||||
static int r = 0;
|
||||
static int g = 0;
|
||||
if (st->buzz_state == BUZZ_HEY) {
|
||||
tone(PIN_BUZZ, 1500);
|
||||
st->buzz_state = BUZZ_ACTIVE;
|
||||
st->buzz_t0 = millis();
|
||||
} else if (st->buzz_state == BUZZ_ACTIVE) {
|
||||
if (millis() - st->buzz_t0 > 20) {
|
||||
st->buzz_state = BUZZ_OFF;
|
||||
noTone(PIN_BUZZ);
|
||||
}
|
||||
} else {
|
||||
noTone(PIN_BUZZ);
|
||||
}
|
||||
}
|
||||
|
||||
if (state == HEATING || state == COOLING) {
|
||||
analogWrite(PIN_LED_RED, r);
|
||||
setled(PIN_LED_GREEN, 0);
|
||||
if (r >= 255)
|
||||
r = 0;
|
||||
else
|
||||
r += 3;
|
||||
} else if (state == HOT) {
|
||||
setled(PIN_LED_RED, 0);
|
||||
setled(PIN_LED_GREEN, 1);
|
||||
r = 0;
|
||||
} else if (state == BREWING) {
|
||||
setled(PIN_LED_RED, 0);
|
||||
analogWrite(PIN_LED_GREEN, g);
|
||||
if (g >= 255)
|
||||
g = 0;
|
||||
else
|
||||
g += 3;
|
||||
} else {
|
||||
setled(PIN_LED_RED, 0);
|
||||
setled(PIN_LED_GREEN, 0);
|
||||
r = 0;
|
||||
}
|
||||
void do_proc(struct state *st, const struct input *input)
|
||||
{
|
||||
proc_ntc(st, input);
|
||||
proc_buttons(st, input);
|
||||
proc_machine(st);
|
||||
proc_buzz(st);
|
||||
}
|
||||
|
||||
void
|
||||
update_heater()
|
||||
output_leds(const struct state *st)
|
||||
{
|
||||
if (state == HEATING || state == HOT || state == BREWING) {
|
||||
int temp = analogRead(PIN_NTC);
|
||||
if (temp < TEMP_MIN)
|
||||
relay(PIN_HEAT, ON);
|
||||
else if (temp > TEMP_MAX)
|
||||
relay(PIN_HEAT, OFF);
|
||||
} else {
|
||||
relay(PIN_HEAT, OFF);
|
||||
}
|
||||
static int r = 0;
|
||||
static int g = 0;
|
||||
|
||||
if (st->mstate == HEATING || st->mstate == COOLING) {
|
||||
analogWrite(PIN_LED_RED, r);
|
||||
setled(PIN_LED_GREEN, 0);
|
||||
if (r >= 255)
|
||||
r = 0;
|
||||
else
|
||||
r += 3;
|
||||
} else if (st->mstate == HOT) {
|
||||
setled(PIN_LED_RED, 0);
|
||||
setled(PIN_LED_GREEN, 1);
|
||||
r = 0;
|
||||
} else if (st->mstate == BREWING) {
|
||||
setled(PIN_LED_RED, 0);
|
||||
analogWrite(PIN_LED_GREEN, g);
|
||||
if (g >= 255)
|
||||
g = 0;
|
||||
else
|
||||
g += 3;
|
||||
} else {
|
||||
setled(PIN_LED_RED, 0);
|
||||
setled(PIN_LED_GREEN, 0);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
update_pump()
|
||||
output_heater(const struct state *st)
|
||||
{
|
||||
if (state == BREWING) {
|
||||
if (st->mstate == HEATING || st->mstate == HOT || st->mstate == BREWING) {
|
||||
if (st->ntc_T < TEMP_MIN)
|
||||
relay(PIN_HEAT, ON);
|
||||
else if (st->ntc_T > TEMP_MAX)
|
||||
relay(PIN_HEAT, OFF);
|
||||
} else {
|
||||
relay(PIN_HEAT, OFF);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
output_pump(const struct state *st)
|
||||
{
|
||||
if (st->mstate == BREWING)
|
||||
relay(PIN_PUMP, ON);
|
||||
} else {
|
||||
else
|
||||
relay(PIN_PUMP, OFF);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
update_buzz()
|
||||
void do_output(const struct state *st)
|
||||
{
|
||||
static unsigned long started = 0;
|
||||
|
||||
if (buzz_state == BUZZ_HEY) {
|
||||
tone(PIN_BUZZ, 1500);
|
||||
if (started == 0)
|
||||
started = millis();
|
||||
else if (millis() - started > 20) {
|
||||
buzz_state = BUZZ_OFF;
|
||||
}
|
||||
} else if (buzz_state == BUZZ_STOP) {
|
||||
tone(PIN_BUZZ, 220);
|
||||
} else if (buzz_state == BUZZ_OFF) {
|
||||
noTone(PIN_BUZZ);
|
||||
started = 0;
|
||||
}
|
||||
output_leds(st);
|
||||
output_heater(st);
|
||||
}
|
||||
|
||||
void setup()
|
||||
@ -331,21 +337,18 @@ void setup()
|
||||
pinMode(PIN_HEAT, OUTPUT);
|
||||
pinMode(PIN_PUMP, OUTPUT);
|
||||
|
||||
/* Turn all relays off */
|
||||
relay(PIN_HEAT, OFF);
|
||||
relay(PIN_PUMP, OFF);
|
||||
/* Turn all relays off */
|
||||
relay(PIN_HEAT, OFF);
|
||||
relay(PIN_PUMP, OFF);
|
||||
|
||||
Serial.println("Ready");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
//Serial.println("Looping...");
|
||||
update_buttons();
|
||||
progress();
|
||||
update_leds();
|
||||
update_heater();
|
||||
update_pump();
|
||||
update_buzz();
|
||||
delay(5);
|
||||
do_input(&g_in);
|
||||
do_proc(&g_st, &g_in);
|
||||
do_output(&g_st);
|
||||
|
||||
delay(5);
|
||||
}
|
||||
|
||||
44
barista/ntc.c
Normal file
44
barista/ntc.c
Normal file
@ -0,0 +1,44 @@
|
||||
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* Steinhart-Hart Thermistor Coefficients, used to convert resistance into
|
||||
* temperature.
|
||||
*
|
||||
* The current NTC sensor has 102kOhm at 24C but I don't know the specific
|
||||
* model, so the coefficients are computed for this NTC sensor instead:
|
||||
* https://www.tme.eu/Document/f9d2f5e38227fc1c7d979e546ff51768/NTCM-100K-B3950.pdf
|
||||
*
|
||||
* The table seems to match what I would expect. Their R2 resistor is 6.8 kOhm,
|
||||
* which yields a cuttof temperature of around 98.5 C at exactly half voltage
|
||||
* (where the ADC would have more precision).
|
||||
*
|
||||
* In any case, we can calibrate the original NTC sensor by taking three
|
||||
* temperature points. See:
|
||||
* https://www.thinksrs.com/downloads/programs/therm%20calc/ntccalibrator/ntccalculator.html
|
||||
*/
|
||||
#define C1 0.7740577674e-3
|
||||
#define C2 2.073449619e-4
|
||||
#define C3 1.263502259e-7
|
||||
|
||||
/* Return the temperature in celsisus */
|
||||
float
|
||||
ntc_temp(float R)
|
||||
{
|
||||
/* Computing the log is slow, we may want to build a table */
|
||||
float logR = log(R);
|
||||
float T = (1.0 / (C1 + C2*logR + C3*logR*logR*logR));
|
||||
float Tc = T - 273.15;
|
||||
return Tc;
|
||||
}
|
||||
|
||||
/* Return resistance in Ohms */
|
||||
float
|
||||
ntc_resistance(int Vo)
|
||||
{
|
||||
float R1 = 10.0e3; /* Resistor for voltage divider */
|
||||
float R2 = R1 * (1023.0 / (float)Vo - 1.0);
|
||||
|
||||
return R2;
|
||||
}
|
||||
18
barista/ntc.h
Normal file
18
barista/ntc.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#ifndef BARISTA_NTC_H
|
||||
#define BARISTA_NTC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
float ntc_resistance(int Vo);
|
||||
float ntc_temp(float omhs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BARISTA_NTC_H */
|
||||
78
barista/pinout.h
Normal file
78
barista/pinout.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* Copyright (c) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
#ifndef BARISTA_PINOUT_H
|
||||
#define BARISTA_PINOUT_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* ATmega328p
|
||||
* +---------+
|
||||
* (PCINT14/RESET) PC6 -|1 \_/ 28|- PC5 (ADC5/SCL/PCINT13)
|
||||
* (PCINT16/RXD) PD0 -|2 27|- PC4 (ADC4/SDA/PCINT12)
|
||||
* (PCINT17/TXD) PD1 -|3 26|- PC3 (ADC3/PCINT11)
|
||||
* (PCINT18/INT0) PD2 -|4 25|- PC2 (ADC2/PCINT10)
|
||||
* (PCINT19/OC2B/INT1) PD3 -|5 24|- PC1 (ADC1/PCINT9)
|
||||
* (PCINT20/XCK/T0) PD4 -|6 23|- PC0 (ADC0/PCINT8)
|
||||
* VCC -|7 22|- GND
|
||||
* GND -|8 21|- AREF
|
||||
* (PCINT6/XTAL1/TOSC1) PB6 -|9 20|- AVCC
|
||||
* (PCINT7/XTAL2/TOSC2) PB7 -|10 19|- PB5 (SCK/PCINT5)
|
||||
* (PCINT21/OC0B/T1) PD5 -|11 18|- PB4 (MISO/PCINT4)
|
||||
* (PCINT22/OC0A/AIN0) PD6 -|12 17|- PB3 (MOSI/OC2A/PCINT3)
|
||||
* (PCINT23/AIN1) PD7 -|13 16|- PB2 (SS/OC1B/PCINT2)
|
||||
* (PCINT0/CLKO/ICP1) PB0 -|14 15|- PB1 (OC1A/PCINT1)
|
||||
* +---------+
|
||||
*
|
||||
*
|
||||
* ATMEL ATMEGA8 & 168 / ARDUINO
|
||||
*
|
||||
* +-\/-+
|
||||
* PC6 1| |28 PC5 (AI 5)
|
||||
* (D 0) PD0 2| |27 PC4 (AI 4)
|
||||
* (D 1) PD1 3| |26 PC3 (AI 3)
|
||||
* (D 2) PD2 4| |25 PC2 (AI 2)
|
||||
* PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
|
||||
* (D 4) PD4 6| |23 PC0 (AI 0)
|
||||
* VCC 7| |22 GND
|
||||
* GND 8| |21 AREF
|
||||
* PB6 9| |20 AVCC
|
||||
* PB7 10| |19 PB5 (D 13)
|
||||
* PWM+ (D 5) PD5 11| |18 PB4 (D 12)
|
||||
* PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
|
||||
* (D 7) PD7 13| |16 PB2 (D 10) PWM
|
||||
* (D 8) PB0 14| |15 PB1 (D 9) PWM
|
||||
* +----+
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
enum pinout {
|
||||
/* Inputs */
|
||||
PIN_POWER_ON = 8,
|
||||
PIN_HOT = 9,
|
||||
//PIN_FLOW = PIN_D5,
|
||||
|
||||
/* Outputs */
|
||||
PIN_LED_GREEN = 5,
|
||||
PIN_LED_RED = 6,
|
||||
PIN_HEAT = 7,
|
||||
PIN_PUMP = 12,
|
||||
PIN_BUZZ = 10,
|
||||
|
||||
/* Analog */
|
||||
PIN_NTC = PIN_A0,
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BARISTA_PINOUT_H */
|
||||
1
barista/test/Makefile
Normal file
1
barista/test/Makefile
Normal file
@ -0,0 +1 @@
|
||||
test_ntc: test_ntc.o ../ntc.c
|
||||
15
barista/test/test_ntc.c
Normal file
15
barista/test/test_ntc.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#include "ntc.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
for (int i = 0; i <= 1023; i++) {
|
||||
float R = ntc_resistance(i);
|
||||
float T = ntc_temp(R);
|
||||
if (T < 96.0 || T > 100.2)
|
||||
continue;
|
||||
|
||||
printf("%6d %12.1f Ohm %12.1f C\n", i, R, T);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user