|
|
@ -436,7 +436,7 @@ Temperature::Temperature() { } |
|
|
|
|
|
|
|
void Temperature::updatePID() { |
|
|
|
#if ENABLED(PIDTEMP) |
|
|
|
for (int e = 0; e < HOTENDS; e++) { |
|
|
|
HOTEND_LOOP() { |
|
|
|
temp_iState_max[e] = (PID_INTEGRAL_DRIVE_MAX) / PID_PARAM(Ki, e); |
|
|
|
#if ENABLED(PID_ADD_EXTRUSION_RATE) |
|
|
|
last_position[e] = 0; |
|
|
@ -465,12 +465,12 @@ int Temperature::getHeaterPower(int heater) { |
|
|
|
EXTRUDER_3_AUTO_FAN_PIN == EXTRUDER_2_AUTO_FAN_PIN ? 2 : 3 |
|
|
|
}; |
|
|
|
uint8_t fanState = 0; |
|
|
|
for (int f = 0; f < HOTENDS; f++) { |
|
|
|
if (current_temperature[f] > EXTRUDER_AUTO_FAN_TEMPERATURE) |
|
|
|
SBI(fanState, fanBit[f]); |
|
|
|
HOTEND_LOOP() { |
|
|
|
if (current_temperature[e] > EXTRUDER_AUTO_FAN_TEMPERATURE) |
|
|
|
SBI(fanState, fanBit[e]); |
|
|
|
} |
|
|
|
uint8_t fanDone = 0; |
|
|
|
for (int f = 0; f <= 3; f++) { |
|
|
|
for (int8_t f = 0; f <= 3; f++) { |
|
|
|
int8_t pin = fanPin[f]; |
|
|
|
if (pin >= 0 && !TEST(fanDone, fanBit[f])) { |
|
|
|
unsigned char newFanSpeed = TEST(fanState, fanBit[f]) ? EXTRUDER_AUTO_FAN_SPEED : 0; |
|
|
@ -507,95 +507,99 @@ void Temperature::_temp_error(int e, const char* serial_msg, const char* lcd_msg |
|
|
|
} |
|
|
|
|
|
|
|
void Temperature::max_temp_error(uint8_t e) { |
|
|
|
_temp_error(e, PSTR(MSG_T_MAXTEMP), PSTR(MSG_ERR_MAXTEMP)); |
|
|
|
#if HOTENDS == 1 |
|
|
|
UNUSED(e); |
|
|
|
#endif |
|
|
|
_temp_error(HOTEND_INDEX, PSTR(MSG_T_MAXTEMP), PSTR(MSG_ERR_MAXTEMP)); |
|
|
|
} |
|
|
|
void Temperature::min_temp_error(uint8_t e) { |
|
|
|
_temp_error(e, PSTR(MSG_T_MINTEMP), PSTR(MSG_ERR_MINTEMP)); |
|
|
|
#if HOTENDS == 1 |
|
|
|
UNUSED(e); |
|
|
|
#endif |
|
|
|
_temp_error(HOTEND_INDEX, PSTR(MSG_T_MINTEMP), PSTR(MSG_ERR_MINTEMP)); |
|
|
|
} |
|
|
|
|
|
|
|
float Temperature::get_pid_output(int e) { |
|
|
|
#if HOTENDS == 1 |
|
|
|
UNUSED(e); |
|
|
|
#define _HOTEND_TEST true |
|
|
|
#define _HOTEND_EXTRUDER active_extruder |
|
|
|
#else |
|
|
|
#define _HOTEND_TEST e == active_extruder |
|
|
|
#define _HOTEND_EXTRUDER e |
|
|
|
#endif |
|
|
|
float pid_output; |
|
|
|
#if ENABLED(PIDTEMP) |
|
|
|
#if DISABLED(PID_OPENLOOP) |
|
|
|
pid_error[e] = target_temperature[e] - current_temperature[e]; |
|
|
|
dTerm[e] = K2 * PID_PARAM(Kd, e) * (current_temperature[e] - temp_dState[e]) + K1 * dTerm[e]; |
|
|
|
temp_dState[e] = current_temperature[e]; |
|
|
|
if (pid_error[e] > PID_FUNCTIONAL_RANGE) { |
|
|
|
pid_error[HOTEND_INDEX] = target_temperature[HOTEND_INDEX] - current_temperature[HOTEND_INDEX]; |
|
|
|
dTerm[HOTEND_INDEX] = K2 * PID_PARAM(Kd, HOTEND_INDEX) * (current_temperature[HOTEND_INDEX] - temp_dState[HOTEND_INDEX]) + K1 * dTerm[HOTEND_INDEX]; |
|
|
|
temp_dState[HOTEND_INDEX] = current_temperature[HOTEND_INDEX]; |
|
|
|
if (pid_error[HOTEND_INDEX] > PID_FUNCTIONAL_RANGE) { |
|
|
|
pid_output = BANG_MAX; |
|
|
|
pid_reset[e] = true; |
|
|
|
pid_reset[HOTEND_INDEX] = true; |
|
|
|
} |
|
|
|
else if (pid_error[e] < -(PID_FUNCTIONAL_RANGE) || target_temperature[e] == 0) { |
|
|
|
else if (pid_error[HOTEND_INDEX] < -(PID_FUNCTIONAL_RANGE) || target_temperature[HOTEND_INDEX] == 0) { |
|
|
|
pid_output = 0; |
|
|
|
pid_reset[e] = true; |
|
|
|
pid_reset[HOTEND_INDEX] = true; |
|
|
|
} |
|
|
|
else { |
|
|
|
if (pid_reset[e]) { |
|
|
|
temp_iState[e] = 0.0; |
|
|
|
pid_reset[e] = false; |
|
|
|
if (pid_reset[HOTEND_INDEX]) { |
|
|
|
temp_iState[HOTEND_INDEX] = 0.0; |
|
|
|
pid_reset[HOTEND_INDEX] = false; |
|
|
|
} |
|
|
|
pTerm[e] = PID_PARAM(Kp, e) * pid_error[e]; |
|
|
|
temp_iState[e] += pid_error[e]; |
|
|
|
temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]); |
|
|
|
iTerm[e] = PID_PARAM(Ki, e) * temp_iState[e]; |
|
|
|
pTerm[HOTEND_INDEX] = PID_PARAM(Kp, HOTEND_INDEX) * pid_error[HOTEND_INDEX]; |
|
|
|
temp_iState[HOTEND_INDEX] += pid_error[HOTEND_INDEX]; |
|
|
|
temp_iState[HOTEND_INDEX] = constrain(temp_iState[HOTEND_INDEX], temp_iState_min[HOTEND_INDEX], temp_iState_max[HOTEND_INDEX]); |
|
|
|
iTerm[HOTEND_INDEX] = PID_PARAM(Ki, HOTEND_INDEX) * temp_iState[HOTEND_INDEX]; |
|
|
|
|
|
|
|
pid_output = pTerm[e] + iTerm[e] - dTerm[e]; |
|
|
|
|
|
|
|
#if ENABLED(SINGLENOZZLE) |
|
|
|
#define _NOZZLE_TEST true |
|
|
|
#define _NOZZLE_EXTRUDER active_extruder |
|
|
|
#define _CTERM_INDEX 0 |
|
|
|
#else |
|
|
|
#define _NOZZLE_TEST e == active_extruder |
|
|
|
#define _NOZZLE_EXTRUDER e |
|
|
|
#define _CTERM_INDEX e |
|
|
|
#endif |
|
|
|
pid_output = pTerm[HOTEND_INDEX] + iTerm[HOTEND_INDEX] - dTerm[HOTEND_INDEX]; |
|
|
|
|
|
|
|
#if ENABLED(PID_ADD_EXTRUSION_RATE) |
|
|
|
cTerm[_CTERM_INDEX] = 0; |
|
|
|
if (_NOZZLE_TEST) { |
|
|
|
cTerm[HOTEND_INDEX] = 0; |
|
|
|
if (_HOTEND_TEST) { |
|
|
|
long e_position = stepper.position(E_AXIS); |
|
|
|
if (e_position > last_position[_NOZZLE_EXTRUDER]) { |
|
|
|
lpq[lpq_ptr++] = e_position - last_position[_NOZZLE_EXTRUDER]; |
|
|
|
last_position[_NOZZLE_EXTRUDER] = e_position; |
|
|
|
if (e_position > last_position[_HOTEND_EXTRUDER]) { |
|
|
|
lpq[lpq_ptr++] = e_position - last_position[_HOTEND_EXTRUDER]; |
|
|
|
last_position[_HOTEND_EXTRUDER] = e_position; |
|
|
|
} |
|
|
|
else { |
|
|
|
lpq[lpq_ptr++] = 0; |
|
|
|
} |
|
|
|
if (lpq_ptr >= lpq_len) lpq_ptr = 0; |
|
|
|
cTerm[_CTERM_INDEX] = (lpq[lpq_ptr] / planner.axis_steps_per_mm[E_AXIS]) * PID_PARAM(Kc, e); |
|
|
|
pid_output += cTerm[e]; |
|
|
|
cTerm[HOTEND_INDEX] = (lpq[lpq_ptr] / planner.axis_steps_per_mm[E_AXIS]) * PID_PARAM(Kc, HOTEND_INDEX); |
|
|
|
pid_output += cTerm[HOTEND_INDEX]; |
|
|
|
} |
|
|
|
#endif //PID_ADD_EXTRUSION_RATE
|
|
|
|
|
|
|
|
if (pid_output > PID_MAX) { |
|
|
|
if (pid_error[e] > 0) temp_iState[e] -= pid_error[e]; // conditional un-integration
|
|
|
|
if (pid_error[HOTEND_INDEX] > 0) temp_iState[HOTEND_INDEX] -= pid_error[HOTEND_INDEX]; // conditional un-integration
|
|
|
|
pid_output = PID_MAX; |
|
|
|
} |
|
|
|
else if (pid_output < 0) { |
|
|
|
if (pid_error[e] < 0) temp_iState[e] -= pid_error[e]; // conditional un-integration
|
|
|
|
if (pid_error[HOTEND_INDEX] < 0) temp_iState[HOTEND_INDEX] -= pid_error[HOTEND_INDEX]; // conditional un-integration
|
|
|
|
pid_output = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
#else |
|
|
|
pid_output = constrain(target_temperature[e], 0, PID_MAX); |
|
|
|
pid_output = constrain(target_temperature[HOTEND_INDEX], 0, PID_MAX); |
|
|
|
#endif //PID_OPENLOOP
|
|
|
|
|
|
|
|
#if ENABLED(PID_DEBUG) |
|
|
|
SERIAL_ECHO_START; |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG, e); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_INPUT, current_temperature[e]); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG, HOTEND_INDEX); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_INPUT, current_temperature[HOTEND_INDEX]); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_OUTPUT, pid_output); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_PTERM, pTerm[e]); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_ITERM, iTerm[e]); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_DTERM, dTerm[e]); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_PTERM, pTerm[HOTEND_INDEX]); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_ITERM, iTerm[HOTEND_INDEX]); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_DTERM, dTerm[HOTEND_INDEX]); |
|
|
|
#if ENABLED(PID_ADD_EXTRUSION_RATE) |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_CTERM, cTerm[e]); |
|
|
|
SERIAL_ECHOPAIR(MSG_PID_DEBUG_CTERM, cTerm[HOTEND_INDEX]); |
|
|
|
#endif |
|
|
|
SERIAL_EOL; |
|
|
|
#endif //PID_DEBUG
|
|
|
|
|
|
|
|
#else /* PID off */ |
|
|
|
pid_output = (current_temperature[e] < target_temperature[e]) ? PID_MAX : 0; |
|
|
|
pid_output = (current_temperature[HOTEND_INDEX] < target_temperature[HOTEND_INDEX]) ? PID_MAX : 0; |
|
|
|
#endif |
|
|
|
|
|
|
|
return pid_output; |
|
|
@ -672,7 +676,7 @@ void Temperature::manage_heater() { |
|
|
|
#endif |
|
|
|
|
|
|
|
// Loop through all hotends
|
|
|
|
for (int e = 0; e < HOTENDS; e++) { |
|
|
|
HOTEND_LOOP() { |
|
|
|
|
|
|
|
#if ENABLED(THERMAL_PROTECTION_HOTENDS) |
|
|
|
thermal_runaway_protection(&thermal_runaway_state_machine[e], &thermal_runaway_timer[e], current_temperature[e], target_temperature[e], e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS); |
|
|
@ -879,7 +883,7 @@ void Temperature::updateTemperaturesFromRawValues() { |
|
|
|
#if ENABLED(HEATER_0_USES_MAX6675) |
|
|
|
current_temperature_raw[0] = read_max6675(); |
|
|
|
#endif |
|
|
|
for (uint8_t e = 0; e < HOTENDS; e++) { |
|
|
|
HOTEND_LOOP() { |
|
|
|
current_temperature[e] = Temperature::analog2temp(current_temperature_raw[e], e); |
|
|
|
} |
|
|
|
current_temperature_bed = Temperature::analog2tempBed(current_temperature_bed_raw); |
|
|
@ -933,7 +937,7 @@ void Temperature::init() { |
|
|
|
#endif |
|
|
|
|
|
|
|
// Finish init of mult hotend arrays
|
|
|
|
for (int e = 0; e < HOTENDS; e++) { |
|
|
|
HOTEND_LOOP() { |
|
|
|
// populate with the first value
|
|
|
|
maxttemp[e] = maxttemp[0]; |
|
|
|
#if ENABLED(PIDTEMP) |
|
|
@ -1140,13 +1144,16 @@ void Temperature::init() { |
|
|
|
* their target temperature by a configurable margin. |
|
|
|
* This is called when the temperature is set. (M104, M109) |
|
|
|
*/ |
|
|
|
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; |
|
|
|
void Temperature::start_watching_heater(uint8_t e) { |
|
|
|
#if HOTENDS == 1 |
|
|
|
UNUSED(e); |
|
|
|
#endif |
|
|
|
if (degHotend(HOTEND_INDEX) < degTargetHotend(HOTEND_INDEX) - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1)) { |
|
|
|
watch_target_temp[HOTEND_INDEX] = degHotend(HOTEND_INDEX) + WATCH_TEMP_INCREASE; |
|
|
|
watch_heater_next_ms[HOTEND_INDEX] = millis() + (WATCH_TEMP_PERIOD) * 1000UL; |
|
|
|
} |
|
|
|
else |
|
|
|
watch_heater_next_ms[e] = 0; |
|
|
|
watch_heater_next_ms[HOTEND_INDEX] = 0; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
@ -1224,7 +1231,7 @@ void Temperature::init() { |
|
|
|
#endif // THERMAL_PROTECTION_HOTENDS || THERMAL_PROTECTION_BED
|
|
|
|
|
|
|
|
void Temperature::disable_all_heaters() { |
|
|
|
for (int i = 0; i < HOTENDS; i++) setTargetHotend(0, i); |
|
|
|
HOTEND_LOOP() setTargetHotend(0, e); |
|
|
|
setTargetBed(0); |
|
|
|
|
|
|
|
// If all heaters go down then for sure our print job has stopped
|
|
|
|