From 084f6b5b448cb9f67297dca40541127ea260f552 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 28 Apr 2016 18:18:13 -0700 Subject: [PATCH] Temperature singleton class --- Marlin/Marlin.h | 4 - Marlin/Marlin_main.cpp | 126 +++-- Marlin/cardreader.cpp | 2 +- Marlin/configuration_store.cpp | 58 ++- Marlin/dogm_lcd_implementation.h | 6 +- Marlin/endstops.cpp | 2 +- Marlin/planner.cpp | 19 +- Marlin/temperature.cpp | 382 ++++----------- Marlin/temperature.h | 435 ++++++++++++------ Marlin/ultralcd.cpp | 70 +-- .../ultralcd_implementation_hitachi_HD44780.h | 20 +- 11 files changed, 538 insertions(+), 586 deletions(-) diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index f6f488df84..4714601fa1 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -340,10 +340,6 @@ extern int16_t code_value_short(); extern uint8_t host_keepalive_interval; #endif -#if ENABLED(PREVENT_DANGEROUS_EXTRUDE) - extern float extrude_min_temp; -#endif - #if FAN_COUNT > 0 extern int fanSpeeds[FAN_COUNT]; #endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index fc05f174ac..0d2d9f5172 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -544,10 +544,6 @@ static void report_current_position(); } #endif -#if ENABLED(PREVENT_DANGEROUS_EXTRUDE) - float extrude_min_temp = EXTRUDE_MINTEMP; -#endif - #if ENABLED(SDSUPPORT) #include "SdFatUtil.h" int freeMemory() { return SdFatUtil::FreeRam(); } @@ -816,7 +812,7 @@ void setup() { lcd_init(); - tp_init(); // Initialize temperature loop + thermalManager.init(); // Initialize temperature loop #if ENABLED(DELTA) || ENABLED(SCARA) // Vital to init kinematic equivalent for X0 Y0 Z0 @@ -3839,7 +3835,7 @@ inline void gcode_M31() { SERIAL_ECHO_START; SERIAL_ECHOLN(time); lcd_setstatus(time); - autotempShutdown(); + thermalManager.autotempShutdown(); } #if ENABLED(SDSUPPORT) @@ -4274,10 +4270,10 @@ inline void gcode_M104() { if (code_seen('S')) { float temp = code_value(); - setTargetHotend(temp, target_extruder); + thermalManager.setTargetHotend(temp, target_extruder); #if ENABLED(DUAL_X_CARRIAGE) if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && target_extruder == 0) - setTargetHotend1(temp == 0.0 ? 0.0 : temp + duplicate_extruder_temp_offset); + thermalManager.setTargetHotend(temp == 0.0 ? 0.0 : temp + duplicate_extruder_temp_offset, 1); #endif /** @@ -4296,7 +4292,7 @@ inline void gcode_M104() { */ else print_job_timer.start(); - if (temp > degHotend(target_extruder)) LCD_MESSAGEPGM(MSG_HEATING); + if (temp > thermalManager.degHotend(target_extruder)) LCD_MESSAGEPGM(MSG_HEATING); } } @@ -4305,41 +4301,41 @@ inline void gcode_M104() { void print_heaterstates() { #if HAS_TEMP_HOTEND SERIAL_PROTOCOLPGM(" T:"); - SERIAL_PROTOCOL_F(degHotend(target_extruder), 1); + SERIAL_PROTOCOL_F(thermalManager.degHotend(target_extruder), 1); SERIAL_PROTOCOLPGM(" /"); - SERIAL_PROTOCOL_F(degTargetHotend(target_extruder), 1); + SERIAL_PROTOCOL_F(thermalManager.degTargetHotend(target_extruder), 1); #endif #if HAS_TEMP_BED SERIAL_PROTOCOLPGM(" B:"); - SERIAL_PROTOCOL_F(degBed(), 1); + SERIAL_PROTOCOL_F(thermalManager.degBed(), 1); SERIAL_PROTOCOLPGM(" /"); - SERIAL_PROTOCOL_F(degTargetBed(), 1); + SERIAL_PROTOCOL_F(thermalManager.degTargetBed(), 1); #endif #if EXTRUDERS > 1 for (int8_t e = 0; e < EXTRUDERS; ++e) { SERIAL_PROTOCOLPGM(" T"); SERIAL_PROTOCOL(e); SERIAL_PROTOCOLCHAR(':'); - SERIAL_PROTOCOL_F(degHotend(e), 1); + SERIAL_PROTOCOL_F(thermalManager.degHotend(e), 1); SERIAL_PROTOCOLPGM(" /"); - SERIAL_PROTOCOL_F(degTargetHotend(e), 1); + SERIAL_PROTOCOL_F(thermalManager.degTargetHotend(e), 1); } #endif #if HAS_TEMP_BED SERIAL_PROTOCOLPGM(" B@:"); #ifdef BED_WATTS - SERIAL_PROTOCOL(((BED_WATTS) * getHeaterPower(-1)) / 127); + SERIAL_PROTOCOL(((BED_WATTS) * thermalManager.getHeaterPower(-1)) / 127); SERIAL_PROTOCOLCHAR('W'); #else - SERIAL_PROTOCOL(getHeaterPower(-1)); + SERIAL_PROTOCOL(thermalManager.getHeaterPower(-1)); #endif #endif SERIAL_PROTOCOLPGM(" @:"); #ifdef EXTRUDER_WATTS - SERIAL_PROTOCOL(((EXTRUDER_WATTS) * getHeaterPower(target_extruder)) / 127); + SERIAL_PROTOCOL(((EXTRUDER_WATTS) * thermalManager.getHeaterPower(target_extruder)) / 127); SERIAL_PROTOCOLCHAR('W'); #else - SERIAL_PROTOCOL(getHeaterPower(target_extruder)); + SERIAL_PROTOCOL(thermalManager.getHeaterPower(target_extruder)); #endif #if EXTRUDERS > 1 for (int8_t e = 0; e < EXTRUDERS; ++e) { @@ -4347,27 +4343,27 @@ inline void gcode_M104() { SERIAL_PROTOCOL(e); SERIAL_PROTOCOLCHAR(':'); #ifdef EXTRUDER_WATTS - SERIAL_PROTOCOL(((EXTRUDER_WATTS) * getHeaterPower(e)) / 127); + SERIAL_PROTOCOL(((EXTRUDER_WATTS) * thermalManager.getHeaterPower(e)) / 127); SERIAL_PROTOCOLCHAR('W'); #else - SERIAL_PROTOCOL(getHeaterPower(e)); + SERIAL_PROTOCOL(thermalManager.getHeaterPower(e)); #endif } #endif #if ENABLED(SHOW_TEMP_ADC_VALUES) #if HAS_TEMP_BED SERIAL_PROTOCOLPGM(" ADC B:"); - SERIAL_PROTOCOL_F(degBed(), 1); + SERIAL_PROTOCOL_F(thermalManager.degBed(), 1); SERIAL_PROTOCOLPGM("C->"); - SERIAL_PROTOCOL_F(rawBedTemp() / OVERSAMPLENR, 0); + SERIAL_PROTOCOL_F(thermalManager.rawBedTemp() / OVERSAMPLENR, 0); #endif for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) { SERIAL_PROTOCOLPGM(" T"); SERIAL_PROTOCOL(cur_extruder); SERIAL_PROTOCOLCHAR(':'); - SERIAL_PROTOCOL_F(degHotend(cur_extruder), 1); + SERIAL_PROTOCOL_F(thermalManager.degHotend(cur_extruder), 1); SERIAL_PROTOCOLPGM("C->"); - SERIAL_PROTOCOL_F(rawHotendTemp(cur_extruder) / OVERSAMPLENR, 0); + SERIAL_PROTOCOL_F(thermalManager.rawHotendTemp(cur_extruder) / OVERSAMPLENR, 0); } #endif } @@ -4427,10 +4423,10 @@ inline void gcode_M109() { bool no_wait_for_cooling = code_seen('S'); if (no_wait_for_cooling || code_seen('R')) { float temp = code_value(); - setTargetHotend(temp, target_extruder); + thermalManager.setTargetHotend(temp, target_extruder); #if ENABLED(DUAL_X_CARRIAGE) if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && target_extruder == 0) - setTargetHotend1(temp == 0.0 ? 0.0 : temp + duplicate_extruder_temp_offset); + thermalManager.setTargetHotend(temp == 0.0 ? 0.0 : temp + duplicate_extruder_temp_offset, 1); #endif /** @@ -4449,7 +4445,7 @@ inline void gcode_M109() { */ else print_job_timer.start(); - if (temp > degHotend(target_extruder)) LCD_MESSAGEPGM(MSG_HEATING); + if (temp > thermalManager.degHotend(target_extruder)) LCD_MESSAGEPGM(MSG_HEATING); } #if ENABLED(AUTOTEMP) @@ -4462,7 +4458,7 @@ inline void gcode_M109() { #define TEMP_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + (TEMP_RESIDENCY_TIME) * 1000UL)) #else // Loop until the temperature is very close target - #define TEMP_CONDITIONS (wants_to_cool ? isCoolingHotend(target_extruder) : isHeatingHotend(target_extruder)) + #define TEMP_CONDITIONS (wants_to_cool ? thermalManager.isCoolingHotend(target_extruder) : thermalManager.isHeatingHotend(target_extruder)) #endif //TEMP_RESIDENCY_TIME > 0 float theTarget = -1; @@ -4473,7 +4469,6 @@ inline void gcode_M109() { KEEPALIVE_STATE(NOT_BUSY); do { - now = millis(); if (ELAPSED(now, next_temp_ms)) { //Print temp & remaining time every 1s while waiting next_temp_ms = now + 1000UL; @@ -4495,9 +4490,9 @@ inline void gcode_M109() { } // Target temperature might be changed during the loop - if (theTarget != degTargetHotend(target_extruder)) { - theTarget = degTargetHotend(target_extruder); - wants_to_cool = isCoolingHotend(target_extruder); + if (theTarget != thermalManager.degTargetHotend(target_extruder)) { + wants_to_cool = thermalManager.isCoolingHotend(target_extruder); + theTarget = thermalManager.degTargetHotend(target_extruder); // Exit if S, continue if S, R, or R if (no_wait_for_cooling && wants_to_cool) break; @@ -4512,7 +4507,7 @@ inline void gcode_M109() { #if TEMP_RESIDENCY_TIME > 0 - float temp_diff = fabs(theTarget - degHotend(target_extruder)); + float temp_diff = fabs(theTarget - thermalManager.degHotend(target_extruder)); if (!residency_start_ms) { // Start the TEMP_RESIDENCY_TIME timer when we reach target temp for the first time. @@ -4542,7 +4537,7 @@ inline void gcode_M109() { LCD_MESSAGEPGM(MSG_BED_HEATING); bool no_wait_for_cooling = code_seen('S'); - if (no_wait_for_cooling || code_seen('R')) setTargetBed(code_value()); + if (no_wait_for_cooling || code_seen('R')) thermalManager.setTargetBed(code_value()); #if TEMP_BED_RESIDENCY_TIME > 0 millis_t residency_start_ms = 0; @@ -4550,7 +4545,7 @@ inline void gcode_M109() { #define TEMP_BED_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + (TEMP_BED_RESIDENCY_TIME) * 1000UL)) #else // Loop until the temperature is very close target - #define TEMP_BED_CONDITIONS (wants_to_cool ? isCoolingBed() : isHeatingBed()) + #define TEMP_BED_CONDITIONS (wants_to_cool ? thermalManager.isCoolingBed() : thermalManager.isHeatingBed()) #endif //TEMP_BED_RESIDENCY_TIME > 0 float theTarget = -1; @@ -4580,16 +4575,16 @@ inline void gcode_M109() { } // Target temperature might be changed during the loop - if (theTarget != degTargetBed()) { - theTarget = degTargetBed(); - wants_to_cool = isCoolingBed(); + if (theTarget != thermalManager.degTargetBed()) { + wants_to_cool = thermalManager.isCoolingBed(); + theTarget = thermalManager.degTargetBed(); // Exit if S, continue if S, R, or R if (no_wait_for_cooling && wants_to_cool) break; // Prevent a wait-forever situation if R is misused i.e. M190 R0 - // Simply don't wait for cooling below 30C - if (wants_to_cool && theTarget < (EXTRUDE_MINTEMP)/2) break; + // Simply don't wait to cool a bed under 30C + if (wants_to_cool && theTarget < 30) break; } idle(); @@ -4597,7 +4592,7 @@ inline void gcode_M109() { #if TEMP_BED_RESIDENCY_TIME > 0 - float temp_diff = fabs(degBed() - degTargetBed()); + float temp_diff = fabs(theTarget - thermalManager.degBed()); if (!residency_start_ms) { // Start the TEMP_BED_RESIDENCY_TIME timer when we reach target temp for the first time. @@ -4720,7 +4715,7 @@ inline void gcode_M112() { kill(PSTR(MSG_KILLED)); } */ inline void gcode_M140() { if (DEBUGGING(DRYRUN)) return; - if (code_seen('S')) setTargetBed(code_value()); + if (code_seen('S')) thermalManager.setTargetBed(code_value()); } #if ENABLED(ULTIPANEL) @@ -4811,7 +4806,7 @@ inline void gcode_M140() { * This code should ALWAYS be available for EMERGENCY SHUTDOWN! */ inline void gcode_M81() { - disable_all_heaters(); + thermalManager.disable_all_heaters(); stepper.finish_and_disable(); #if FAN_COUNT > 0 #if FAN_COUNT > 1 @@ -5469,7 +5464,7 @@ inline void gcode_M226() { NOMORE(lpq_len, LPQ_MAX_LEN); #endif - updatePID(); + thermalManager.updatePID(); SERIAL_ECHO_START; #if ENABLED(PID_PARAMS_PER_EXTRUDER) SERIAL_ECHO(" e:"); // specify extruder in serial output @@ -5499,18 +5494,19 @@ inline void gcode_M226() { #if ENABLED(PIDTEMPBED) inline void gcode_M304() { - if (code_seen('P')) bedKp = code_value(); - if (code_seen('I')) bedKi = scalePID_i(code_value()); - if (code_seen('D')) bedKd = scalePID_d(code_value()); + if (code_seen('P')) thermalManager.bedKp = code_value(); + if (code_seen('I')) thermalManager.bedKi = scalePID_i(code_value()); + if (code_seen('D')) thermalManager.bedKd = scalePID_d(code_value()); + + thermalManager.updatePID(); - updatePID(); SERIAL_ECHO_START; SERIAL_ECHO(" p:"); - SERIAL_ECHO(bedKp); + SERIAL_ECHO(thermalManager.bedKp); SERIAL_ECHO(" i:"); - SERIAL_ECHO(unscalePID_i(bedKi)); + SERIAL_ECHO(unscalePID_i(thermalManager.bedKi)); SERIAL_ECHO(" d:"); - SERIAL_ECHOLN(unscalePID_d(bedKd)); + SERIAL_ECHOLN(unscalePID_d(thermalManager.bedKd)); } #endif // PIDTEMPBED @@ -5567,13 +5563,11 @@ inline void gcode_M226() { #if ENABLED(PREVENT_DANGEROUS_EXTRUDE) - void set_extrude_min_temp(float temp) { extrude_min_temp = temp; } - /** * M302: Allow cold extrudes, or set the minimum extrude S. */ inline void gcode_M302() { - set_extrude_min_temp(code_seen('S') ? code_value() : 0); + thermalManager.extrude_min_temp = code_seen('S') ? code_value() : 0; } #endif // PREVENT_DANGEROUS_EXTRUDE @@ -5599,7 +5593,7 @@ inline void gcode_M303() { KEEPALIVE_STATE(NOT_BUSY); // don't send "busy: processing" messages during autotune output - PID_autotune(temp, e, c, u); + thermalManager.PID_autotune(temp, e, c, u); KEEPALIVE_STATE(IN_HANDLER); #else @@ -5781,7 +5775,7 @@ inline void gcode_M400() { stepper.synchronize(); } NOMORE(meas_delay_cm, MAX_MEASUREMENT_DELAY); if (filwidth_delay_index2 == -1) { // Initialize the ring buffer if not done since startup - int temp_ratio = widthFil_to_size_ratio(); + int temp_ratio = thermalManager.widthFil_to_size_ratio(); for (uint8_t i = 0; i < COUNT(measurement_delay); ++i) measurement_delay[i] = temp_ratio - 100; // Subtract 100 to scale within a signed byte @@ -5984,7 +5978,7 @@ inline void gcode_M503() { */ inline void gcode_M600() { - if (degHotend(active_extruder) < extrude_min_temp) { + if (thermalManager.tooColdToExtrude(active_extruder)) { SERIAL_ERROR_START; SERIAL_ERRORLNPGM(MSG_TOO_COLD_FOR_M600); return; @@ -7268,7 +7262,7 @@ void mesh_buffer_line(float x, float y, float z, const float e, float feed_rate, if (DEBUGGING(DRYRUN)) return; float de = dest_e - curr_e; if (de) { - if (degHotend(active_extruder) < extrude_min_temp) { + if (thermalManager.tooColdToExtrude(active_extruder)) { curr_e = dest_e; // Behave as if the move really took place, but ignore E part SERIAL_ECHO_START; SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP); @@ -7565,7 +7559,7 @@ void plan_arc( millis_t ms = millis(); if (ELAPSED(ms, nextMotorCheck)) { nextMotorCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s - if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON || soft_pwm_bed > 0 + if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON || thermalManager.soft_pwm_bed > 0 || E0_ENABLE_READ == E_ENABLE_ON // If any of the drivers are enabled... #if EXTRUDERS > 1 || E1_ENABLE_READ == E_ENABLE_ON @@ -7683,9 +7677,9 @@ void plan_arc( if (ELAPSED(millis(), next_status_led_update_ms)) { next_status_led_update_ms += 500; // Update every 0.5s for (int8_t cur_extruder = 0; cur_extruder < EXTRUDERS; ++cur_extruder) - max_temp = max(max(max_temp, degHotend(cur_extruder)), degTargetHotend(cur_extruder)); + max_temp = max(max(max_temp, thermalManager.degHotend(cur_extruder)), thermalManager.degTargetHotend(cur_extruder)); #if HAS_TEMP_BED - max_temp = max(max(max_temp, degTargetBed()), degBed()); + max_temp = max(max(max_temp, thermalManager.degTargetBed()), thermalManager.degBed()); #endif bool new_led = (max_temp > 55.0) ? true : (max_temp < 54.0) ? false : red_led; if (new_led != red_led) { @@ -7726,7 +7720,7 @@ void idle( bool no_stepper_sleep/*=false*/ #endif ) { - manage_heater(); + thermalManager.manage_heater(); manage_inactivity( #if ENABLED(FILAMENTCHANGEENABLE) no_stepper_sleep @@ -7831,7 +7825,7 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) { #if ENABLED(EXTRUDER_RUNOUT_PREVENT) if (ELAPSED(ms, previous_cmd_ms + (EXTRUDER_RUNOUT_SECONDS) * 1000UL)) - if (degHotend(active_extruder) > EXTRUDER_RUNOUT_MINTEMP) { + if (thermalManager.degHotend(active_extruder) > EXTRUDER_RUNOUT_MINTEMP) { bool oldstatus; switch (active_extruder) { case 0: @@ -7914,7 +7908,7 @@ void kill(const char* lcd_msg) { #endif cli(); // Stop interrupts - disable_all_heaters(); + thermalManager.disable_all_heaters(); disable_all_steppers(); #if HAS_POWER_SWITCH @@ -8010,7 +8004,7 @@ void kill(const char* lcd_msg) { #endif // FAST_PWM_FAN void stop() { - disable_all_heaters(); + thermalManager.disable_all_heaters(); if (IsRunning()) { Running = false; Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 1e9aab3b66..2fead53823 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -609,7 +609,7 @@ void CardReader::printingHasFinished() { sdprinting = false; if (SD_FINISHED_STEPPERRELEASE) enqueue_and_echo_commands_P(PSTR(SD_FINISHED_RELEASECOMMAND)); - autotempShutdown(); + thermalManager.autotempShutdown(); } } diff --git a/Marlin/configuration_store.cpp b/Marlin/configuration_store.cpp index 8946156b11..0dbcd995b2 100644 --- a/Marlin/configuration_store.cpp +++ b/Marlin/configuration_store.cpp @@ -95,7 +95,7 @@ * 363 M301 L lpq_len (int) * * PIDTEMPBED: - * 365 M304 PID bedKp, bedKi, bedKd (float x3) + * 365 M304 PID thermalManager.bedKp, thermalManager.bedKi, thermalManager.bedKd (float x3) * * DOGLCD: * 377 M250 C lcd_contrast (int) @@ -261,9 +261,9 @@ void Config_StoreSettings() { #endif // !PIDTEMP { dummy = DUMMY_PID_VALUE; // When read, will not change the existing value - EEPROM_WRITE_VAR(i, dummy); + EEPROM_WRITE_VAR(i, dummy); // Kp dummy = 0.0f; - for (uint8_t q = 3; q--;) EEPROM_WRITE_VAR(i, dummy); + for (uint8_t q = 3; q--;) EEPROM_WRITE_VAR(i, dummy); // Ki, Kd, Kc } } // Extruders Loop @@ -274,13 +274,14 @@ void Config_StoreSettings() { EEPROM_WRITE_VAR(i, lpq_len); #if DISABLED(PIDTEMPBED) - float bedKp = DUMMY_PID_VALUE, bedKi = DUMMY_PID_VALUE, bedKd = DUMMY_PID_VALUE; + dummy = DUMMY_PID_VALUE; + for (uint8_t q = 3; q--;) EEPROM_WRITE_VAR(i, dummy); + #else + EEPROM_WRITE_VAR(i, thermalManager.bedKp); + EEPROM_WRITE_VAR(i, thermalManager.bedKi); + EEPROM_WRITE_VAR(i, thermalManager.bedKd); #endif - EEPROM_WRITE_VAR(i, bedKp); - EEPROM_WRITE_VAR(i, bedKi); - EEPROM_WRITE_VAR(i, bedKd); - #if DISABLED(HAS_LCD_CONTRAST) const int lcd_contrast = 32; #endif @@ -450,20 +451,17 @@ void Config_RetrieveSettings() { #endif EEPROM_READ_VAR(i, lpq_len); - #if DISABLED(PIDTEMPBED) - float bedKp, bedKi, bedKd; + #if ENABLED(PIDTEMPBED) + EEPROM_READ_VAR(i, dummy); // bedKp + if (dummy != DUMMY_PID_VALUE) { + thermalManager.bedKp = dummy; + EEPROM_READ_VAR(i, thermalManager.bedKi); + EEPROM_READ_VAR(i, thermalManager.bedKd); + } + #else + for (uint8_t q=3; q--;) EEPROM_READ_VAR(i, dummy); // bedKp, bedKi, bedKd #endif - EEPROM_READ_VAR(i, dummy); // bedKp - if (dummy != DUMMY_PID_VALUE) { - bedKp = dummy; UNUSED(bedKp); - EEPROM_READ_VAR(i, bedKi); - EEPROM_READ_VAR(i, bedKd); - } - else { - for (uint8_t q=2; q--;) EEPROM_READ_VAR(i, dummy); // bedKi, bedKd - } - #if DISABLED(HAS_LCD_CONTRAST) int lcd_contrast; #endif @@ -502,8 +500,8 @@ void Config_RetrieveSettings() { } calculate_volumetric_multipliers(); - // Call updatePID (similar to when we have processed M301) - updatePID(); + // Call thermalManager.updatePID (similar to when we have processed M301) + thermalManager.updatePID(); // Report settings retrieved and length SERIAL_ECHO_START; @@ -602,14 +600,14 @@ void Config_ResetDefault() { #if ENABLED(PID_ADD_EXTRUSION_RATE) lpq_len = 20; // default last-position-queue size #endif - // call updatePID (similar to when we have processed M301) - updatePID(); + // call thermalManager.updatePID (similar to when we have processed M301) + thermalManager.updatePID(); #endif // PIDTEMP #if ENABLED(PIDTEMPBED) - bedKp = DEFAULT_bedKp; - bedKi = scalePID_i(DEFAULT_bedKi); - bedKd = scalePID_d(DEFAULT_bedKd); + thermalManager.bedKp = DEFAULT_bedKp; + thermalManager.bedKi = scalePID_i(DEFAULT_bedKi); + thermalManager.bedKd = scalePID_d(DEFAULT_bedKd); #endif #if ENABLED(FWRETRACT) @@ -835,9 +833,9 @@ void Config_PrintSettings(bool forReplay) { #if ENABLED(PIDTEMPBED) CONFIG_ECHO_START; - SERIAL_ECHOPAIR(" M304 P", bedKp); - SERIAL_ECHOPAIR(" I", unscalePID_i(bedKi)); - SERIAL_ECHOPAIR(" D", unscalePID_d(bedKd)); + SERIAL_ECHOPAIR(" M304 P", thermalManager.bedKp); + SERIAL_ECHOPAIR(" I", unscalePID_i(thermalManager.bedKi)); + SERIAL_ECHOPAIR(" D", unscalePID_d(thermalManager.bedKd)); SERIAL_EOL; #endif diff --git a/Marlin/dogm_lcd_implementation.h b/Marlin/dogm_lcd_implementation.h index 3af19e15d4..89094bb00d 100644 --- a/Marlin/dogm_lcd_implementation.h +++ b/Marlin/dogm_lcd_implementation.h @@ -294,13 +294,13 @@ FORCE_INLINE void _draw_heater_status(int x, int heater) { const bool isBed = false; #endif - _draw_centered_temp((isBed ? degTargetBed() : degTargetHotend(heater)) + 0.5, x, 7); + _draw_centered_temp((isBed ? thermalManager.degTargetBed() : thermalManager.degTargetHotend(heater)) + 0.5, x, 7); - _draw_centered_temp((isBed ? degBed() : degHotend(heater)) + 0.5, x, 28); + _draw_centered_temp((isBed ? thermalManager.degBed() : thermalManager.degHotend(heater)) + 0.5, x, 28); int h = isBed ? 7 : 8, y = isBed ? 18 : 17; - if (isBed ? isHeatingBed() : isHeatingHotend(heater)) { + if (isBed ? thermalManager.isHeatingBed() : thermalManager.isHeatingHotend(heater)) { u8g.setColorIndex(0); // white on black u8g.drawBox(x + h, y, 2, 2); u8g.setColorIndex(1); // black on white diff --git a/Marlin/endstops.cpp b/Marlin/endstops.cpp index 8d0b0f979e..d08bf1a8aa 100644 --- a/Marlin/endstops.cpp +++ b/Marlin/endstops.cpp @@ -153,7 +153,7 @@ void Endstops::report_state() { card.sdprinting = false; card.closefile(); stepper.quick_stop(); - disable_all_heaters(); // switch off all heaters. + thermalManager.disable_all_heaters(); // switch off all heaters. } #endif } diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index 4fe8dee9fa..0beae32674 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -304,7 +304,7 @@ void Planner::recalculate() { static float oldt = 0; if (!autotemp_enabled) return; - if (degTargetHotend0() + 2 < autotemp_min) return; // probably temperature set to zero. + if (thermalManager.degTargetHotend(0) + 2 < autotemp_min) return; // probably temperature set to zero. float high = 0.0; for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) { @@ -322,7 +322,7 @@ void Planner::recalculate() { t += (AUTOTEMP_OLDWEIGHT) * oldt; } oldt = t; - setTargetHotend0(t); + thermalManager.setTargetHotend(t, 0); } #endif //AUTOTEMP @@ -489,11 +489,12 @@ void Planner::check_axes_activity() { // The target position of the tool in absolute steps // Calculate target position in absolute steps //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow - long target[NUM_AXIS]; - target[X_AXIS] = lround(x * axis_steps_per_unit[X_AXIS]); - target[Y_AXIS] = lround(y * axis_steps_per_unit[Y_AXIS]); - target[Z_AXIS] = lround(z * axis_steps_per_unit[Z_AXIS]); - target[E_AXIS] = lround(e * axis_steps_per_unit[E_AXIS]); + long target[NUM_AXIS] = { + lround(x * axis_steps_per_unit[X_AXIS]), + lround(y * axis_steps_per_unit[Y_AXIS]), + lround(z * axis_steps_per_unit[Z_AXIS]), + lround(e * axis_steps_per_unit[E_AXIS]) + }; long dx = target[X_AXIS] - position[X_AXIS], dy = target[Y_AXIS] - position[Y_AXIS], @@ -507,7 +508,7 @@ void Planner::check_axes_activity() { #if ENABLED(PREVENT_DANGEROUS_EXTRUDE) if (de) { - if (degHotend(extruder) < extrude_min_temp) { + if (thermalManager.tooColdToExtrude(extruder)) { position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part de = 0; // no difference SERIAL_ECHO_START; @@ -788,7 +789,7 @@ void Planner::check_axes_activity() { // If the index has changed (must have gone forward)... if (filwidth_delay_index1 != filwidth_delay_index2) { filwidth_e_count = 0; // Reset the E movement counter - int8_t meas_sample = widthFil_to_size_ratio() - 100; // Subtract 100 to reduce magnitude - to store in a signed char + int8_t meas_sample = thermalManager.widthFil_to_size_ratio() - 100; // Subtract 100 to reduce magnitude - to store in a signed char do { filwidth_delay_index2 = (filwidth_delay_index2 + 1) % MMD_CM; // The next unused slot measurement_delay[filwidth_delay_index2] = meas_sample; // Store the measurement diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index 3f5b2d1c53..1d71724521 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -21,24 +21,8 @@ */ /** - temperature.cpp - temperature control - Part of Marlin - - Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ + * temperature.cpp - temperature control + */ #include "Marlin.h" #include "ultralcd.h" @@ -50,144 +34,10 @@ #include "watchdog.h" #endif -//=========================================================================== -//================================== macros ================================= -//=========================================================================== - #ifdef K1 // Defined in Configuration.h in the PID settings #define K2 (1.0-K1) #endif -#if ENABLED(PIDTEMPBED) || ENABLED(PIDTEMP) - #define PID_dT ((OVERSAMPLENR * 12.0)/(F_CPU / 64.0 / 256.0)) -#endif - -//=========================================================================== -//============================= public variables ============================ -//=========================================================================== - -int target_temperature[4] = { 0 }; -int target_temperature_bed = 0; -int current_temperature_raw[4] = { 0 }; -float current_temperature[4] = { 0.0 }; -int current_temperature_bed_raw = 0; -float current_temperature_bed = 0.0; -#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT) - int redundant_temperature_raw = 0; - float redundant_temperature = 0.0; -#endif - -#if ENABLED(PIDTEMPBED) - float bedKp = DEFAULT_bedKp; - float bedKi = (DEFAULT_bedKi* PID_dT); - float bedKd = (DEFAULT_bedKd / PID_dT); -#endif //PIDTEMPBED - -#if ENABLED(FAN_SOFT_PWM) - unsigned char fanSpeedSoftPwm[FAN_COUNT]; -#endif - -unsigned char soft_pwm_bed; - -#if ENABLED(BABYSTEPPING) - volatile int babystepsTodo[3] = { 0 }; -#endif - -#if ENABLED(FILAMENT_WIDTH_SENSOR) - int current_raw_filwidth = 0; //Holds measured filament diameter - one extruder only -#endif - -#if ENABLED(THERMAL_PROTECTION_HOTENDS) || ENABLED(THERMAL_PROTECTION_BED) - enum TRState { TRReset, TRInactive, TRFirstHeating, TRStable, TRRunaway }; - void thermal_runaway_protection(TRState* state, millis_t* timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc); - #if ENABLED(THERMAL_PROTECTION_HOTENDS) - static TRState thermal_runaway_state_machine[4] = { TRReset, TRReset, TRReset, TRReset }; - static millis_t thermal_runaway_timer[4]; // = {0,0,0,0}; - #endif - #if ENABLED(THERMAL_PROTECTION_BED) && TEMP_SENSOR_BED != 0 - static TRState thermal_runaway_bed_state_machine = TRReset; - static millis_t thermal_runaway_bed_timer; - #endif -#endif - -//=========================================================================== -//============================ private variables ============================ -//=========================================================================== - -static volatile bool temp_meas_ready = false; - -#if ENABLED(PIDTEMP) - //static cannot be external: - static float temp_iState[EXTRUDERS] = { 0 }; - static float temp_dState[EXTRUDERS] = { 0 }; - static float pTerm[EXTRUDERS]; - static float iTerm[EXTRUDERS]; - static float dTerm[EXTRUDERS]; - #if ENABLED(PID_ADD_EXTRUSION_RATE) - static float cTerm[EXTRUDERS]; - static long last_position[EXTRUDERS]; - static long lpq[LPQ_MAX_LEN]; - static int lpq_ptr = 0; - #endif - //int output; - static float pid_error[EXTRUDERS]; - static float temp_iState_min[EXTRUDERS]; - static float temp_iState_max[EXTRUDERS]; - static bool pid_reset[EXTRUDERS]; -#endif //PIDTEMP -#if ENABLED(PIDTEMPBED) - //static cannot be external: - static float temp_iState_bed = { 0 }; - static float temp_dState_bed = { 0 }; - static float pTerm_bed; - static float iTerm_bed; - static float dTerm_bed; - //int output; - static float pid_error_bed; - static float temp_iState_min_bed; - static float temp_iState_max_bed; -#else //PIDTEMPBED - static millis_t next_bed_check_ms; -#endif //PIDTEMPBED -static unsigned char soft_pwm[EXTRUDERS]; - -#if ENABLED(FAN_SOFT_PWM) - static unsigned char soft_pwm_fan[FAN_COUNT]; -#endif -#if HAS_AUTO_FAN - static millis_t next_auto_fan_check_ms; -#endif - -#if ENABLED(PIDTEMP) - #if ENABLED(PID_PARAMS_PER_EXTRUDER) - float Kp[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(DEFAULT_Kp); - float Ki[EXTRUDERS] = ARRAY_BY_EXTRUDERS1((DEFAULT_Ki) * (PID_dT)); - float Kd[EXTRUDERS] = ARRAY_BY_EXTRUDERS1((DEFAULT_Kd) / (PID_dT)); - #if ENABLED(PID_ADD_EXTRUSION_RATE) - float Kc[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(DEFAULT_Kc); - #endif // PID_ADD_EXTRUSION_RATE - #else //PID_PARAMS_PER_EXTRUDER - float Kp = DEFAULT_Kp; - float Ki = (DEFAULT_Ki) * (PID_dT); - float Kd = (DEFAULT_Kd) / (PID_dT); - #if ENABLED(PID_ADD_EXTRUSION_RATE) - float Kc = DEFAULT_Kc; - #endif // PID_ADD_EXTRUSION_RATE - #endif // PID_PARAMS_PER_EXTRUDER -#endif //PIDTEMP - -// Init min and max temp with extreme values to prevent false errors during startup -static int minttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS(HEATER_0_RAW_LO_TEMP , HEATER_1_RAW_LO_TEMP , HEATER_2_RAW_LO_TEMP, HEATER_3_RAW_LO_TEMP); -static int maxttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS(HEATER_0_RAW_HI_TEMP , HEATER_1_RAW_HI_TEMP , HEATER_2_RAW_HI_TEMP, HEATER_3_RAW_HI_TEMP); -static int minttemp[EXTRUDERS] = { 0 }; -static int maxttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(16383); -#ifdef BED_MINTEMP - static int bed_minttemp_raw = HEATER_BED_RAW_LO_TEMP; -#endif -#ifdef BED_MAXTEMP - static int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP; -#endif - #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT) static void* heater_ttbl_map[2] = {(void*)HEATER_0_TEMPTABLE, (void*)HEATER_1_TEMPTABLE }; static uint8_t heater_ttbllen_map[2] = { HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN }; @@ -196,39 +46,11 @@ static int maxttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(16383); static uint8_t heater_ttbllen_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS(HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN, HEATER_2_TEMPTABLE_LEN, HEATER_3_TEMPTABLE_LEN); #endif -static float analog2temp(int raw, uint8_t e); -static float analog2tempBed(int raw); -static void updateTemperaturesFromRawValues(); - -#if ENABLED(THERMAL_PROTECTION_HOTENDS) && WATCH_TEMP_PERIOD > 0 - int watch_target_temp[EXTRUDERS] = { 0 }; - millis_t watch_heater_next_ms[EXTRUDERS] = { 0 }; -#endif - -#if ENABLED(THERMAL_PROTECTION_BED) && WATCH_BED_TEMP_PERIOD > 0 - int watch_target_bed_temp = 0; - millis_t watch_bed_next_ms = 0; -#endif - -#ifndef SOFT_PWM_SCALE - #define SOFT_PWM_SCALE 0 -#endif - -#if ENABLED(FILAMENT_WIDTH_SENSOR) - static int meas_shift_index; //used to point to a delayed sample in buffer for filament width sensor -#endif - -#if ENABLED(HEATER_0_USES_MAX6675) - static int read_max6675(); -#endif - -//=========================================================================== -//================================ Functions ================================ -//=========================================================================== +Temperature thermalManager; #if HAS_PID_HEATING - void PID_autotune(float temp, int extruder, int ncycles, bool set_result/*=false*/) { + void Temperature::PID_autotune(float temp, int extruder, int ncycles, bool set_result/*=false*/) { float input = 0.0; int cycles = 0; bool heating = true; @@ -242,7 +64,7 @@ static void updateTemperaturesFromRawValues(); float max = 0, min = 10000; #if HAS_AUTO_FAN - millis_t next_auto_fan_check_ms = temp_ms + 2500UL; + next_auto_fan_check_ms = temp_ms + 2500UL; #endif if (false @@ -459,9 +281,37 @@ static void updateTemperaturesFromRawValues(); } } -#endif // PIDTEMP +#endif // HAS_PID_HEATING + +#if ENABLED(PIDTEMP) + + #if ENABLED(PID_PARAMS_PER_EXTRUDER) + + float Temperature::Kp[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(DEFAULT_Kp), + Temperature::Ki[EXTRUDERS] = ARRAY_BY_EXTRUDERS1((DEFAULT_Ki) * (PID_dT)), + Temperature::Kd[EXTRUDERS] = ARRAY_BY_EXTRUDERS1((DEFAULT_Kd) / (PID_dT)); -void updatePID() { + #if ENABLED(PID_ADD_EXTRUSION_RATE) + float Temperature::Kc[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(DEFAULT_Kc); + #endif + + #else + + float Temperature::Kp = DEFAULT_Kp, + Temperature::Ki = (DEFAULT_Ki) * (PID_dT), + Temperature::Kd = (DEFAULT_Kd) / (PID_dT); + + #if ENABLED(PID_ADD_EXTRUSION_RATE) + float Temperature::Kc = DEFAULT_Kc; + #endif + + #endif + +#endif + +Temperature::Temperature() { } + +void Temperature::updatePID() { #if ENABLED(PIDTEMP) for (int e = 0; e < EXTRUDERS; e++) { temp_iState_max[e] = (PID_INTEGRAL_DRIVE_MAX) / PID_PARAM(Ki, e); @@ -475,85 +325,41 @@ void updatePID() { #endif } -int getHeaterPower(int heater) { +int Temperature::getHeaterPower(int heater) { return heater < 0 ? soft_pwm_bed : soft_pwm[heater]; } #if HAS_AUTO_FAN -void setExtruderAutoFanState(int pin, bool state) { - unsigned char newFanSpeed = (state != 0) ? EXTRUDER_AUTO_FAN_SPEED : 0; - // this idiom allows both digital and PWM fan outputs (see M42 handling). - digitalWrite(pin, newFanSpeed); - analogWrite(pin, newFanSpeed); -} - -void checkExtruderAutoFans() { - uint8_t fanState = 0; - - // which fan pins need to be turned on? - #if HAS_AUTO_FAN_0 - if (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE) - fanState |= 1; - #endif - #if HAS_AUTO_FAN_1 - if (current_temperature[1] > EXTRUDER_AUTO_FAN_TEMPERATURE) { - if (EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) - fanState |= 1; - else - fanState |= 2; + void Temperature::checkExtruderAutoFans() { + const uint8_t fanPin[] = { EXTRUDER_0_AUTO_FAN_PIN, EXTRUDER_1_AUTO_FAN_PIN, EXTRUDER_2_AUTO_FAN_PIN, EXTRUDER_3_AUTO_FAN_PIN }; + const int fanBit[] = { 0, + EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN ? 0 : 1, + EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN ? 0 : + EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN ? 1 : 2, + EXTRUDER_3_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN ? 0 : + EXTRUDER_3_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN ? 1 : + EXTRUDER_3_AUTO_FAN_PIN == EXTRUDER_2_AUTO_FAN_PIN ? 2 : 3 + }; + uint8_t fanState = 0; + for (int f = 0; f <= 3; f++) { + if (current_temperature[f] > EXTRUDER_AUTO_FAN_TEMPERATURE) + SBI(fanState, fanBit[f]); } - #endif - #if HAS_AUTO_FAN_2 - if (current_temperature[2] > EXTRUDER_AUTO_FAN_TEMPERATURE) { - if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) - fanState |= 1; - else if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) - fanState |= 2; - else - fanState |= 4; - } - #endif - #if HAS_AUTO_FAN_3 - if (current_temperature[3] > EXTRUDER_AUTO_FAN_TEMPERATURE) { - if (EXTRUDER_3_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) - fanState |= 1; - else if (EXTRUDER_3_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) - fanState |= 2; - else if (EXTRUDER_3_AUTO_FAN_PIN == EXTRUDER_2_AUTO_FAN_PIN) - fanState |= 4; - else - fanState |= 8; + for (int f = 0; f <= 3; f++) { + unsigned char newFanSpeed = TEST(fanState, f) ? EXTRUDER_AUTO_FAN_SPEED : 0; + // this idiom allows both digital and PWM fan outputs (see M42 handling). + digitalWrite(fanPin[f], newFanSpeed); + analogWrite(fanPin[f], newFanSpeed); } - #endif - - // update extruder auto fan states - #if HAS_AUTO_FAN_0 - setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, (fanState & 1) != 0); - #endif - #if HAS_AUTO_FAN_1 - if (EXTRUDER_1_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_1_AUTO_FAN_PIN, (fanState & 2) != 0); - #endif - #if HAS_AUTO_FAN_2 - if (EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN - && EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_2_AUTO_FAN_PIN, (fanState & 4) != 0); - #endif - #if HAS_AUTO_FAN_3 - if (EXTRUDER_3_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN - && EXTRUDER_3_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN - && EXTRUDER_3_AUTO_FAN_PIN != EXTRUDER_2_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_3_AUTO_FAN_PIN, (fanState & 8) != 0); - #endif -} + } #endif // HAS_AUTO_FAN // // Temperature Error Handlers // -inline void _temp_error(int e, const char* serial_msg, const char* lcd_msg) { +void Temperature::_temp_error(int e, const char* serial_msg, const char* lcd_msg) { static bool killed = false; if (IsRunning()) { SERIAL_ERROR_START; @@ -572,14 +378,14 @@ inline void _temp_error(int e, const char* serial_msg, const char* lcd_msg) { #endif } -void max_temp_error(uint8_t e) { +void Temperature::max_temp_error(uint8_t e) { _temp_error(e, PSTR(MSG_T_MAXTEMP), PSTR(MSG_ERR_MAXTEMP)); } -void min_temp_error(uint8_t e) { +void Temperature::min_temp_error(uint8_t e) { _temp_error(e, PSTR(MSG_T_MINTEMP), PSTR(MSG_ERR_MINTEMP)); } -float get_pid_output(int e) { +float Temperature::get_pid_output(int e) { float pid_output; #if ENABLED(PIDTEMP) #if DISABLED(PID_OPENLOOP) @@ -658,7 +464,7 @@ float get_pid_output(int e) { } #if ENABLED(PIDTEMPBED) - float get_pid_output_bed() { + float Temperature::get_pid_output_bed() { float pid_output; #if DISABLED(PID_OPENLOOP) pid_error_bed = target_temperature_bed - current_temperature_bed; @@ -710,7 +516,7 @@ float get_pid_output(int e) { * - Apply filament width to the extrusion rate (may move) * - Update the heated bed PID output value */ -void manage_heater() { +void Temperature::manage_heater() { if (!temp_meas_ready) return; @@ -811,7 +617,7 @@ void manage_heater() { #if TEMP_SENSOR_BED != 0 - #if ENABLED(THERMAL_PROTECTION_BED) + #if HAS_THERMALLY_PROTECTED_BED thermal_runaway_protection(&thermal_runaway_bed_state_machine, &thermal_runaway_bed_timer, current_temperature_bed, target_temperature_bed, -1, THERMAL_PROTECTION_BED_PERIOD, THERMAL_PROTECTION_BED_HYSTERESIS); #endif @@ -846,9 +652,10 @@ void manage_heater() { } #define PGM_RD_W(x) (short)pgm_read_word(&x) + // Derived from RepRap FiveD extruder::getTemperature() // For hot end temperature measurement. -static float analog2temp(int raw, uint8_t e) { +float Temperature::analog2temp(int raw, uint8_t e) { #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT) if (e > EXTRUDERS) #else @@ -891,7 +698,7 @@ static float analog2temp(int raw, uint8_t e) { // Derived from RepRap FiveD extruder::getTemperature() // For bed temperature measurement. -static float analog2tempBed(int raw) { +float Temperature::analog2tempBed(int raw) { #if ENABLED(BED_USES_THERMISTOR) float celsius = 0; byte i; @@ -923,18 +730,22 @@ static float analog2tempBed(int raw) { #endif } -/* Called to get the raw values into the the actual temperatures. The raw values are created in interrupt context, - and this function is called from normal context as it is too slow to run in interrupts and will block the stepper routine otherwise */ -static void updateTemperaturesFromRawValues() { +/** + * Get the raw values into the actual temperatures. + * The raw values are created in interrupt context, + * and this function is called from normal context + * as it would block the stepper routine. + */ +void Temperature::updateTemperaturesFromRawValues() { #if ENABLED(HEATER_0_USES_MAX6675) current_temperature_raw[0] = read_max6675(); #endif for (uint8_t e = 0; e < EXTRUDERS; e++) { - current_temperature[e] = analog2temp(current_temperature_raw[e], e); + current_temperature[e] = Temperature::analog2temp(current_temperature_raw[e], e); } - current_temperature_bed = analog2tempBed(current_temperature_bed_raw); + current_temperature_bed = Temperature::analog2tempBed(current_temperature_bed_raw); #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT) - redundant_temperature = analog2temp(redundant_temperature_raw, 1); + redundant_temperature = Temperature::analog2temp(redundant_temperature_raw, 1); #endif #if ENABLED(FILAMENT_WIDTH_SENSOR) filament_width_meas = analog2widthFil(); @@ -954,13 +765,13 @@ static void updateTemperaturesFromRawValues() { #if ENABLED(FILAMENT_WIDTH_SENSOR) // Convert raw Filament Width to millimeters - float analog2widthFil() { + float Temperature::analog2widthFil() { return current_raw_filwidth / 16383.0 * 5.0; //return current_raw_filwidth; } // Convert raw Filament Width to a ratio - int widthFil_to_size_ratio() { + int Temperature::widthFil_to_size_ratio() { float temp = filament_width_meas; if (temp < MEASURED_LOWER_LIMIT) temp = filament_width_nominal; //assume sensor cut out else NOMORE(temp, MEASURED_UPPER_LIMIT); @@ -974,7 +785,8 @@ static void updateTemperaturesFromRawValues() { * Initialize the temperature manager * The manager is implemented by periodic calls to manage_heater() */ -void tp_init() { +void Temperature::init() { + #if MB(RUMBA) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1)) //disable RUMBA JTAG in case the thermocouple extension is plugged on top of JTAG connector MCUCR = _BV(JTD); @@ -1189,7 +1001,7 @@ void tp_init() { * their target temperature by a configurable margin. * This is called when the temperature is set. (M104, M109) */ - void start_watching_heater(int e) { + void Temperature::start_watching_heater(int e) { if (degHotend(e) < degTargetHotend(e) - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1)) { watch_target_temp[e] = degHotend(e) + WATCH_TEMP_INCREASE; watch_heater_next_ms[e] = millis() + (WATCH_TEMP_PERIOD) * 1000UL; @@ -1205,7 +1017,7 @@ void tp_init() { * their target temperature by a configurable margin. * This is called when the temperature is set. (M140, M190) */ - void start_watching_bed() { + void Temperature::start_watching_bed() { if (degBed() < degTargetBed() - (WATCH_BED_TEMP_INCREASE + TEMP_BED_HYSTERESIS + 1)) { watch_target_bed_temp = degBed() + WATCH_BED_TEMP_INCREASE; watch_bed_next_ms = millis() + (WATCH_BED_TEMP_PERIOD) * 1000UL; @@ -1215,9 +1027,9 @@ void tp_init() { } #endif -#if ENABLED(THERMAL_PROTECTION_HOTENDS) || ENABLED(THERMAL_PROTECTION_BED) +#if ENABLED(THERMAL_PROTECTION_HOTENDS) || HAS_THERMALLY_PROTECTED_BED - void thermal_runaway_protection(TRState* state, millis_t* timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc) { + void Temperature::thermal_runaway_protection(TRState* state, millis_t* timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc) { static float tr_target_temperature[EXTRUDERS + 1] = { 0.0 }; @@ -1273,7 +1085,7 @@ void tp_init() { #endif // THERMAL_PROTECTION_HOTENDS || THERMAL_PROTECTION_BED -void disable_all_heaters() { +void Temperature::disable_all_heaters() { for (int i = 0; i < EXTRUDERS; i++) setTargetHotend(0, i); setTargetBed(0); @@ -1327,9 +1139,9 @@ void disable_all_heaters() { #define MAX6675_DISCARD_BITS 3 #endif - static millis_t next_max6675_ms = 0; + int Temperature::read_max6675() { - static int read_max6675() { + static millis_t next_max6675_ms = 0; millis_t ms = millis(); @@ -1392,10 +1204,10 @@ enum TempState { StartupDelay // Startup, delay initial temp reading a tiny bit so the hardware can settle }; -static unsigned long raw_temp_value[4] = { 0 }; -static unsigned long raw_temp_bed_value = 0; - -static void set_current_temp_raw() { +/** + * Get raw temperatures + */ +void Temperature::set_current_temp_raw() { #if HAS_TEMP_0 && DISABLED(HEATER_0_USES_MAX6675) current_temperature_raw[0] = raw_temp_value[0]; #endif @@ -1423,7 +1235,9 @@ static void set_current_temp_raw() { * - Check new temperature values for MIN/MAX errors * - Step the babysteps value for each axis towards 0 */ -ISR(TIMER0_COMPB_vect) { +ISR(TIMER0_COMPB_vect) { thermalManager.isr(); } + +void Temperature::isr() { static unsigned char temp_count = 0; static TempState temp_state = StartupDelay; @@ -1845,11 +1659,3 @@ ISR(TIMER0_COMPB_vect) { } #endif //BABYSTEPPING } - -#if ENABLED(PIDTEMP) - // Apply the scale factors to the PID values - float scalePID_i(float i) { return i * PID_dT; } - float unscalePID_i(float i) { return i / PID_dT; } - float scalePID_d(float d) { return d / PID_dT; } - float unscalePID_d(float d) { return d * PID_dT; } -#endif //PIDTEMP diff --git a/Marlin/temperature.h b/Marlin/temperature.h index c5754a590b..2e404ba805 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -21,182 +21,331 @@ */ /** - temperature.h - temperature controller - Part of Marlin - - Copyright (c) 2011 Erik van der Zalm - - Grbl is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Grbl is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grbl. If not, see . -*/ + * temperature.h - temperature controller + */ #ifndef TEMPERATURE_H #define TEMPERATURE_H #include "Marlin.h" #include "planner.h" + #if ENABLED(PID_ADD_EXTRUSION_RATE) #include "stepper.h" #endif -// public functions -void tp_init(); //initialize the heating -void manage_heater(); //it is critical that this is called periodically. +#ifndef SOFT_PWM_SCALE + #define SOFT_PWM_SCALE 0 +#endif -#if ENABLED(FILAMENT_WIDTH_SENSOR) - // For converting raw Filament Width to milimeters - float analog2widthFil(); +class Temperature { - // For converting raw Filament Width to an extrusion ratio - int widthFil_to_size_ratio(); -#endif + public: -// low level conversion routines -// do not use these routines and variables outside of temperature.cpp -extern int target_temperature[4]; -extern float current_temperature[4]; -#if ENABLED(SHOW_TEMP_ADC_VALUES) - extern int current_temperature_raw[4]; - extern int current_temperature_bed_raw; -#endif -extern int target_temperature_bed; -extern float current_temperature_bed; -#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT) - extern float redundant_temperature; -#endif + int current_temperature_raw[EXTRUDERS] = { 0 }; + float current_temperature[EXTRUDERS] = { 0.0 }; + int target_temperature[EXTRUDERS] = { 0 }; -#if HAS_CONTROLLERFAN - extern unsigned char soft_pwm_bed; -#endif + int current_temperature_bed_raw = 0; + float current_temperature_bed = 0.0; + int target_temperature_bed = 0; -#if ENABLED(FAN_SOFT_PWM) - extern unsigned char fanSpeedSoftPwm[FAN_COUNT]; -#endif + #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT) + float redundant_temperature = 0.0; + #endif -#if ENABLED(PIDTEMP) + unsigned char soft_pwm_bed; - #if ENABLED(PID_PARAMS_PER_EXTRUDER) - extern float Kp[EXTRUDERS], Ki[EXTRUDERS], Kd[EXTRUDERS]; // one param per extruder - #if ENABLED(PID_ADD_EXTRUSION_RATE) - extern float Kc[EXTRUDERS]; + #if ENABLED(FAN_SOFT_PWM) + unsigned char fanSpeedSoftPwm[FAN_COUNT]; #endif - #define PID_PARAM(param, e) param[e] // use macro to point to array value - #else - extern float Kp, Ki, Kd; // one param per extruder - saves 20 or 36 bytes of ram (inc array pointer) - #if ENABLED(PID_ADD_EXTRUSION_RATE) - extern float Kc; + + #if ENABLED(PIDTEMP) || ENABLED(PIDTEMPBED) + #define PID_dT ((OVERSAMPLENR * 12.0)/(F_CPU / 64.0 / 256.0)) #endif - #define PID_PARAM(param, e) param // use macro to point directly to value - #endif // PID_PARAMS_PER_EXTRUDER - float scalePID_i(float i); - float scalePID_d(float d); - float unscalePID_i(float i); - float unscalePID_d(float d); -#endif + #if ENABLED(PIDTEMP) -#if ENABLED(PIDTEMPBED) - extern float bedKp, bedKi, bedKd; -#endif + #if ENABLED(PID_PARAMS_PER_EXTRUDER) -#if ENABLED(BABYSTEPPING) - extern volatile int babystepsTodo[3]; -#endif + static float Kp[EXTRUDERS], Ki[EXTRUDERS], Kd[EXTRUDERS]; + #if ENABLED(PID_ADD_EXTRUSION_RATE) + float Kc[EXTRUDERS]; + #endif + #define PID_PARAM(param, e) Temperature::param[e] -//high level conversion routines, for use outside of temperature.cpp -//inline so that there is no performance decrease. -//deg=degreeCelsius + #else -FORCE_INLINE float degHotend(uint8_t extruder) { return current_temperature[extruder]; } -FORCE_INLINE float degBed() { return current_temperature_bed; } + static float Kp, Ki, Kd; + #if ENABLED(PID_ADD_EXTRUSION_RATE) + static float Kc; + #endif + #define PID_PARAM(param, e) Temperature::param -#if ENABLED(SHOW_TEMP_ADC_VALUES) -FORCE_INLINE float rawHotendTemp(uint8_t extruder) { return current_temperature_raw[extruder]; } -FORCE_INLINE float rawBedTemp() { return current_temperature_bed_raw; } -#endif + #endif // PID_PARAMS_PER_EXTRUDER -FORCE_INLINE float degTargetHotend(uint8_t extruder) { return target_temperature[extruder]; } -FORCE_INLINE float degTargetBed() { return target_temperature_bed; } + // Apply the scale factors to the PID values + #define scalePID_i(i) ( (i) * PID_dT ) + #define unscalePID_i(i) ( (i) / PID_dT ) + #define scalePID_d(d) ( (d) / PID_dT ) + #define unscalePID_d(d) ( (d) * PID_dT ) -#if ENABLED(THERMAL_PROTECTION_HOTENDS) && WATCH_TEMP_PERIOD > 0 - void start_watching_heater(int e = 0); -#endif + #endif -#if ENABLED(THERMAL_PROTECTION_BED) && WATCH_BED_TEMP_PERIOD > 0 - void start_watching_bed(); -#endif + #if ENABLED(PIDTEMPBED) + float bedKp = DEFAULT_bedKp, + bedKi = ((DEFAULT_bedKi) * PID_dT), + bedKd = ((DEFAULT_bedKd) / PID_dT); + #endif -FORCE_INLINE void setTargetHotend(const float& celsius, uint8_t extruder) { - target_temperature[extruder] = celsius; - #if ENABLED(THERMAL_PROTECTION_HOTENDS) && WATCH_TEMP_PERIOD > 0 - start_watching_heater(extruder); - #endif -} -FORCE_INLINE void setTargetBed(const float& celsius) { - target_temperature_bed = celsius; - #if ENABLED(THERMAL_PROTECTION_BED) && WATCH_BED_TEMP_PERIOD > 0 - start_watching_bed(); - #endif -} - -FORCE_INLINE bool isHeatingHotend(uint8_t extruder) { return target_temperature[extruder] > current_temperature[extruder]; } -FORCE_INLINE bool isHeatingBed() { return target_temperature_bed > current_temperature_bed; } - -FORCE_INLINE bool isCoolingHotend(uint8_t extruder) { return target_temperature[extruder] < current_temperature[extruder]; } -FORCE_INLINE bool isCoolingBed() { return target_temperature_bed < current_temperature_bed; } - -#define HOTEND_ROUTINES(NR) \ - FORCE_INLINE float degHotend##NR() { return degHotend(NR); } \ - FORCE_INLINE float degTargetHotend##NR() { return degTargetHotend(NR); } \ - FORCE_INLINE void setTargetHotend##NR(const float c) { setTargetHotend(c, NR); } \ - FORCE_INLINE bool isHeatingHotend##NR() { return isHeatingHotend(NR); } \ - FORCE_INLINE bool isCoolingHotend##NR() { return isCoolingHotend(NR); } -HOTEND_ROUTINES(0); -#if EXTRUDERS > 1 - HOTEND_ROUTINES(1); -#else - #define setTargetHotend1(c) do{}while(0) -#endif -#if EXTRUDERS > 2 - HOTEND_ROUTINES(2); -#else - #define setTargetHotend2(c) do{}while(0) -#endif -#if EXTRUDERS > 3 - HOTEND_ROUTINES(3); -#else - #define setTargetHotend3(c) do{}while(0) -#endif + #if ENABLED(BABYSTEPPING) + volatile int babystepsTodo[3] = { 0 }; + #endif -int getHeaterPower(int heater); -void disable_all_heaters(); -void updatePID(); + #if ENABLED(THERMAL_PROTECTION_HOTENDS) && WATCH_TEMP_PERIOD > 0 + int watch_target_temp[EXTRUDERS] = { 0 }; + millis_t watch_heater_next_ms[EXTRUDERS] = { 0 }; + #endif -#if ENABLED(PIDTEMP) - void PID_autotune(float temp, int extruder, int ncycles, bool set_result=false); -#endif + #if ENABLED(THERMAL_PROTECTION_HOTENDS) && WATCH_BED_TEMP_PERIOD > 0 + int watch_target_bed_temp = 0; + millis_t watch_bed_next_ms = 0; + #endif + + #if ENABLED(PREVENT_DANGEROUS_EXTRUDE) + float extrude_min_temp = EXTRUDE_MINTEMP; + FORCE_INLINE bool tooColdToExtrude(uint8_t e) { return degHotend(e) < extrude_min_temp; } + #else + FORCE_INLINE bool tooColdToExtrude(uint8_t e) { UNUSED(e); return false; } + #endif + + private: + + #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT) + int redundant_temperature_raw = 0; + float redundant_temperature = 0.0; + #endif + + volatile bool temp_meas_ready = false; + + #if ENABLED(PIDTEMP) + float temp_iState[EXTRUDERS] = { 0 }; + float temp_dState[EXTRUDERS] = { 0 }; + float pTerm[EXTRUDERS]; + float iTerm[EXTRUDERS]; + float dTerm[EXTRUDERS]; + + #if ENABLED(PID_ADD_EXTRUSION_RATE) + float cTerm[EXTRUDERS]; + long last_position[EXTRUDERS]; + long lpq[LPQ_MAX_LEN]; + int lpq_ptr = 0; + #endif + + float pid_error[EXTRUDERS]; + float temp_iState_min[EXTRUDERS]; + float temp_iState_max[EXTRUDERS]; + bool pid_reset[EXTRUDERS]; + #endif + + #if ENABLED(PIDTEMPBED) + float temp_iState_bed = { 0 }; + float temp_dState_bed = { 0 }; + float pTerm_bed; + float iTerm_bed; + float dTerm_bed; + float pid_error_bed; + float temp_iState_min_bed; + float temp_iState_max_bed; + #else + millis_t next_bed_check_ms; + #endif -void setExtruderAutoFanState(int pin, bool state); -void checkExtruderAutoFans(); + unsigned long raw_temp_value[4] = { 0 }; + unsigned long raw_temp_bed_value = 0; + + // Init min and max temp with extreme values to prevent false errors during startup + int minttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS(HEATER_0_RAW_LO_TEMP , HEATER_1_RAW_LO_TEMP , HEATER_2_RAW_LO_TEMP, HEATER_3_RAW_LO_TEMP); + int maxttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS(HEATER_0_RAW_HI_TEMP , HEATER_1_RAW_HI_TEMP , HEATER_2_RAW_HI_TEMP, HEATER_3_RAW_HI_TEMP); + int minttemp[EXTRUDERS] = { 0 }; + int maxttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(16383); + + #ifdef BED_MINTEMP + int bed_minttemp_raw = HEATER_BED_RAW_LO_TEMP; + #endif + + #ifdef BED_MAXTEMP + int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP; + #endif + + #if ENABLED(FILAMENT_WIDTH_SENSOR) + int meas_shift_index; // Index of a delayed sample in buffer + #endif + + #if HAS_AUTO_FAN + millis_t next_auto_fan_check_ms; + #endif + + unsigned char soft_pwm[EXTRUDERS]; + + #if ENABLED(FAN_SOFT_PWM) + unsigned char soft_pwm_fan[FAN_COUNT]; + #endif -FORCE_INLINE void autotempShutdown() { - #if ENABLED(AUTOTEMP) - if (planner.autotemp_enabled) { - planner.autotemp_enabled = false; - if (degTargetHotend(active_extruder) > planner.autotemp_min) - setTargetHotend(0, active_extruder); + #if ENABLED(FILAMENT_WIDTH_SENSOR) + int current_raw_filwidth = 0; //Holds measured filament diameter - one extruder only + #endif + + public: + + /** + * Static (class) methods + */ + static float analog2temp(int raw, uint8_t e); + static float analog2tempBed(int raw); + + /** + * Instance Methods + */ + + Temperature(); + + void init(); + + /** + * Called from the Temperature ISR + */ + void isr(); + + /** + * Call periodically to manage heaters + */ + void manage_heater(); + + #if ENABLED(FILAMENT_WIDTH_SENSOR) + float analog2widthFil(); // Convert raw Filament Width to millimeters + int widthFil_to_size_ratio(); // Convert raw Filament Width to an extrusion ratio + #endif + + + //high level conversion routines, for use outside of temperature.cpp + //inline so that there is no performance decrease. + //deg=degreeCelsius + + FORCE_INLINE float degHotend(uint8_t extruder) { return current_temperature[extruder]; } + FORCE_INLINE float degBed() { return current_temperature_bed; } + + #if ENABLED(SHOW_TEMP_ADC_VALUES) + FORCE_INLINE float rawHotendTemp(uint8_t extruder) { return current_temperature_raw[extruder]; } + FORCE_INLINE float rawBedTemp() { return current_temperature_bed_raw; } + #endif + + FORCE_INLINE float degTargetHotend(uint8_t extruder) { return target_temperature[extruder]; } + FORCE_INLINE float degTargetBed() { return target_temperature_bed; } + + #if ENABLED(THERMAL_PROTECTION_HOTENDS) && WATCH_TEMP_PERIOD > 0 + void start_watching_heater(int e = 0); + #endif + + #if ENABLED(THERMAL_PROTECTION_BED) && WATCH_BED_TEMP_PERIOD > 0 + void start_watching_bed(); + #endif + + FORCE_INLINE void setTargetHotend(const float& celsius, uint8_t extruder) { + target_temperature[extruder] = celsius; + #if ENABLED(THERMAL_PROTECTION_HOTENDS) && WATCH_TEMP_PERIOD > 0 + start_watching_heater(extruder); + #endif + } + + FORCE_INLINE void setTargetBed(const float& celsius) { + target_temperature_bed = celsius; + #if ENABLED(THERMAL_PROTECTION_BED) && WATCH_BED_TEMP_PERIOD > 0 + start_watching_bed(); + #endif } - #endif -} + + FORCE_INLINE bool isHeatingHotend(uint8_t extruder) { return target_temperature[extruder] > current_temperature[extruder]; } + FORCE_INLINE bool isHeatingBed() { return target_temperature_bed > current_temperature_bed; } + + FORCE_INLINE bool isCoolingHotend(uint8_t extruder) { return target_temperature[extruder] < current_temperature[extruder]; } + FORCE_INLINE bool isCoolingBed() { return target_temperature_bed < current_temperature_bed; } + + /** + * The software PWM power for a heater + */ + int getHeaterPower(int heater); + + /** + * Switch off all heaters, set all target temperatures to 0 + */ + void disable_all_heaters(); + + /** + * Perform auto-tuning for hotend or bed in response to M303 + */ + #if HAS_PID_HEATING + void PID_autotune(float temp, int extruder, int ncycles, bool set_result=false); + #endif + + /** + * Update the temp manager when PID values change + */ + void updatePID(); + + FORCE_INLINE void autotempShutdown() { + #if ENABLED(AUTOTEMP) + if (planner.autotemp_enabled) { + planner.autotemp_enabled = false; + if (degTargetHotend(active_extruder) > planner.autotemp_min) + setTargetHotend(0, active_extruder); + } + #endif + } + + private: + + void set_current_temp_raw(); + + void updateTemperaturesFromRawValues(); + + #if ENABLED(HEATER_0_USES_MAX6675) + int read_max6675(); + #endif + + void setExtruderAutoFanState(int pin, bool state); + void checkExtruderAutoFans(); + + float get_pid_output(int e); + + #if ENABLED(PIDTEMPBED) + float get_pid_output_bed(); + #endif + + void _temp_error(int e, const char* serial_msg, const char* lcd_msg); + void min_temp_error(uint8_t e); + void max_temp_error(uint8_t e); + + #if ENABLED(THERMAL_PROTECTION_HOTENDS) || HAS_THERMALLY_PROTECTED_BED + + typedef enum TRState { TRReset, TRInactive, TRFirstHeating, TRStable, TRRunaway } TRstate; + + void thermal_runaway_protection(TRState* state, millis_t* timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc); + + #if ENABLED(THERMAL_PROTECTION_HOTENDS) + TRState thermal_runaway_state_machine[EXTRUDERS] = { TRReset }; + millis_t thermal_runaway_timer[EXTRUDERS] = { 0 }; + #endif + + #if HAS_THERMALLY_PROTECTED_BED + TRState thermal_runaway_bed_state_machine = TRReset; + millis_t thermal_runaway_bed_timer; + #endif + + #endif // THERMAL_PROTECTION + +}; + +extern Temperature thermalManager; #endif // TEMPERATURE_H diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 93991abbcc..7b247fa177 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -479,7 +479,7 @@ inline void line_to_current(AxisEnum axis) { stepper.quick_stop(); card.sdprinting = false; card.closefile(); - autotempShutdown(); + thermalManager.autotempShutdown(); cancel_heatup = true; lcd_setstatus(MSG_PRINT_ABORTED, true); } @@ -605,16 +605,16 @@ void lcd_set_home_offsets() { */ #if ENABLED(THERMAL_PROTECTION_HOTENDS) && WATCH_TEMP_PERIOD > 0 #if TEMP_SENSOR_0 != 0 - void watch_temp_callback_E0() { start_watching_heater(0); } + void watch_temp_callback_E0() { thermalManager.start_watching_heater(0); } #endif #if EXTRUDERS > 1 && TEMP_SENSOR_1 != 0 - void watch_temp_callback_E1() { start_watching_heater(1); } + void watch_temp_callback_E1() { thermalManager.start_watching_heater(1); } #endif // EXTRUDERS > 1 #if EXTRUDERS > 2 && TEMP_SENSOR_2 != 0 - void watch_temp_callback_E2() { start_watching_heater(2); } + void watch_temp_callback_E2() { thermalManager.start_watching_heater(2); } #endif // EXTRUDERS > 2 #if EXTRUDERS > 3 && TEMP_SENSOR_3 != 0 - void watch_temp_callback_E3() { start_watching_heater(3); } + void watch_temp_callback_E3() { thermalManager.start_watching_heater(3); } #endif // EXTRUDERS > 3 #else #if TEMP_SENSOR_0 != 0 @@ -633,7 +633,7 @@ void lcd_set_home_offsets() { #if ENABLED(THERMAL_PROTECTION_BED) && WATCH_BED_TEMP_PERIOD > 0 #if TEMP_SENSOR_BED != 0 - void watch_temp_callback_bed() { start_watching_bed(); } + void watch_temp_callback_bed() { thermalManager.start_watching_bed(); } #endif #else #if TEMP_SENSOR_BED != 0 @@ -670,22 +670,22 @@ static void lcd_tune_menu() { // #if EXTRUDERS == 1 #if TEMP_SENSOR_0 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0); #endif #else //EXTRUDERS > 1 #if TEMP_SENSOR_0 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0); #endif #if TEMP_SENSOR_1 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &thermalManager.target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1); #endif #if EXTRUDERS > 2 #if TEMP_SENSOR_2 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &thermalManager.target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2); #endif #if EXTRUDERS > 3 #if TEMP_SENSOR_3 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &thermalManager.target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3); #endif #endif // EXTRUDERS > 3 #endif // EXTRUDERS > 2 @@ -695,7 +695,7 @@ static void lcd_tune_menu() { // Bed: // #if TEMP_SENSOR_BED != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP - 15, watch_temp_callback_bed); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_BED, &thermalManager.target_temperature_bed, 0, BED_MAXTEMP - 15, watch_temp_callback_bed); #endif // @@ -768,9 +768,9 @@ static void lcd_tune_menu() { * */ void _lcd_preheat(int endnum, const float temph, const float tempb, const int fan) { - if (temph > 0) setTargetHotend(temph, endnum); + if (temph > 0) thermalManager.setTargetHotend(temph, endnum); #if TEMP_SENSOR_BED != 0 - setTargetBed(tempb); + thermalManager.setTargetBed(tempb); #else UNUSED(tempb); #endif @@ -805,19 +805,27 @@ void _lcd_preheat(int endnum, const float temph, const float tempb, const int fa void lcd_preheat_pla0123() { #if EXTRUDERS > 1 - setTargetHotend0(plaPreheatHotendTemp); - setTargetHotend1(plaPreheatHotendTemp); - setTargetHotend2(plaPreheatHotendTemp); + thermalManager.setTargetHotend(plaPreheatHotendTemp, 1); + #if EXTRUDERS > 2 + thermalManager.setTargetHotend(plaPreheatHotendTemp, 2); + #if EXTRUDERS > 3 + thermalManager.setTargetHotend(plaPreheatHotendTemp, 3); + #endif + #endif #endif - _lcd_preheat(EXTRUDERS - 1, plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed); + lcd_preheat_pla0(); } void lcd_preheat_abs0123() { #if EXTRUDERS > 1 - setTargetHotend0(absPreheatHotendTemp); - setTargetHotend1(absPreheatHotendTemp); - setTargetHotend2(absPreheatHotendTemp); + thermalManager.setTargetHotend(absPreheatHotendTemp, 1); + #if EXTRUDERS > 2 + thermalManager.setTargetHotend(absPreheatHotendTemp, 2); + #if EXTRUDERS > 3 + thermalManager.setTargetHotend(absPreheatHotendTemp, 3); + #endif + #endif #endif - _lcd_preheat(EXTRUDERS - 1, absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed); + lcd_preheat_abs0(); } #endif // EXTRUDERS > 1 @@ -879,7 +887,7 @@ void lcd_cooldown() { #if FAN_COUNT > 0 for (uint8_t i = 0; i < FAN_COUNT; i++) fanSpeeds[i] = 0; #endif - disable_all_heaters(); + thermalManager.disable_all_heaters(); lcd_return_to_status(); } @@ -1414,14 +1422,14 @@ static void lcd_control_menu() { UNUSED(e); #endif PID_PARAM(Ki, e) = scalePID_i(raw_Ki); - updatePID(); + thermalManager.updatePID(); } void copy_and_scalePID_d(int e) { #if DISABLED(PID_PARAMS_PER_EXTRUDER) UNUSED(e); #endif PID_PARAM(Kd, e) = scalePID_d(raw_Kd); - updatePID(); + thermalManager.updatePID(); } #define _PIDTEMP_BASE_FUNCTIONS(eindex) \ void copy_and_scalePID_i_E ## eindex() { copy_and_scalePID_i(eindex); } \ @@ -1469,22 +1477,22 @@ static void lcd_control_temperature_menu() { // #if EXTRUDERS == 1 #if TEMP_SENSOR_0 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0); #endif #else //EXTRUDERS > 1 #if TEMP_SENSOR_0 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0); #endif #if TEMP_SENSOR_1 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &thermalManager.target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1); #endif #if EXTRUDERS > 2 #if TEMP_SENSOR_2 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &thermalManager.target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2); #endif #if EXTRUDERS > 3 #if TEMP_SENSOR_3 != 0 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &thermalManager.target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3); #endif #endif // EXTRUDERS > 3 #endif // EXTRUDERS > 2 @@ -1494,7 +1502,7 @@ static void lcd_control_temperature_menu() { // Bed: // #if TEMP_SENSOR_BED != 0 - MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP - 15); + MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_BED, &thermalManager.target_temperature_bed, 0, BED_MAXTEMP - 15); #endif // diff --git a/Marlin/ultralcd_implementation_hitachi_HD44780.h b/Marlin/ultralcd_implementation_hitachi_HD44780.h index b6d60c2ffc..05afe59a3d 100644 --- a/Marlin/ultralcd_implementation_hitachi_HD44780.h +++ b/Marlin/ultralcd_implementation_hitachi_HD44780.h @@ -633,7 +633,7 @@ static void lcd_implementation_status_screen() { // // Hotend 0 Temperature // - LCD_TEMP_ONLY(degHotend(0), degTargetHotend(0)); + LCD_TEMP_ONLY(thermalManager.degHotend(0), thermalManager.degTargetHotend(0)); // // Hotend 1 or Bed Temperature @@ -643,10 +643,10 @@ static void lcd_implementation_status_screen() { lcd.setCursor(8, 0); #if EXTRUDERS > 1 lcd.print(LCD_STR_THERMOMETER[0]); - LCD_TEMP_ONLY(degHotend(1), degTargetHotend(1)); + LCD_TEMP_ONLY(thermalManager.degHotend(1), thermalManager.degTargetHotend(1)); #else lcd.print(LCD_STR_BEDTEMP[0]); - LCD_TEMP_ONLY(degBed(), degTargetBed()); + LCD_TEMP_ONLY(thermalManager.degBed(), thermalManager.degTargetBed()); #endif #endif // EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 @@ -656,7 +656,7 @@ static void lcd_implementation_status_screen() { // // Hotend 0 Temperature // - LCD_TEMP(degHotend(0), degTargetHotend(0), LCD_STR_THERMOMETER[0]); + LCD_TEMP(thermalManager.degHotend(0), thermalManager.degTargetHotend(0), LCD_STR_THERMOMETER[0]); // // Hotend 1 or Bed Temperature @@ -664,9 +664,9 @@ static void lcd_implementation_status_screen() { #if EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 lcd.setCursor(10, 0); #if EXTRUDERS > 1 - LCD_TEMP(degHotend(1), degTargetHotend(1), LCD_STR_THERMOMETER[0]); + LCD_TEMP(thermalManager.degHotend(1), thermalManager.degTargetHotend(1), LCD_STR_THERMOMETER[0]); #else - LCD_TEMP(degBed(), degTargetBed(), LCD_STR_BEDTEMP[0]); + LCD_TEMP(thermalManager.degBed(), thermalManager.degTargetBed(), LCD_STR_BEDTEMP[0]); #endif #endif // EXTRUDERS > 1 || TEMP_SENSOR_BED != 0 @@ -702,7 +702,7 @@ static void lcd_implementation_status_screen() { // If we both have a 2nd extruder and a heated bed, // show the heated bed temp on the left, // since the first line is filled with extruder temps - LCD_TEMP(degBed(), degTargetBed(), LCD_STR_BEDTEMP[0]); + LCD_TEMP(thermalManager.degBed(), thermalManager.degTargetBed(), LCD_STR_BEDTEMP[0]); #else // Before homing the axis letters are blinking 'X' <-> '?'. @@ -925,9 +925,9 @@ void lcd_implementation_drawedit(const char* pstr, const char* value=NULL) { static uint8_t ledsprev = 0; uint8_t leds = 0; - if (target_temperature_bed > 0) leds |= LED_A; + if (thermalManager.degTargetBed() > 0) leds |= LED_A; - if (target_temperature[0] > 0) leds |= LED_B; + if (thermalManager.degTargetHotend(0) > 0) leds |= LED_B; #if FAN_COUNT > 0 if (0 @@ -944,7 +944,7 @@ void lcd_implementation_drawedit(const char* pstr, const char* value=NULL) { #endif // FAN_COUNT > 0 #if EXTRUDERS > 1 - if (target_temperature[1] > 0) leds |= LED_C; + if (thermalManager.degTargetHotend(1) > 0) leds |= LED_C; #endif if (leds != ledsprev) {