#include "oven_control.h" #include #include #include "profile.h" //Pin assignments for SainSmart LCD Keypad Shield LiquidCrystal _lcd(8, 9, 4, 5, 6, 7); DFR_Key _keypad; Profile _profile; OvenCtl::OvenCtl() { time = 0; temperature = 1; last_temperature = 1; actual_dt = 0; // timestamps of event beginnings/ends Ts_time_start = 0; Ts_time_end = 0; Tl_time_start = 0; Tl_time_end = 0; Tp_time_start = 0; Tp_time_end = 0; // thermostat set_min = 0; set_max = 0; set_dt_min = 0; set_dt_max = 0; state = 0; error_condition = 0; is_oven_heating = false; // ui stuff led_on = false; disable_checks = false; lcd = &_lcd; keypad = &_keypad; profile = &_profile; lcd->begin(16, 2); } void OvenCtl::reset() { digitalWrite(7, LOW); } void OvenCtl::send_state() { Serial.write(time & 0xff); Serial.write((time>>8) & 0xff); Serial.write(temperature & 0xff); Serial.write((temperature >> 8) & 0xff); Serial.write(last_temperature & 0xff); Serial.write((last_temperature >> 8) & 0xff); Serial.write(state & 0xff); Serial.write((state >> 8) & 0xff); Serial.write(error_condition & 0xff); Serial.write((error_condition >> 8) & 0xff); Serial.write(is_oven_heating); Serial.flush(); } void OvenCtl::send_config() { int tmp; for (int i=0;i < PI_END; i++) { tmp = profile->data[i]; Serial.write(tmp & 0xff); Serial.write((tmp >> 8 ) & 0xff); } Serial.flush(); } void OvenCtl::dispatch_input_config(int cmd) { if (cmd == 255) send_config(); else if (cmd == 254) recv_config(); else if (cmd == 250) reset(); else if (cmd == 253) ; } void OvenCtl::recv_config() { } void OvenCtl::handle_states() { int cmd = -1; if (state > 0) { time++; get_temp(); check_dt(); } if (error_condition != 0) { set_error_state(); } if (Serial.available() > 0) { cmd = Serial.read(); if (cmd == 255) send_config(); else if (cmd == 254) send_state(); else if (cmd == 253) recv_config(); else if (cmd == 252) reset(); else if (cmd == 251) set_start_state(); } switch (state) { case CONFIG_STATE: if (profile->handle_config_state(lcd, keypad)) set_start_state(); break; 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(); if (state > 0) { print_status(); delay(1000); } } void OvenCtl::print_status() { if (error_condition == 0) { String tmp("T: "); if (time < 10) tmp += "00"; else if (time < 100) tmp += "0"; tmp += time; tmp += " Tmp: "; if (temperature < 10) tmp += "00"; else if (temperature < 100) tmp += "0"; tmp += temperature; lcd->setCursor(0, 0); lcd->print(tmp); tmp = "Profile: "; tmp += state; tmp += "/"; tmp += END_STATE; lcd->setCursor(0, 1); lcd->print(tmp); lcd->setCursor(13, 1); if (is_oven_heating) lcd->print("on "); else lcd->print("off"); } else { lcd->clear(); lcd->print("Error:"); lcd->setCursor(0, 1); if (error_condition & E_DT_MIN) lcd->print("K/s too low"); if (error_condition & E_DT_MAX) lcd->print("K/s too high"); if (error_condition & E_TIME_MAX) lcd->print("reflow too long"); if (error_condition & E_TS_TOO_SHORT) lcd->print("ts too short"); if (error_condition & E_TS_TOO_LONG) lcd->print("ts too long"); if (error_condition & E_TL_TOO_SHORT) lcd->print("tal too short"); if (error_condition & E_TL_TOO_LONG) lcd->print("tal too long"); if (error_condition & E_TP_TOO_LONG) lcd->print("peak too short"); if (error_condition & E_TP_TOO_SHORT) lcd->print("peak too long"); } } void OvenCtl::control_oven() { if (temperature < set_min && !is_oven_heating) { is_oven_heating = true; // Serial.println("Oven turned on"); } else if (temperature > set_min && is_oven_heating) { is_oven_heating = false; } } void OvenCtl::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; } void OvenCtl::get_temp() { last_temperature = temperature; temperature = int(float(analogRead(2)) * 0.2929); actual_dt = temperature - last_temperature; } void OvenCtl::check_dt() { if (disable_checks) return; if (actual_dt > set_dt_max) { error_condition |= E_DT_MAX; } if (actual_dt < set_dt_min) { error_condition |= E_DT_MIN; } } void OvenCtl::check_max_duration() { if (disable_checks) return; if (time > profile->data[PI_TIME_MAX]) { error_condition |= E_TIME_MAX; } } void OvenCtl::check_Ts_duration_min() { if (disable_checks) return; Tl_time_end = time; if (time - Tl_time_start < profile->data[PI_TL_DURATION_MIN]) { error_condition |= E_TL_TOO_SHORT; } } void OvenCtl::check_Ts_duration_max() { if (disable_checks) return; if (time - Ts_time_start > profile->data[PI_TL_DURATION_MAX]) { error_condition |= E_TS_TOO_LONG; } } void OvenCtl::check_Tl_duration_min() { if (disable_checks) return; Tl_time_end = time; if (time - Tl_time_start < profile->data[PI_TL_DURATION_MIN]) { error_condition |= E_TL_TOO_SHORT; } } void OvenCtl::check_Tl_duration_max() { if (disable_checks) return; if (time - Tl_time_start > profile->data[PI_TL_DURATION_MAX]) { error_condition |= E_TL_TOO_LONG; } } void OvenCtl::check_Tp_duration_min() { Tp_time_end = time; if (time - Tp_time_start < profile->data[PI_TP_DURATION_MIN]) { error_condition |= E_TP_TOO_SHORT; } } void OvenCtl::check_Tp_duration_max() { if (disable_checks) return; if (time - Tp_time_start > profile->data[PI_TP_DURATION_MAX]) { error_condition |= E_TP_TOO_LONG; } } void OvenCtl::set_config_state() { profile->print_config_state_0(lcd); } void OvenCtl::set_start_state() { led_on = false; digitalWrite(13, LOW); error_condition = 0; state = START_STATE; get_temp(); last_temperature = temperature; actual_dt = temperature - last_temperature; set_temp(profile->data[PI_TP]-5, profile->data[PI_TP], 0, profile->data[PI_RAMP_UP_MAX]); lcd->clear(); } void OvenCtl::set_preheat_state() { // Serial.println("Changing state to PREHEAT_STATE"); state++; } void OvenCtl::set_ramp_up_state() { state++; } void OvenCtl::set_tal_first_state() { state++; } void OvenCtl::set_peak_state() { state++; } void OvenCtl::set_tal_second_state() { set_temp(0, 25, -3, -6); state++; } void OvenCtl::set_ramp_down_state() { state++; } void OvenCtl::set_end_state() { state++; } void OvenCtl::set_error_state() { if (state != ERROR_STATE) { set_temp(0, 0, 0, 0); state = ERROR_STATE; } } void OvenCtl::handle_config_state() { if (profile->handle_config_state(lcd, keypad)) state++; } void OvenCtl::handle_start_state() { check_max_duration(); if (temperature > profile->data[PI_TS_MIN]) { Ts_time_start = time; set_preheat_state(); } } void OvenCtl::handle_preheat_state() { check_Ts_duration_max(); check_max_duration(); if (temperature > profile->data[PI_TS_MAX]) { check_Ts_duration_min(); set_ramp_up_state(); } } void OvenCtl::handle_ramp_up_state() { check_max_duration(); if (temperature > profile->data[PI_TL]) { Tl_time_start = time; set_tal_first_state(); } } void OvenCtl::handle_tal_first_state() { check_max_duration(); check_Tl_duration_max(); if (temperature > profile->data[PI_TP] - 5) { Tp_time_start = time; set_peak_state(); } } void OvenCtl::handle_peak_state() { check_Tl_duration_max(); check_Tp_duration_max(); if (time - Tp_time_start > profile->data[PI_TP_DURATION_MAX]) { check_Tp_duration_min(); set_tal_second_state(); } } void OvenCtl::handle_tal_second_state() { check_Tl_duration_max(); if (temperature < profile->data[PI_TL]) { check_Tl_duration_min(); set_ramp_down_state(); } } void OvenCtl::handle_ramp_down_state() { if (temperature < profile->data[PI_TS_MIN]) { set_end_state(); } } void OvenCtl::handle_end_state() { } void OvenCtl::handle_error_state() { if (led_on) { digitalWrite(13, LOW); led_on = false; } else { digitalWrite(13, HIGH); led_on = true; } }