2 * Marlin 3D Printer Firmware
3 * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
5 * Based on Sprinter and grbl.
6 * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 * temperature.h - temperature controller
28 #include "thermistor/thermistors.h"
30 #include "../inc/MarlinConfig.h"
32 #if ENABLED(AUTO_POWER_CONTROL)
33 #include "../feature/power.h"
36 #ifndef SOFT_PWM_SCALE
37 #define SOFT_PWM_SCALE 0
40 #define HOTEND_INDEX TERN(HAS_MULTI_HOTEND, e, 0)
41 #define E_NAME TERN_(HAS_MULTI_HOTEND, e)
43 // Identifiers for other heaters
44 typedef enum : int8_t {
46 H_PROBE
, H_REDUNDANT
, H_CHAMBER
, H_BED
,
47 H_E0
, H_E1
, H_E2
, H_E3
, H_E4
, H_E5
, H_E6
, H_E7
51 typedef struct { float Kp
, Ki
, Kd
; } PID_t
;
52 typedef struct { float Kp
, Ki
, Kd
, Kc
; } PIDC_t
;
53 typedef struct { float Kp
, Ki
, Kd
, Kf
; } PIDF_t
;
54 typedef struct { float Kp
, Ki
, Kd
, Kc
, Kf
; } PIDCF_t
;
57 #if BOTH(PID_EXTRUSION_SCALING, PID_FAN_SCALING)
59 #elif ENABLED(PID_EXTRUSION_SCALING)
61 #elif ENABLED(PID_FAN_SCALING)
68 #if ENABLED(PID_EXTRUSION_SCALING)
69 typedef IF
<(LPQ_MAX_LEN
> 255), uint16_t, uint8_t>::type lpq_ptr_t
;
72 #define PID_PARAM(F,H) _PID_##F(TERN(PID_PARAMS_PER_HOTEND, H, 0))
73 #define _PID_Kp(H) TERN(PIDTEMP, Temperature::temp_hotend[H].pid.Kp, NAN)
74 #define _PID_Ki(H) TERN(PIDTEMP, Temperature::temp_hotend[H].pid.Ki, NAN)
75 #define _PID_Kd(H) TERN(PIDTEMP, Temperature::temp_hotend[H].pid.Kd, NAN)
77 #define _PID_Kc(H) TERN(PID_EXTRUSION_SCALING, Temperature::temp_hotend[H].pid.Kc, 1)
78 #define _PID_Kf(H) TERN(PID_FAN_SCALING, Temperature::temp_hotend[H].pid.Kf, 0)
85 * States for ADC reading in the ISR
87 enum ADCSensorState
: char {
90 PrepareTemp_0
, MeasureTemp_0
,
93 PrepareTemp_BED
, MeasureTemp_BED
,
96 PrepareTemp_CHAMBER
, MeasureTemp_CHAMBER
,
99 PrepareTemp_PROBE
, MeasureTemp_PROBE
,
102 PrepareTemp_1
, MeasureTemp_1
,
105 PrepareTemp_2
, MeasureTemp_2
,
108 PrepareTemp_3
, MeasureTemp_3
,
111 PrepareTemp_4
, MeasureTemp_4
,
114 PrepareTemp_5
, MeasureTemp_5
,
117 PrepareTemp_6
, MeasureTemp_6
,
120 PrepareTemp_7
, MeasureTemp_7
,
123 PrepareJoy_X
, MeasureJoy_X
,
126 PrepareJoy_Y
, MeasureJoy_Y
,
129 PrepareJoy_Z
, MeasureJoy_Z
,
131 #if ENABLED(FILAMENT_WIDTH_SENSOR)
132 Prepare_FILWIDTH
, Measure_FILWIDTH
,
134 #if ENABLED(POWER_MONITOR_CURRENT)
135 Prepare_POWER_MONITOR_CURRENT
,
136 Measure_POWER_MONITOR_CURRENT
,
138 #if ENABLED(POWER_MONITOR_VOLTAGE)
139 Prepare_POWER_MONITOR_VOLTAGE
,
140 Measure_POWER_MONITOR_VOLTAGE
,
143 Prepare_ADC_KEY
, Measure_ADC_KEY
,
145 SensorsReady
, // Temperatures ready. Delay the next round of readings to let ADC pins settle.
146 StartupDelay
// Startup, delay initial temp reading a tiny bit so the hardware can settle
149 // Minimum number of Temperature::ISR loops between sensor readings.
150 // Multiplied by 16 (OVERSAMPLENR) to obtain the total time to
151 // get all oversampled sensor readings
152 #define MIN_ADC_ISR_LOOPS 10
154 #define ACTUAL_ADC_SAMPLES _MAX(int(MIN_ADC_ISR_LOOPS), int(SensorsReady))
157 #define PID_K2 (1-float(PID_K1))
158 #define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / TEMP_TIMER_FREQUENCY)
160 // Apply the scale factors to the PID values
161 #define scalePID_i(i) ( float(i) * PID_dT )
162 #define unscalePID_i(i) ( float(i) / PID_dT )
163 #define scalePID_d(d) ( float(d) / PID_dT )
164 #define unscalePID_d(d) ( float(d) * PID_dT )
167 #if BOTH(HAS_LCD_MENU, G26_MESH_VALIDATION)
168 #define G26_CLICK_CAN_CANCEL 1
171 // A temperature sensor
172 typedef struct TempInfo
{
176 inline void reset() { acc
= 0; }
177 inline void sample(const uint16_t s
) { acc
+= s
; }
178 inline void update() { raw
= acc
; }
181 // A PWM heater with temperature sensor
182 typedef struct HeaterInfo
: public TempInfo
{
184 uint8_t soft_pwm_amount
;
187 // A heater with PID stabilization
189 struct PIDHeaterInfo
: public HeaterInfo
{
190 T pid
; // Initialized by settings.load()
194 typedef struct PIDHeaterInfo
<hotend_pid_t
> hotend_info_t
;
196 typedef heater_info_t hotend_info_t
;
199 #if ENABLED(PIDTEMPBED)
200 typedef struct PIDHeaterInfo
<PID_t
> bed_info_t
;
202 typedef heater_info_t bed_info_t
;
206 typedef temp_info_t probe_info_t
;
208 #if HAS_HEATED_CHAMBER
209 typedef heater_info_t chamber_info_t
;
210 #elif HAS_TEMP_CHAMBER
211 typedef temp_info_t chamber_info_t
;
214 // Heater idle handling
218 inline void update(const millis_t
&ms
) { if (!timed_out
&& timeout_ms
&& ELAPSED(ms
, timeout_ms
)) timed_out
= true; }
219 inline void start(const millis_t
&ms
) { timeout_ms
= millis() + ms
; timed_out
= false; }
220 inline void reset() { timeout_ms
= 0; timed_out
= false; }
221 inline void expire() { start(0); }
224 // Heater watch handling
225 template <int INCREASE
, int HYSTERESIS
, millis_t PERIOD
>
229 inline bool elapsed(const millis_t
&ms
) { return next_ms
&& ELAPSED(ms
, next_ms
); }
230 inline bool elapsed() { return elapsed(millis()); }
232 inline void restart(const int16_t curr
, const int16_t tgt
) {
234 const int16_t newtarget
= curr
+ INCREASE
;
235 if (newtarget
< tgt
- HYSTERESIS
- 1) {
237 next_ms
= millis() + SEC_TO_MS(PERIOD
);
246 typedef struct HeaterWatch
<WATCH_TEMP_INCREASE
, TEMP_HYSTERESIS
, WATCH_TEMP_PERIOD
> hotend_watch_t
;
249 typedef struct HeaterWatch
<WATCH_BED_TEMP_INCREASE
, TEMP_BED_HYSTERESIS
, WATCH_BED_TEMP_PERIOD
> bed_watch_t
;
252 typedef struct HeaterWatch
<WATCH_CHAMBER_TEMP_INCREASE
, TEMP_CHAMBER_HYSTERESIS
, WATCH_CHAMBER_TEMP_PERIOD
> chamber_watch_t
;
255 // Temperature sensor read value ranges
256 typedef struct { int16_t raw_min
, raw_max
; } raw_range_t
;
257 typedef struct { int16_t mintemp
, maxtemp
; } celsius_range_t
;
258 typedef struct { int16_t raw_min
, raw_max
, mintemp
, maxtemp
; } temp_range_t
;
260 #define THERMISTOR_ABS_ZERO_C -273.15f // bbbbrrrrr cold !
261 #define THERMISTOR_RESISTANCE_NOMINAL_C 25.0f // mmmmm comfortable
263 #if HAS_USER_THERMISTORS
265 enum CustomThermistorIndex
: uint8_t {
266 #if ENABLED(HEATER_0_USER_THERMISTOR)
269 #if ENABLED(HEATER_1_USER_THERMISTOR)
272 #if ENABLED(HEATER_2_USER_THERMISTOR)
275 #if ENABLED(HEATER_3_USER_THERMISTOR)
278 #if ENABLED(HEATER_4_USER_THERMISTOR)
281 #if ENABLED(HEATER_5_USER_THERMISTOR)
284 #if ENABLED(HEATER_BED_USER_THERMISTOR)
287 #if ENABLED(HEATER_PROBE_USER_THERMISTOR)
290 #if ENABLED(HEATER_CHAMBER_USER_THERMISTOR)
296 // User-defined thermistor
298 bool pre_calc
; // true if pre-calculations update needed
299 float sh_c_coeff
, // Steinhart-Hart C coefficient .. defaults to '0.0'
302 res_25
, res_25_recip
,
314 #define HOTEND_TEMPS (HOTENDS + ENABLED(TEMP_SENSOR_1_AS_REDUNDANT))
315 static hotend_info_t temp_hotend
[HOTEND_TEMPS
];
316 static const uint16_t heater_maxtemp
[HOTENDS
];
318 TERN_(HAS_HEATED_BED
, static bed_info_t temp_bed
);
319 TERN_(HAS_TEMP_PROBE
, static probe_info_t temp_probe
);
320 TERN_(HAS_TEMP_CHAMBER
, static chamber_info_t temp_chamber
);
322 TERN_(AUTO_POWER_E_FANS
, static uint8_t autofan_speed
[HOTENDS
]);
323 TERN_(AUTO_POWER_CHAMBER_FAN
, static uint8_t chamberfan_speed
);
325 #if ENABLED(FAN_SOFT_PWM)
326 static uint8_t soft_pwm_amount_fan
[FAN_COUNT
],
327 soft_pwm_count_fan
[FAN_COUNT
];
330 #if ENABLED(PREVENT_COLD_EXTRUSION)
331 static bool allow_cold_extrude
;
332 static int16_t extrude_min_temp
;
333 FORCE_INLINE
static bool tooCold(const int16_t temp
) { return allow_cold_extrude
? false : temp
< extrude_min_temp
- (TEMP_WINDOW
); }
334 FORCE_INLINE
static bool tooColdToExtrude(const uint8_t E_NAME
) {
335 return tooCold(degHotend(HOTEND_INDEX
));
337 FORCE_INLINE
static bool targetTooColdToExtrude(const uint8_t E_NAME
) {
338 return tooCold(degTargetHotend(HOTEND_INDEX
));
341 FORCE_INLINE
static bool tooColdToExtrude(const uint8_t) { return false; }
342 FORCE_INLINE
static bool targetTooColdToExtrude(const uint8_t) { return false; }
345 FORCE_INLINE
static bool hotEnoughToExtrude(const uint8_t e
) { return !tooColdToExtrude(e
); }
346 FORCE_INLINE
static bool targetHotEnoughToExtrude(const uint8_t e
) { return !targetTooColdToExtrude(e
); }
348 #if HEATER_IDLE_HANDLER
349 static hotend_idle_t hotend_idle
[HOTENDS
];
350 TERN_(HAS_HEATED_BED
, static hotend_idle_t bed_idle
);
351 TERN_(HAS_HEATED_CHAMBER
, static hotend_idle_t chamber_idle
);
356 TERN_(EARLY_WATCHDOG
, static bool inited
); // If temperature controller is running
358 static volatile bool raw_temps_ready
;
360 TERN_(WATCH_HOTENDS
, static hotend_watch_t watch_hotend
[HOTENDS
]);
362 #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
363 static uint16_t redundant_temperature_raw
;
364 static float redundant_temperature
;
367 #if ENABLED(PID_EXTRUSION_SCALING)
368 static int32_t last_e_position
, lpq
[LPQ_MAX_LEN
];
369 static lpq_ptr_t lpq_ptr
;
372 TERN_(HAS_HOTEND
, static temp_range_t temp_range
[HOTENDS
]);
375 TERN_(WATCH_BED
, static bed_watch_t watch_bed
);
376 TERN(PIDTEMPBED
,,static millis_t next_bed_check_ms
);
378 static int16_t mintemp_raw_BED
;
381 static int16_t maxtemp_raw_BED
;
385 #if HAS_HEATED_CHAMBER
386 TERN_(WATCH_CHAMBER
, static chamber_watch_t watch_chamber
);
387 static millis_t next_chamber_check_ms
;
388 #ifdef CHAMBER_MINTEMP
389 static int16_t mintemp_raw_CHAMBER
;
391 #ifdef CHAMBER_MAXTEMP
392 static int16_t maxtemp_raw_CHAMBER
;
396 #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
397 static uint8_t consecutive_low_temperature_error
[HOTENDS
];
400 #ifdef MILLISECONDS_PREHEAT_TIME
401 static millis_t preheat_end_time
[HOTENDS
];
404 TERN_(HAS_AUTO_FAN
, static millis_t next_auto_fan_check_ms
);
406 TERN_(PROBING_HEATERS_OFF
, static bool paused
);
410 static uint32_t current_ADCKey_raw
;
411 static uint16_t ADCKey_count
;
414 TERN_(PID_EXTRUSION_SCALING
, static int16_t lpq_len
);
423 * Static (class) methods
426 #if HAS_USER_THERMISTORS
427 static user_thermistor_t user_thermistor
[USER_THERMISTORS
];
428 static void log_user_thermistor(const uint8_t t_index
, const bool eprom
=false);
429 static void reset_user_thermistors();
430 static float user_thermistor_to_deg_c(const uint8_t t_index
, const int raw
);
431 static bool set_pull_up_res(int8_t t_index
, float value
) {
432 //if (!WITHIN(t_index, 0, USER_THERMISTORS - 1)) return false;
433 if (!WITHIN(value
, 1, 1000000)) return false;
434 user_thermistor
[t_index
].series_res
= value
;
437 static bool set_res25(int8_t t_index
, float value
) {
438 if (!WITHIN(value
, 1, 10000000)) return false;
439 user_thermistor
[t_index
].res_25
= value
;
440 user_thermistor
[t_index
].pre_calc
= true;
443 static bool set_beta(int8_t t_index
, float value
) {
444 if (!WITHIN(value
, 1, 1000000)) return false;
445 user_thermistor
[t_index
].beta
= value
;
446 user_thermistor
[t_index
].pre_calc
= true;
449 static bool set_sh_coeff(int8_t t_index
, float value
) {
450 if (!WITHIN(value
, -0.01f
, 0.01f
)) return false;
451 user_thermistor
[t_index
].sh_c_coeff
= value
;
452 user_thermistor
[t_index
].pre_calc
= true;
458 static float analog_to_celsius_hotend(const int raw
, const uint8_t e
);
462 static float analog_to_celsius_bed(const int raw
);
465 static float analog_to_celsius_probe(const int raw
);
468 static float analog_to_celsius_chamber(const int raw
);
473 static uint8_t fan_speed
[FAN_COUNT
];
474 #define FANS_LOOP(I) LOOP_L_N(I, FAN_COUNT)
476 static void set_fan_speed(const uint8_t target
, const uint16_t speed
);
478 #if ENABLED(REPORT_FAN_CHANGE)
479 static void report_fan_speed(const uint8_t target
);
482 #if EITHER(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
483 static bool fans_paused
;
484 static uint8_t saved_fan_speed
[FAN_COUNT
];
487 static constexpr inline uint8_t fanPercent(const uint8_t speed
) { return ui8_to_percent(speed
); }
489 TERN_(ADAPTIVE_FAN_SLOWING
, static uint8_t fan_speed_scaler
[FAN_COUNT
]);
491 static inline uint8_t scaledFanSpeed(const uint8_t target
, const uint8_t fs
) {
492 UNUSED(target
); // Potentially unused!
493 return (fs
* uint16_t(TERN(ADAPTIVE_FAN_SLOWING
, fan_speed_scaler
[target
], 128))) >> 7;
496 static inline uint8_t scaledFanSpeed(const uint8_t target
) {
497 return scaledFanSpeed(target
, fan_speed
[target
]);
500 #if ENABLED(EXTRA_FAN_SPEED)
501 static uint8_t old_fan_speed
[FAN_COUNT
], new_fan_speed
[FAN_COUNT
];
502 static void set_temp_fan_speed(const uint8_t fan
, const uint16_t tmp_temp
);
505 #if EITHER(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
506 void set_fans_paused(const bool p
);
511 static inline void zero_fan_speeds() {
513 FANS_LOOP(i
) set_fan_speed(i
, 0);
518 * Called from the Temperature ISR
520 static void readings_ready();
524 * Call periodically to manage heaters
526 static void manage_heater() _O2
; // Added _O2 to work around a compiler error
531 #ifdef MILLISECONDS_PREHEAT_TIME
532 static bool is_preheating(const uint8_t E_NAME
) {
533 return preheat_end_time
[HOTEND_INDEX
] && PENDING(millis(), preheat_end_time
[HOTEND_INDEX
]);
535 static void start_preheat_time(const uint8_t E_NAME
) {
536 preheat_end_time
[HOTEND_INDEX
] = millis() + MILLISECONDS_PREHEAT_TIME
;
538 static void reset_preheat_time(const uint8_t E_NAME
) {
539 preheat_end_time
[HOTEND_INDEX
] = 0;
542 #define is_preheating(n) (false)
545 //high level conversion routines, for use outside of temperature.cpp
546 //inline so that there is no performance decrease.
549 FORCE_INLINE
static float degHotend(const uint8_t E_NAME
) {
550 return TERN0(HAS_HOTEND
, temp_hotend
[HOTEND_INDEX
].celsius
);
553 #if ENABLED(SHOW_TEMP_ADC_VALUES)
554 FORCE_INLINE
static int16_t rawHotendTemp(const uint8_t E_NAME
) {
555 return TERN0(HAS_HOTEND
, temp_hotend
[HOTEND_INDEX
].raw
);
559 FORCE_INLINE
static int16_t degTargetHotend(const uint8_t E_NAME
) {
560 return TERN0(HAS_HOTEND
, temp_hotend
[HOTEND_INDEX
].target
);
564 static void start_watching_hotend(const uint8_t e
=0);
566 static inline void start_watching_hotend(const uint8_t=0) {}
571 static void setTargetHotend(const int16_t celsius
, const uint8_t E_NAME
) {
572 const uint8_t ee
= HOTEND_INDEX
;
573 #ifdef MILLISECONDS_PREHEAT_TIME
575 reset_preheat_time(ee
);
576 else if (temp_hotend
[ee
].target
== 0)
577 start_preheat_time(ee
);
579 TERN_(AUTO_POWER_CONTROL
, if (celsius
) powerManager
.power_on());
580 temp_hotend
[ee
].target
= _MIN(celsius
, temp_range
[ee
].maxtemp
- HOTEND_OVERSHOOT
);
581 start_watching_hotend(ee
);
584 FORCE_INLINE
static bool isHeatingHotend(const uint8_t E_NAME
) {
585 return temp_hotend
[HOTEND_INDEX
].target
> temp_hotend
[HOTEND_INDEX
].celsius
;
588 FORCE_INLINE
static bool isCoolingHotend(const uint8_t E_NAME
) {
589 return temp_hotend
[HOTEND_INDEX
].target
< temp_hotend
[HOTEND_INDEX
].celsius
;
593 static bool wait_for_hotend(const uint8_t target_extruder
, const bool no_wait_for_cooling
=true
594 #if G26_CLICK_CAN_CANCEL
595 , const bool click_to_cancel
=false
600 FORCE_INLINE
static bool still_heating(const uint8_t e
) {
601 return degTargetHotend(e
) > TEMP_HYSTERESIS
&& ABS(degHotend(e
) - degTargetHotend(e
)) > TEMP_HYSTERESIS
;
604 FORCE_INLINE
static bool degHotendNear(const uint8_t e
, const float &temp
) {
605 return ABS(degHotend(e
) - temp
) < (TEMP_HYSTERESIS
);
612 #if ENABLED(SHOW_TEMP_ADC_VALUES)
613 FORCE_INLINE
static int16_t rawBedTemp() { return temp_bed
.raw
; }
615 FORCE_INLINE
static float degBed() { return temp_bed
.celsius
; }
616 FORCE_INLINE
static int16_t degTargetBed() { return temp_bed
.target
; }
617 FORCE_INLINE
static bool isHeatingBed() { return temp_bed
.target
> temp_bed
.celsius
; }
618 FORCE_INLINE
static bool isCoolingBed() { return temp_bed
.target
< temp_bed
.celsius
; }
621 static void start_watching_bed();
623 static inline void start_watching_bed() {}
626 static void setTargetBed(const int16_t celsius
) {
627 TERN_(AUTO_POWER_CONTROL
, if (celsius
) powerManager
.power_on());
629 #ifdef BED_MAX_TARGET
630 _MIN(celsius
, BED_MAX_TARGET
)
635 start_watching_bed();
638 static bool wait_for_bed(const bool no_wait_for_cooling
=true
639 #if G26_CLICK_CAN_CANCEL
640 , const bool click_to_cancel
=false
644 static void wait_for_bed_heating();
646 FORCE_INLINE
static bool degBedNear(const float &temp
) {
647 return ABS(degBed() - temp
) < (TEMP_BED_HYSTERESIS
);
650 #endif // HAS_HEATED_BED
653 #if ENABLED(SHOW_TEMP_ADC_VALUES)
654 FORCE_INLINE
static int16_t rawProbeTemp() { return temp_probe
.raw
; }
656 FORCE_INLINE
static float degProbe() { return temp_probe
.celsius
; }
660 static void start_watching_probe();
662 static inline void start_watching_probe() {}
666 #if ENABLED(SHOW_TEMP_ADC_VALUES)
667 FORCE_INLINE
static int16_t rawChamberTemp() { return temp_chamber
.raw
; }
669 FORCE_INLINE
static float degChamber() { return temp_chamber
.celsius
; }
670 #if HAS_HEATED_CHAMBER
671 FORCE_INLINE
static int16_t degTargetChamber() { return temp_chamber
.target
; }
672 FORCE_INLINE
static bool isHeatingChamber() { return temp_chamber
.target
> temp_chamber
.celsius
; }
673 FORCE_INLINE
static bool isCoolingChamber() { return temp_chamber
.target
< temp_chamber
.celsius
; }
675 static bool wait_for_chamber(const bool no_wait_for_cooling
=true);
677 #endif // HAS_TEMP_CHAMBER
680 static void start_watching_chamber();
682 static inline void start_watching_chamber() {}
685 #if HAS_HEATED_CHAMBER
686 static void setTargetChamber(const int16_t celsius
) {
687 temp_chamber
.target
=
688 #ifdef CHAMBER_MAXTEMP
689 _MIN(celsius
, CHAMBER_MAXTEMP
- 10)
694 start_watching_chamber();
696 #endif // HAS_HEATED_CHAMBER
699 * The software PWM power for a heater
701 static int16_t getHeaterPower(const heater_ind_t heater
);
704 * Switch off all heaters, set all target temperatures to 0
706 static void disable_all_heaters();
708 #if ENABLED(PRINTJOB_TIMER_AUTOSTART)
710 * Methods to check if heaters are enabled, indicating an active job
712 static bool over_autostart_threshold();
713 static void check_timer_autostart(const bool can_start
, const bool can_stop
);
717 * Perform auto-tuning for hotend or bed in response to M303
720 static void PID_autotune(const float &target
, const heater_ind_t hotend
, const int8_t ncycles
, const bool set_result
=false);
722 #if ENABLED(NO_FAN_SLOWING_IN_PID_TUNING)
723 static bool adaptive_fan_slowing
;
724 #elif ENABLED(ADAPTIVE_FAN_SLOWING)
725 static constexpr bool adaptive_fan_slowing
= true;
729 * Update the temp manager when PID values change
732 FORCE_INLINE
static void updatePID() {
733 TERN_(PID_EXTRUSION_SCALING
, last_e_position
= 0);
739 #if ENABLED(PROBING_HEATERS_OFF)
740 static void pause(const bool p
);
741 FORCE_INLINE
static bool is_paused() { return paused
; }
744 #if HEATER_IDLE_HANDLER
746 static void reset_hotend_idle_timer(const uint8_t E_NAME
) {
747 hotend_idle
[HOTEND_INDEX
].reset();
748 start_watching_hotend(HOTEND_INDEX
);
752 static void reset_bed_idle_timer() {
754 start_watching_bed();
758 #endif // HEATER_IDLE_HANDLER
761 static void print_heater_states(const uint8_t target_extruder
762 #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
763 , const bool include_r
=false
766 #if ENABLED(AUTO_REPORT_TEMPERATURES)
767 static uint8_t auto_report_temp_interval
;
768 static millis_t next_temp_report_ms
;
769 static void auto_report_temperatures();
770 static inline void set_auto_report_interval(uint8_t v
) {
772 auto_report_temp_interval
= v
;
773 next_temp_report_ms
= millis() + 1000UL * v
;
778 TERN_(HAS_DISPLAY
, static void set_heating_message(const uint8_t e
));
780 #if HAS_LCD_MENU && HAS_TEMPERATURE
781 static void lcd_preheat(const int16_t e
, const int8_t indh
, const int8_t indb
);
785 static void update_raw_temperatures();
786 static void updateTemperaturesFromRawValues();
788 #define HAS_MAX6675 EITHER(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675)
790 #define COUNT_6675 1 + BOTH(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675)
792 #define READ_MAX6675(N) read_max6675(N)
794 #define READ_MAX6675(N) read_max6675()
796 static int read_max6675(
798 const uint8_t hindex
=0
803 static void checkExtruderAutoFans();
805 static float get_pid_output_hotend(const uint8_t e
);
807 TERN_(PIDTEMPBED
, static float get_pid_output_bed());
809 TERN_(HAS_HEATED_CHAMBER
, static float get_pid_output_chamber());
811 static void _temp_error(const heater_ind_t e
, PGM_P
const serial_msg
, PGM_P
const lcd_msg
);
812 static void min_temp_error(const heater_ind_t e
);
813 static void max_temp_error(const heater_ind_t e
);
815 #define HAS_THERMAL_PROTECTION (EITHER(THERMAL_PROTECTION_HOTENDS, THERMAL_PROTECTION_CHAMBER) || HAS_THERMALLY_PROTECTED_BED)
817 #if HAS_THERMAL_PROTECTION
819 enum TRState
: char { TRInactive
, TRFirstHeating
, TRStable
, TRRunaway
};
823 TRState state
= TRInactive
;
824 } tr_state_machine_t
;
826 TERN_(THERMAL_PROTECTION_HOTENDS
, static tr_state_machine_t tr_state_machine
[HOTENDS
]);
827 TERN_(HAS_THERMALLY_PROTECTED_BED
, static tr_state_machine_t tr_state_machine_bed
);
828 TERN_(THERMAL_PROTECTION_CHAMBER
, static tr_state_machine_t tr_state_machine_chamber
);
830 static void thermal_runaway_protection(tr_state_machine_t
&state
, const float ¤t
, const float &target
, const heater_ind_t heater_id
, const uint16_t period_seconds
, const uint16_t hysteresis_degc
);
832 #endif // HAS_THERMAL_PROTECTION
835 extern Temperature thermalManager
;