#define START_STATE 0 #define PREHEAT_STATE 1 #define RAMP_UP_STATE 2 #define TAL_FIRST_STATE 3 #define PEAK_STATE 4 #define TAL_SECOND_STATE 5 #define RAMP_DOWN_STATE 6 #define END_STATE 7 #define ERROR_STATE 8 // error conditions #define E_DT_MIN 1 // temperatur dt too small #define E_DT_MAX 2 // temperatur dt too big #define E_TIME_MAX 4 // reflow process does take too long #define E_TL_TOO_LONG 8 // package was roasted #define E_TP_TOO_LONG 16 // package was roasted // system time, timestamps and temperatures from sensors __attribute__((__unused__)) static unsigned int time = 0; // profile seconds __attribute__((__unused__)) static unsigned int temperatur = 25; // actual oven temp __attribute__((__unused__)) static unsigned int last_temperatur = 25; // last oven temp __attribute__((__unused__)) static int actual_dt = 0; // actual difference from last to actual temperatur // profile temperatures __attribute__((__unused__)) static unsigned int Ts_min = 150; // °C __attribute__((__unused__)) static unsigned int Ts_max = 200; // °C __attribute__((__unused__)) static unsigned int Tl = 217; // 217°C __attribute__((__unused__)) static unsigned int Tp = 260; // 245-260°C __attribute__((__unused__)) static unsigned int time_max = 480; // 8*60s max // profile temp per second rates __attribute__((__unused__)) static unsigned int ramp_up_rate_min = 0; // not used yet __attribute__((__unused__)) static unsigned int ramp_up_rate_max = 50; // 3°C/s __attribute__((__unused__)) static unsigned int ramp_down_max = 6; // 6°C/s max __attribute__((__unused__)) static unsigned int ramp_down_min = 2; // 2°C/s max // profile temp durations __attribute__((__unused__)) static unsigned int Ts_duration = 100; // 60-180s __attribute__((__unused__)) static unsigned int Tl_duration = 100; // 60-150s __attribute__((__unused__)) static unsigned int Tp_duration = 30; // 20-40s // timestamps of event beginnings/ends __attribute__((__unused__)) static unsigned int Ts_min_time = 0; __attribute__((__unused__)) static unsigned int Ts_max_time = 0; __attribute__((__unused__)) static unsigned int Tl_time_start = 0; __attribute__((__unused__)) static unsigned int Tl_time_end = 0; __attribute__((__unused__)) static unsigned int Tp_time_start = 0; __attribute__((__unused__)) static unsigned int Tp_time_end = 0; // thermostat __attribute__((__unused__)) static unsigned int set_min = 0; __attribute__((__unused__)) static unsigned int set_max = 0; __attribute__((__unused__)) static int set_dt_min = 0; __attribute__((__unused__)) static int set_dt_max = 0; // state machine __attribute__((__unused__)) static byte state; __attribute__((__unused__)) static boolean is_oven_heating = false; __attribute__((__unused__)) static byte error_condition = 0; // ui stuff __attribute__((__unused__)) static boolean led_on = false; void setup() { Serial.begin(9600); delay(2000); set_start_state(); } static void control_oven() { if (temperatur < set_min && (!is_oven_heating)) { is_oven_heating = true; Serial.println("Oven turned on"); } else if (temperatur > set_max && is_oven_heating) { is_oven_heating = false; Serial.println("Oven turned off"); } } static void set_temp(int min, int max, int dt_min, int dt_max) { set_min = min; set_max = max; set_dt_min = dt_min; set_dt_max = dt_max; } static void get_temp() { last_temperatur = temperatur; temperatur = int(float(analogRead(2)) * 0.2929); actual_dt = temperatur - last_temperatur; } static void check_dt() { if (actual_dt > set_dt_max) { error_condition |= E_DT_MAX; } if (actual_dt < set_dt_min) { error_condition |= E_DT_MIN; } } static void print_debug() { Serial.print("Time: "); Serial.print(time); Serial.print(", temperatur: "); Serial.print(temperatur); Serial.print(", last_temperatur: "); Serial.print(last_temperatur); Serial.print(", state: "); Serial.print(state); Serial.print(", Error: "); Serial.println(error_condition); } boolean check_max_duration() { if (time > time_max) { error_condition |= E_TIME_MAX; return false; } } boolean check_Tl_duration() { if (time - Tl_time_start > Tp_duration) { error_condition |= E_TL_TOO_LONG; return false; } } boolean check_Tp_duration() { if (time - Tp_time_start > Tp_duration) { error_condition |= E_TP_TOO_LONG; return false; } } static void set_start_state() { state = START_STATE; get_temp(); last_temperatur = temperatur; set_temp(Tp-5, Tp, 0, ramp_up_rate_max); } static void set_preheat_state() { Serial.println("Changing state to PREHEAT_STATE"); state++; } static void set_ramp_up_state() { Serial.println("Changed state to RAMP_UP_STATE"); state++; } static void set_tal_first_state() { Serial.println("Changed state to TAL_FIRST_STATE"); state++; } static void set_peak_state() { Serial.println("Changed state to PEAK_STATE"); state++; } static void set_tal_second_state() { Serial.println("Changed state to TAL_SECOND_STATE"); set_temp(25, 25, -3, -6); state++; } static void set_ramp_down_state() { Serial.println("Changed state to RAMP_DOWN_STATE"); state++; } static void set_end_state() { Serial.println("Changed state to END_STATE"); state++; } void set_error_state() { if (state != ERROR_STATE) { Serial.println("Changed state to ERROR_STATE"); set_temp(0, 0, 0, 0); state = ERROR_STATE; } } static void handle_start_state() { if (temperatur > Ts_min) { Ts_min_time = time; set_preheat_state(); } } static void handle_preheat_state() { if (temperatur > Ts_max) { Ts_max_time = time; set_ramp_up_state(); } } static void handle_ramp_up_state() { if (temperatur > Tl) { Tl_time_start = time; set_tal_first_state(); } } static void handle_tal_first_state() { check_Tl_duration(); if (temperatur > Tp - 5) { Tp_time_start = time; set_peak_state(); } } static void handle_peak_state() { check_Tl_duration(); check_Tp_duration(); if (time - Tp_time_start > Tp_duration) { Tp_time_end = time; set_tal_second_state(); } } static void handle_tal_second_state() { check_Tl_duration(); if (temperatur < Tl) { set_ramp_down_state(); } } static void handle_ramp_down_state() { if (temperatur < Ts_min) { set_end_state(); } } static void handle_end_state() { while(true) { continue; } } static void handle_error_state() { if (led_on) { digitalWrite(13, LOW); led_on = false; } else { digitalWrite(13, HIGH); led_on = true; } if (error_condition & E_DT_MIN) Serial.println("Error: delta °K/second too low"); if (error_condition & E_DT_MAX) Serial.println("Error: delta °K/second too big"); if (error_condition & E_TIME_MAX) Serial.println("Error: reflow process does take too long"); if (error_condition & E_TL_TOO_LONG) Serial.println("Error: temperatur above liquidus was too long"); if (error_condition & E_TP_TOO_LONG) Serial.println("Error: peak temperature duration was too long"); } void loop() { time = millis() / 1000; get_temp(); check_dt(); check_max_duration(); if (error_condition) { set_error_state(); } else { print_debug(); } switch (state) { case START_STATE: handle_start_state(); break; case PREHEAT_STATE: handle_preheat_state(); break; case RAMP_UP_STATE: handle_ramp_up_state(); break; case TAL_FIRST_STATE: handle_tal_first_state(); break; case PEAK_STATE: handle_peak_state(); break; case TAL_SECOND_STATE: Tl_time_end = time; handle_tal_second_state(); break; case RAMP_DOWN_STATE: handle_ramp_down_state(); break; case END_STATE: handle_end_state(); break; case ERROR_STATE: handle_error_state(); break; default: break; } control_oven(); delay(1000); }