Initial version of firmware
This commit is contained in:
		
						commit
						695aa4b3c2
					
				
							
								
								
									
										1
									
								
								barista/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								barista/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| build/ | ||||
							
								
								
									
										17
									
								
								barista/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								barista/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| PORT=/dev/ttyUSB0 | ||||
| FQBN=arduino:avr:atmega328bb | ||||
| OPTS=--no-color --log-level=info -v | ||||
| PROJ=barista | ||||
| BUILD=build/$(subst :,.,$(FQBN)) | ||||
| HEX=$(BUILD)/$(PROJ).ino.hex | ||||
| 
 | ||||
| all: $(HEX) | ||||
| 
 | ||||
| $(HEX): barista.ino | ||||
| 	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 | ||||
							
								
								
									
										351
									
								
								barista/barista.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								barista/barista.ino
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,351 @@ | ||||
| /* 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, | ||||
| }; | ||||
| 
 | ||||
| enum logic { | ||||
| 	ON = 1, | ||||
| 	OFF = 0, | ||||
| }; | ||||
| 
 | ||||
| #define DEBOUNCE_TIME 20L /* ms */ | ||||
| #define TEMP_MIN 600 | ||||
| #define TEMP_MAX 700 | ||||
| 
 | ||||
| #define LED_MIN_VALUE 0 | ||||
| 
 | ||||
| enum state { | ||||
| 	SLEEPING, | ||||
| 	DEBOUNCE, | ||||
| 	HEATING, | ||||
| 	HOT, | ||||
| 	BREWING, | ||||
| 	COOLING, | ||||
| }; | ||||
| 
 | ||||
| long debounce_t0 = 0; | ||||
| int state = SLEEPING; | ||||
| 
 | ||||
| enum button { | ||||
| 	BUTTON_ON = 0, | ||||
| 	BUTTON_HOT, | ||||
| 	MAX_BUTTON, | ||||
| }; | ||||
| 
 | ||||
| enum button_state { | ||||
| 	RESTING = 0, | ||||
| 	PRESSING, | ||||
| 	PRESSED, | ||||
| 	RELEASING, | ||||
| 	RELEASED, | ||||
| }; | ||||
| 
 | ||||
| enum buzz_state { | ||||
|   BUZZ_OFF = 0, | ||||
|   BUZZ_HEY, | ||||
|   BUZZ_STOP, | ||||
| }; | ||||
| 
 | ||||
| int buzz_state; | ||||
| 
 | ||||
| int button_pin[MAX_BUTTON] = { | ||||
| 	[BUTTON_ON] = PIN_POWER_ON, | ||||
| 	[BUTTON_HOT] = PIN_HOT, | ||||
| }; | ||||
| 
 | ||||
| int button_state[MAX_BUTTON]; | ||||
| unsigned long button_press_t0[MAX_BUTTON]; | ||||
| unsigned long button_release_t0[MAX_BUTTON]; | ||||
| 
 | ||||
| int read_input(int pin) | ||||
| { | ||||
| 	return !digitalRead(pin); | ||||
| } | ||||
| 
 | ||||
| void relay(int pin, enum logic st) | ||||
| { | ||||
|   /* 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); | ||||
| } | ||||
| 
 | ||||
| void update_buttons() | ||||
| { | ||||
| 	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(); | ||||
| 			} | ||||
| 		} 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 (st == PRESSED) { | ||||
| 			if (read_input(pin) != ON) { | ||||
| 				button_state[i] = RELEASING; | ||||
| 				button_release_t0[i] = 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 (st == RELEASED) { | ||||
| 			button_state[i] = RESTING; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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_idle_time    = 10000UL; /* 10 seconds */ | ||||
| 
 | ||||
| void progress() | ||||
| { | ||||
| 	int temp = analogRead(PIN_NTC); | ||||
| 	int on = (button_state[BUTTON_ON] == RELEASED); | ||||
| 	int hot = (button_state[BUTTON_HOT] == 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(" on="); | ||||
| 	Serial.print(on); | ||||
| 	Serial.print(" temp="); | ||||
| 	Serial.println(temp); | ||||
| 
 | ||||
|   /* Pressing ON cancels any operation */ | ||||
| 	if (state != SLEEPING && on) { | ||||
| 			state = SLEEPING; | ||||
|       return; | ||||
|   } | ||||
| 
 | ||||
| 	if (state == SLEEPING) { | ||||
| 		if (on) { | ||||
| 			state = HEATING; | ||||
|       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) { | ||||
| 		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"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void | ||||
| update_leds() | ||||
| { | ||||
|   static int r = 0; | ||||
|   static int g = 0; | ||||
| 
 | ||||
|   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 | ||||
| update_heater() | ||||
| { | ||||
|   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); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void | ||||
| update_pump() | ||||
| { | ||||
| 	if (state == BREWING) { | ||||
| 		relay(PIN_PUMP, ON); | ||||
|   } else { | ||||
| 		relay(PIN_PUMP, OFF); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void | ||||
| update_buzz() | ||||
| { | ||||
|   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; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void setup() | ||||
| { | ||||
| 	Serial.begin(9600); | ||||
| 	Serial.println("Booting"); | ||||
| 
 | ||||
| 	pinMode(PIN_POWER_ON, INPUT); | ||||
| 	pinMode(PIN_HOT, INPUT); | ||||
| 
 | ||||
| 	pinMode(PIN_LED_RED, OUTPUT); | ||||
| 	pinMode(PIN_LED_GREEN, OUTPUT); | ||||
| 	pinMode(PIN_HEAT, OUTPUT); | ||||
| 	pinMode(PIN_PUMP, OUTPUT); | ||||
| 
 | ||||
|   /* 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); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Rodrigo Arias Mallo
						Rodrigo Arias Mallo