瀏覽代碼

Cooler (for Laser) - M143, M193 (#21255)

Mike La Spina 3 年之前
父節點
當前提交
b95e548ddb
No account linked to committer's email address
共有 41 個文件被更改,包括 1041 次插入125 次删除
  1. 4
    0
      Marlin/Configuration.h
  2. 44
    0
      Marlin/Configuration_adv.h
  3. 1
    1
      Marlin/src/HAL/AVR/fastio.h
  4. 1
    0
      Marlin/src/HAL/ESP32/HAL.cpp
  5. 14
    0
      Marlin/src/HAL/SAMD51/HAL.cpp
  6. 9
    0
      Marlin/src/HAL/STM32F1/HAL.cpp
  7. 18
    17
      Marlin/src/HAL/STM32F1/msc_sd.cpp
  8. 2
    0
      Marlin/src/core/language.h
  9. 37
    0
      Marlin/src/feature/cooler.cpp
  10. 50
    0
      Marlin/src/feature/cooler.h
  11. 7
    0
      Marlin/src/feature/power.cpp
  12. 0
    11
      Marlin/src/gcode/calibrate/G76_M192_M871.cpp
  13. 5
    0
      Marlin/src/gcode/gcode.cpp
  14. 7
    0
      Marlin/src/gcode/gcode.h
  15. 3
    0
      Marlin/src/gcode/host/M115.cpp
  16. 0
    11
      Marlin/src/gcode/temp/M140_M190.cpp
  17. 0
    12
      Marlin/src/gcode/temp/M141_M191.cpp
  18. 67
    0
      Marlin/src/gcode/temp/M143_M193.cpp
  19. 4
    0
      Marlin/src/inc/Conditionals_adv.h
  20. 55
    5
      Marlin/src/inc/Conditionals_post.h
  21. 4
    0
      Marlin/src/inc/SanityCheck.h
  22. 58
    0
      Marlin/src/lcd/dogm/dogm_Statusscreen.h
  23. 70
    0
      Marlin/src/lcd/dogm/status/cooler.h
  24. 32
    3
      Marlin/src/lcd/dogm/status_screen_DOGM.cpp
  25. 14
    12
      Marlin/src/lcd/extui/ui_api.cpp
  26. 1
    1
      Marlin/src/lcd/extui/ui_api.h
  27. 6
    0
      Marlin/src/lcd/language/language_en.h
  28. 10
    0
      Marlin/src/lcd/menu/menu_info.cpp
  29. 22
    1
      Marlin/src/lcd/menu/menu_temperature.cpp
  30. 3
    0
      Marlin/src/lcd/tft/tft_color.h
  31. 6
    0
      Marlin/src/lcd/tft/touch.cpp
  32. 13
    0
      Marlin/src/lcd/tft/ui_320x240.cpp
  33. 6
    0
      Marlin/src/lcd/tft/ui_480x320.cpp
  34. 4
    0
      Marlin/src/lcd/tft/ui_common.h
  35. 342
    38
      Marlin/src/module/temperature.cpp
  36. 70
    5
      Marlin/src/module/temperature.h
  37. 19
    2
      Marlin/src/module/thermistor/thermistors.h
  38. 6
    0
      Marlin/src/pins/pinsDebug_list.h
  39. 19
    1
      Marlin/src/pins/sensitive_pins.h
  40. 6
    5
      buildroot/tests/BIGTREE_SKR_PRO
  41. 2
    0
      platformio.ini

+ 4
- 0
Marlin/Configuration.h 查看文件

@@ -329,8 +329,10 @@
329 329
     #define AUTO_POWER_E_FANS
330 330
     #define AUTO_POWER_CONTROLLERFAN
331 331
     #define AUTO_POWER_CHAMBER_FAN
332
+    #define AUTO_POWER_COOLER_FAN
332 333
     //#define AUTO_POWER_E_TEMP        50 // (°C) Turn on PSU if any extruder is over this temperature
333 334
     //#define AUTO_POWER_CHAMBER_TEMP  30 // (°C) Turn on PSU if the chamber is over this temperature
335
+    //#define AUTO_POWER_COOLER_TEMP   26 // (°C) Turn on PSU if the cooler is over this temperature
334 336
     #define POWER_TIMEOUT              30 // (s) Turn off power if the machine is idle for this duration
335 337
     //#define POWER_OFF_DELAY          60 // (s) Delay of poweroff after M81 command. Useful to let fans run for extra time.
336 338
   #endif
@@ -418,6 +420,7 @@
418 420
 #define TEMP_SENSOR_BED 0
419 421
 #define TEMP_SENSOR_PROBE 0
420 422
 #define TEMP_SENSOR_CHAMBER 0
423
+#define TEMP_SENSOR_COOLER 0
421 424
 
422 425
 // Dummy thermistor constant temperature readings, for use with 998 and 999
423 426
 #define DUMMY_THERMISTOR_998_VALUE  25
@@ -636,6 +639,7 @@
636 639
 #define THERMAL_PROTECTION_HOTENDS // Enable thermal protection for all extruders
637 640
 #define THERMAL_PROTECTION_BED     // Enable thermal protection for the heated bed
638 641
 #define THERMAL_PROTECTION_CHAMBER // Enable thermal protection for the heated chamber
642
+#define THERMAL_PROTECTION_COOLER  // Enable thermal protection for the laser cooling
639 643
 
640 644
 //===========================================================================
641 645
 //============================= Mechanical Settings =========================

+ 44
- 0
Marlin/Configuration_adv.h 查看文件

@@ -113,6 +113,12 @@
113 113
   #define CHAMBER_BETA                 3950    // Beta value
114 114
 #endif
115 115
 
116
+#if TEMP_SENSOR_COOLER == 1000
117
+  #define COOLER_PULLUP_RESISTOR_OHMS 4700    // Pullup resistor
118
+  #define COOLER_RESISTANCE_25C_OHMS  100000  // Resistance at 25C
119
+  #define COOLER_BETA                 3950    // Beta value
120
+#endif
121
+
116 122
 #if TEMP_SENSOR_PROBE == 1000
117 123
   #define PROBE_PULLUP_RESISTOR_OHMS   4700    // Pullup resistor
118 124
   #define PROBE_RESISTANCE_25C_OHMS    100000  // Resistance at 25C
@@ -179,6 +185,25 @@
179 185
   #endif
180 186
 #endif
181 187
 
188
+//
189
+// Laser Cooler options
190
+//
191
+#if TEMP_SENSOR_COOLER
192
+  #define COOLER_MINTEMP           8  // (°C)
193
+  #define COOLER_MAXTEMP          26  // (°C)
194
+  #define COOLER_DEFAULT_TEMP     16  // (°C)
195
+  #define TEMP_COOLER_HYSTERESIS   1  // (°C) Temperature proximity considered "close enough" to the target
196
+  #define COOLER_PIN               8  // Laser cooler on/off pin used to control power to the cooling element e.g. TEC, External chiller via relay
197
+  #define COOLER_INVERTING     false
198
+  #define TEMP_COOLER_PIN         15  // Laser/Cooler temperature sensor pin. ADC is required.
199
+  #define COOLER_FAN                  // Enable a fan on the cooler, Fan# 0,1,2,3 etc.
200
+  #define COOLER_FAN_INDEX         0  // FAN number 0, 1, 2 etc. e.g.
201
+  #if ENABLED(COOLER_FAN)
202
+    #define COOLER_FAN_BASE      100  // Base Cooler fan PWM (0-255); turns on when Cooler temperature is above the target
203
+    #define COOLER_FAN_FACTOR     25  // PWM increase per °C above target
204
+  #endif
205
+#endif
206
+
182 207
 /**
183 208
  * Thermal Protection provides additional protection to your printer from damage
184 209
  * and fire. Marlin always includes safe min and max temperature ranges which
@@ -248,6 +273,20 @@
248 273
   #define WATCH_CHAMBER_TEMP_INCREASE           2 // Degrees Celsius
249 274
 #endif
250 275
 
276
+/**
277
+ * Thermal Protection parameters for the laser cooler.
278
+ */
279
+#if ENABLED(THERMAL_PROTECTION_COOLER)
280
+  #define THERMAL_PROTECTION_COOLER_PERIOD    10 // Seconds
281
+  #define THERMAL_PROTECTION_COOLER_HYSTERESIS 3 // Degrees Celsius
282
+
283
+  /**
284
+   * Laser cooling watch settings (M143/M193).
285
+   */
286
+  #define WATCH_COOLER_TEMP_PERIOD            60 // Seconds
287
+  #define WATCH_COOLER_TEMP_INCREASE           3 // Degrees Celsius
288
+#endif
289
+
251 290
 #if ENABLED(PIDTEMP)
252 291
   // Add an experimental additional term to the heater power, proportional to the extrusion speed.
253 292
   // A well-chosen Kc value should add just enough power to melt the increased material volume.
@@ -493,11 +532,15 @@
493 532
 #define E6_AUTO_FAN_PIN -1
494 533
 #define E7_AUTO_FAN_PIN -1
495 534
 #define CHAMBER_AUTO_FAN_PIN -1
535
+#define COOLER_AUTO_FAN_PIN -1
536
+#define COOLER_FAN_PIN -1
496 537
 
497 538
 #define EXTRUDER_AUTO_FAN_TEMPERATURE 50
498 539
 #define EXTRUDER_AUTO_FAN_SPEED 255   // 255 == full speed
499 540
 #define CHAMBER_AUTO_FAN_TEMPERATURE 30
500 541
 #define CHAMBER_AUTO_FAN_SPEED 255
542
+#define COOLER_AUTO_FAN_TEMPERATURE 18
543
+#define COOLER_AUTO_FAN_SPEED 255
501 544
 
502 545
 /**
503 546
  * Part-Cooling Fan Multiplexer
@@ -1495,6 +1538,7 @@
1495 1538
   #define STATUS_BED_ANIM             // Use a second bitmap to indicate bed heating
1496 1539
   #define STATUS_CHAMBER_ANIM         // Use a second bitmap to indicate chamber heating
1497 1540
   //#define STATUS_CUTTER_ANIM        // Use a second bitmap to indicate spindle / laser active
1541
+  //#define STATUS_COOLER_ANIM        // Use a second bitmap to indicate laser cooling
1498 1542
   //#define STATUS_ALT_BED_BITMAP     // Use the alternative bed bitmap
1499 1543
   //#define STATUS_ALT_FAN_BITMAP     // Use the alternative fan bitmap
1500 1544
   //#define STATUS_FAN_FRAMES 3       // :[0,1,2,3,4] Number of fan animation frames

+ 1
- 1
Marlin/src/HAL/AVR/fastio.h 查看文件

@@ -285,7 +285,7 @@ enum ClockSource2 : char {
285 285
  */
286 286
 
287 287
 // Determine which harware PWMs are already in use
288
-#define _PWM_CHK_FAN_B(P) (P == E0_AUTO_FAN_PIN || P == E1_AUTO_FAN_PIN || P == E2_AUTO_FAN_PIN || P == E3_AUTO_FAN_PIN || P == E4_AUTO_FAN_PIN || P == E5_AUTO_FAN_PIN || P == E6_AUTO_FAN_PIN || P == E7_AUTO_FAN_PIN || P == CHAMBER_AUTO_FAN_PIN)
288
+#define _PWM_CHK_FAN_B(P) (P == E0_AUTO_FAN_PIN || P == E1_AUTO_FAN_PIN || P == E2_AUTO_FAN_PIN || P == E3_AUTO_FAN_PIN || P == E4_AUTO_FAN_PIN || P == E5_AUTO_FAN_PIN || P == E6_AUTO_FAN_PIN || P == E7_AUTO_FAN_PIN || P == CHAMBER_AUTO_FAN_PIN || P == COOLER_AUTO_FAN_PIN)
289 289
 #if PIN_EXISTS(CONTROLLER_FAN)
290 290
   #define PWM_CHK_FAN_B(P) (_PWM_CHK_FAN_B(P) || P == CONTROLLER_FAN_PIN)
291 291
 #else

+ 1
- 0
Marlin/src/HAL/ESP32/HAL.cpp 查看文件

@@ -185,6 +185,7 @@ void HAL_adc_init() {
185 185
   TERN_(HAS_TEMP_ADC_7, adc3_set_attenuation(get_channel(TEMP_7_PIN), ADC_ATTEN_11db));
186 186
   TERN_(HAS_HEATED_BED, adc1_set_attenuation(get_channel(TEMP_BED_PIN), ADC_ATTEN_11db));
187 187
   TERN_(HAS_TEMP_CHAMBER, adc1_set_attenuation(get_channel(TEMP_CHAMBER_PIN), ADC_ATTEN_11db));
188
+  TERN_(HAS_TEMP_COOLER, adc1_set_attenuation(get_channel(TEMP_COOLER_PIN), ADC_ATTEN_11db));
188 189
   TERN_(FILAMENT_WIDTH_SENSOR, adc1_set_attenuation(get_channel(FILWIDTH_PIN), ADC_ATTEN_11db));
189 190
 
190 191
   // Note that adc2 is shared with the WiFi module, which has higher priority, so the conversion may fail.

+ 14
- 0
Marlin/src/HAL/SAMD51/HAL.cpp 查看文件

@@ -57,6 +57,7 @@
57 57
 #define GET_PROBE_ADC()           TERN(HAS_TEMP_PROBE,        PIN_TO_ADC(TEMP_PROBE_PIN),   -1)
58 58
 #define GET_BED_ADC()             TERN(HAS_TEMP_ADC_BED,      PIN_TO_ADC(TEMP_BED_PIN),     -1)
59 59
 #define GET_CHAMBER_ADC()         TERN(HAS_TEMP_ADC_CHAMBER,  PIN_TO_ADC(TEMP_CHAMBER_PIN), -1)
60
+#define GET_COOLER_ADC()          TERN(HAS_TEMP_ADC_COOLER,   PIN_TO_ADC(TEMP_COOLER_PIN),  -1)
60 61
 #define GET_FILAMENT_WIDTH_ADC()  TERN(FILAMENT_WIDTH_SENSOR, PIN_TO_ADC(FILWIDTH_PIN),     -1)
61 62
 #define GET_BUTTONS_ADC()         TERN(HAS_ADC_BUTTONS,       PIN_TO_ADC(ADC_KEYPAD_PIN),   -1)
62 63
 
@@ -66,6 +67,7 @@
66 67
   || GET_PROBE_ADC() == n          \
67 68
   || GET_BED_ADC() == n            \
68 69
   || GET_CHAMBER_ADC() == n        \
70
+  || GET_COOLER_ADC() == n         \
69 71
   || GET_FILAMENT_WIDTH_ADC() == n \
70 72
   || GET_BUTTONS_ADC() == n        \
71 73
 )
@@ -144,6 +146,9 @@ uint16_t HAL_adc_result;
144 146
     #if GET_CHAMBER_ADC() == 0
145 147
       TEMP_CHAMBER_PIN,
146 148
     #endif
149
+    #if GET_COOLER_ADC() == 0
150
+      TEMP_COOLER_PIN,
151
+    #endif
147 152
     #if GET_FILAMENT_WIDTH_ADC() == 0
148 153
       FILWIDTH_PIN,
149 154
     #endif
@@ -184,6 +189,9 @@ uint16_t HAL_adc_result;
184 189
     #if GET_CHAMBER_ADC() == 1
185 190
       TEMP_CHAMBER_PIN,
186 191
     #endif
192
+    #if GET_COOLER_ADC() == 1
193
+      TEMP_COOLER_PIN,
194
+    #endif
187 195
     #if GET_FILAMENT_WIDTH_ADC() == 1
188 196
       FILWIDTH_PIN,
189 197
     #endif
@@ -232,6 +240,9 @@ uint16_t HAL_adc_result;
232 240
       #if GET_CHAMBER_ADC() == 0
233 241
         { PIN_TO_INPUTCTRL(TEMP_CHAMBER_PIN) },
234 242
       #endif
243
+      #if GET_COOLER_ADC() == 0
244
+        { PIN_TO_INPUTCTRL(TEMP_COOLER_PIN) },
245
+      #endif
235 246
       #if GET_FILAMENT_WIDTH_ADC() == 0
236 247
         { PIN_TO_INPUTCTRL(FILWIDTH_PIN) },
237 248
       #endif
@@ -281,6 +292,9 @@ uint16_t HAL_adc_result;
281 292
       #if GET_CHAMBER_ADC() == 1
282 293
         { PIN_TO_INPUTCTRL(TEMP_CHAMBER_PIN) },
283 294
       #endif
295
+      #if GET_COOLER_ADC() == 1
296
+        { PIN_TO_INPUTCTRL(TEMP_COOLER_PIN) },
297
+      #endif
284 298
       #if GET_FILAMENT_WIDTH_ADC() == 1
285 299
         { PIN_TO_INPUTCTRL(FILWIDTH_PIN) },
286 300
       #endif

+ 9
- 0
Marlin/src/HAL/STM32F1/HAL.cpp 查看文件

@@ -132,6 +132,9 @@ const uint8_t adc_pins[] = {
132 132
   #if HAS_TEMP_CHAMBER
133 133
     TEMP_CHAMBER_PIN,
134 134
   #endif
135
+  #if HAS_TEMP_COOLER
136
+    TEMP_COOLER_PIN,
137
+  #endif
135 138
   #if HAS_TEMP_ADC_1
136 139
     TEMP_1_PIN,
137 140
   #endif
@@ -189,6 +192,9 @@ enum TempPinIndex : char {
189 192
   #if HAS_TEMP_CHAMBER
190 193
     TEMP_CHAMBER,
191 194
   #endif
195
+  #if HAS_TEMP_COOLER
196
+    TEMP_COOLER_PIN,
197
+  #endif
192 198
   #if HAS_TEMP_ADC_1
193 199
     TEMP_1,
194 200
   #endif
@@ -385,6 +391,9 @@ void HAL_adc_start_conversion(const uint8_t adc_pin) {
385 391
     #if HAS_TEMP_CHAMBER
386 392
       case TEMP_CHAMBER_PIN: pin_index = TEMP_CHAMBER; break;
387 393
     #endif
394
+    #if HAS_TEMP_COOLER
395
+      case TEMP_COOLER_PIN: pin_index = TEMP_COOLER; break;
396
+    #endif
388 397
     #if HAS_TEMP_ADC_1
389 398
       case TEMP_1_PIN: pin_index = TEMP_1; break;
390 399
     #endif

+ 18
- 17
Marlin/src/HAL/STM32F1/msc_sd.cpp 查看文件

@@ -43,26 +43,27 @@ Serial0Type<USBCompositeSerial> MarlinCompositeSerial(true);
43 43
 
44 44
 #if ENABLED(EMERGENCY_PARSER)
45 45
 
46
-// The original callback is not called (no way to retrieve address).
47
-// That callback detects a special STM32 reset sequence: this functionality is not essential
48
-// as M997 achieves the same.
49
-void my_rx_callback(unsigned int, void*) {
50
-  // max length of 16 is enough to contain all emergency commands
51
-  uint8 buf[16];
46
+  // The original callback is not called (no way to retrieve address).
47
+  // That callback detects a special STM32 reset sequence: this functionality is not essential
48
+  // as M997 achieves the same.
49
+  void my_rx_callback(unsigned int, void*) {
50
+    // max length of 16 is enough to contain all emergency commands
51
+    uint8 buf[16];
52 52
 
53
-  //rx is usbSerialPart.endpoints[2]
54
-  uint16 len = usb_get_ep_rx_count(usbSerialPart.endpoints[2].address);
55
-  uint32 total = composite_cdcacm_data_available();
53
+    //rx is usbSerialPart.endpoints[2]
54
+    uint16 len = usb_get_ep_rx_count(usbSerialPart.endpoints[2].address);
55
+    uint32 total = composite_cdcacm_data_available();
56 56
 
57
-  if (len == 0 || total == 0 || !WITHIN(total, len, COUNT(buf)))
58
-    return;
57
+    if (len == 0 || total == 0 || !WITHIN(total, len, COUNT(buf)))
58
+      return;
59 59
 
60
-  // cannot get character by character due to bug in composite_cdcacm_peek_ex
61
-  len = composite_cdcacm_peek(buf, total);
60
+    // cannot get character by character due to bug in composite_cdcacm_peek_ex
61
+    len = composite_cdcacm_peek(buf, total);
62
+
63
+    for (uint32 i = 0; i < len; i++)
64
+      emergency_parser.update(MarlinCompositeSerial.emergency_state, buf[i+total-len]);
65
+  }
62 66
 
63
-  for (uint32 i = 0; i < len; i++)
64
-    emergency_parser.update(MarlinCompositeSerial.emergency_state, buf[i+total-len]);
65
-}
66 67
 #endif
67 68
 
68 69
 void MSC_SD_init() {
@@ -87,7 +88,7 @@ void MSC_SD_init() {
87 88
   MarlinCompositeSerial.registerComponent();
88 89
   USBComposite.begin();
89 90
   #if ENABLED(EMERGENCY_PARSER)
90
-  	composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_RX, my_rx_callback);
91
+    composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_RX, my_rx_callback);
91 92
   #endif
92 93
 }
93 94
 

+ 2
- 0
Marlin/src/core/language.h 查看文件

@@ -247,6 +247,8 @@
247 247
 
248 248
 #define STR_HEATER_BED                      "bed"
249 249
 #define STR_HEATER_CHAMBER                  "chamber"
250
+#define STR_COOLER                          "cooler"
251
+#define STR_LASER_TEMP                      "laser temperature"
250 252
 
251 253
 #define STR_STOPPED_HEATER                  ", system stopped! Heater_ID: "
252 254
 #define STR_REDUNDANCY                      "Heater switched off. Temperature difference between temp sensors is too high !"

+ 37
- 0
Marlin/src/feature/cooler.cpp 查看文件

@@ -0,0 +1,37 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
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.
12
+ *
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.
17
+ *
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/>.
20
+ *
21
+ */
22
+
23
+#include "../inc/MarlinConfig.h"
24
+
25
+#if HAS_COOLER
26
+
27
+#include "cooler.h"
28
+Cooler cooler;
29
+
30
+uint16_t Cooler::flowrate;        // Flow meter reading in liters, 0 will result in shutdown if equiped
31
+uint8_t Cooler::mode = 0;         // 0 = CO2 Liquid cooling, 1 = Laser Diode TEC Heatsink Cooling
32
+uint16_t Cooler::capacity;        // Cooling capacity in watts
33
+uint16_t Cooler::load;            // Cooling load in watts
34
+bool Cooler::flowmeter = false;
35
+bool Cooler::state = false;       // on = true, off = false
36
+
37
+#endif

+ 50
- 0
Marlin/src/feature/cooler.h 查看文件

@@ -0,0 +1,50 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
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.
12
+ *
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.
17
+ *
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/>.
20
+ *
21
+ */
22
+#pragma once
23
+
24
+#include <stdint.h>
25
+
26
+#define _MSG_COOLER(M) MSG_COOLER_##M
27
+#define MSG_COOLER(M) _MSG_COOLER(M)
28
+
29
+// Cooling device
30
+
31
+class Cooler {
32
+public:
33
+  static uint16_t flowrate;        // Flow meter reading in liters, 0 will result in shutdown if equiped
34
+  static uint8_t mode;             // 0 = CO2 Liquid cooling, 1 = Laser Diode TEC Heatsink Cooling
35
+  static uint16_t capacity;        // Cooling capacity in watts
36
+  static uint16_t load;            // Cooling load in watts
37
+  static bool flowmeter;
38
+  static bool state;               // on = true, off = false
39
+
40
+  static bool is_enabled()                    { return state; }
41
+  static void enable()                        { state = true; }
42
+  static void disable()                       { state = false; }
43
+  static void set_mode(const uint8_t m)       { mode = m; }
44
+  static void set_flowmeter(const bool sflag) { flowmeter = sflag; }
45
+  static uint16_t get_flowrate()              { return flowrate; }
46
+  static void update_flowrate(uint16_t flow)  { flowrate = flow; }
47
+  //static void init() { set_state(false); }
48
+};
49
+
50
+extern Cooler cooler;

+ 7
- 0
Marlin/src/feature/power.cpp 查看文件

@@ -61,6 +61,9 @@ bool Power::is_power_needed() {
61 61
   if (TERN0(AUTO_POWER_CHAMBER_FAN, thermalManager.chamberfan_speed))
62 62
     return true;
63 63
 
64
+  if (TERN0(AUTO_POWER_COOLER_FAN, thermalManager.coolerfan_speed))
65
+    return true;
66
+
64 67
   // If any of the drivers or the bed are enabled...
65 68
   if (X_ENABLE_READ() == X_ENABLE_ON || Y_ENABLE_READ() == Y_ENABLE_ON || Z_ENABLE_READ() == Z_ENABLE_ON
66 69
     #if HAS_X2_ENABLE
@@ -89,6 +92,10 @@ bool Power::is_power_needed() {
89 92
     if (thermalManager.degChamber() >= AUTO_POWER_CHAMBER_TEMP) return true;
90 93
   #endif
91 94
 
95
+  #if HAS_COOLER && AUTO_POWER_COOLER_TEMP
96
+    if (thermalManager.degCooler() >= AUTO_POWER_COOLER_TEMP) return true;
97
+  #endif
98
+
92 99
   return false;
93 100
 }
94 101
 

+ 0
- 11
Marlin/src/gcode/calibrate/G76_M192_M871.cpp 查看文件

@@ -36,17 +36,7 @@
36 36
 #include "../../module/temperature.h"
37 37
 #include "../../module/probe.h"
38 38
 #include "../../feature/probe_temp_comp.h"
39
-
40 39
 #include "../../lcd/marlinui.h"
41
-#include "../../MarlinCore.h" // for wait_for_heatup, idle()
42
-
43
-#if ENABLED(PRINTJOB_TIMER_AUTOSTART)
44
-  #include "../../module/printcounter.h"
45
-#endif
46
-
47
-#if ENABLED(PRINTER_EVENTS_LEDS)
48
-  #include "../../feature/leds/leds.h"
49
-#endif
50 40
 
51 41
 /**
52 42
  * G76: calibrate probe and/or bed temperature offsets
@@ -173,7 +163,6 @@ void GcodeSuite::G76() {
173 163
 
174 164
   remember_feedrate_scaling_off();
175 165
 
176
-
177 166
   /******************************************
178 167
    * Calibrate bed temperature offsets
179 168
    ******************************************/

+ 5
- 0
Marlin/src/gcode/gcode.cpp 查看文件

@@ -539,6 +539,11 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
539 539
         case 191: M191(); break;                                  // M191: Wait for chamber temperature to reach target
540 540
       #endif
541 541
 
542
+      #if HAS_COOLER
543
+        case 143: M143(); break;                                  // M143: Set cooler temperature
544
+        case 193: M193(); break;                                  // M193: Wait for cooler temperature to reach target
545
+      #endif
546
+
542 547
       #if BOTH(AUTO_REPORT_TEMPERATURES, HAS_TEMP_SENSOR)
543 548
         case 155: M155(); break;                                  // M155: Set temperature auto-report interval
544 549
       #endif

+ 7
- 0
Marlin/src/gcode/gcode.h 查看文件

@@ -153,6 +153,7 @@
153 153
  * M129 - EtoP Closed. (Requires BARICUDA)
154 154
  * M140 - Set bed target temp. S<temp>
155 155
  * M141 - Set heated chamber target temp. S<temp> (Requires a chamber heater)
156
+ * M143 - Set cooler target temp. S<temp> (Requires a laser cooling device)
156 157
  * M145 - Set heatup values for materials on the LCD. H<hotend> B<bed> F<fan speed> for S<material> (0=PLA, 1=ABS)
157 158
  * M149 - Set temperature units. (Requires TEMPERATURE_UNITS_SUPPORT)
158 159
  * M150 - Set Status LED Color as R<red> U<green> B<blue> W<white> P<bright>. Values 0-255. (Requires BLINKM, RGB_LED, RGBW_LED, NEOPIXEL_LED, PCA9533, or PCA9632).
@@ -163,6 +164,7 @@
163 164
  * M166 - Set the Gradient Mix for the mixing extruder. (Requires GRADIENT_MIX)
164 165
  * M190 - S<temp> Wait for bed current temp to reach target temp. ** Wait only when heating! **
165 166
  *        R<temp> Wait for bed current temp to reach target temp. ** Wait for heating or cooling. **
167
+ * M193 - R<temp> Wait for cooler temp to reach target temp. ** Wait for cooling. **
166 168
  * M200 - Set filament diameter, D<diameter>, setting E axis units to cubic. (Use S0 to revert to linear units.)
167 169
  * M201 - Set max acceleration in units/s^2 for print moves: "M201 X<accel> Y<accel> Z<accel> E<accel>"
168 170
  * M202 - Set max acceleration in units/s^2 for travel moves: "M202 X<accel> Y<accel> Z<accel> E<accel>" ** UNUSED IN MARLIN! **
@@ -632,6 +634,11 @@ private:
632 634
     static void M191();
633 635
   #endif
634 636
 
637
+  #if HAS_COOLER
638
+    static void M143();
639
+    static void M193();
640
+  #endif
641
+
635 642
   #if PREHEAT_COUNT
636 643
     static void M145();
637 644
   #endif

+ 3
- 0
Marlin/src/gcode/host/M115.cpp 查看文件

@@ -141,6 +141,9 @@ void GcodeSuite::M115() {
141 141
     // CHAMBER_TEMPERATURE (M141, M191)
142 142
     cap_line(PSTR("CHAMBER_TEMPERATURE"), ENABLED(HAS_HEATED_CHAMBER));
143 143
 
144
+    // COOLER_TEMPERATURE (M143, M193)
145
+    cap_line(PSTR("COOLER_TEMPERATURE"), ENABLED(HAS_COOLER));
146
+
144 147
     // MEATPACK Compresson
145 148
     cap_line(PSTR("MEATPACK"), ENABLED(MEATPACK));
146 149
 

+ 0
- 11
Marlin/src/gcode/temp/M140_M190.cpp 查看文件

@@ -32,19 +32,8 @@
32 32
 
33 33
 #include "../gcode.h"
34 34
 #include "../../module/temperature.h"
35
-#include "../../module/motion.h"
36 35
 #include "../../lcd/marlinui.h"
37 36
 
38
-#if ENABLED(PRINTJOB_TIMER_AUTOSTART)
39
-  #include "../../module/printcounter.h"
40
-#endif
41
-
42
-#if ENABLED(PRINTER_EVENT_LEDS)
43
-  #include "../../feature/leds/leds.h"
44
-#endif
45
-
46
-#include "../../MarlinCore.h" // for wait_for_heatup, idle, startOrResumeJob
47
-
48 37
 /**
49 38
  * M140: Set bed temperature
50 39
  *

+ 0
- 12
Marlin/src/gcode/temp/M141_M191.cpp 查看文件

@@ -32,20 +32,8 @@
32 32
 
33 33
 #include "../gcode.h"
34 34
 #include "../../module/temperature.h"
35
-
36
-#include "../../module/motion.h"
37 35
 #include "../../lcd/marlinui.h"
38 36
 
39
-#if ENABLED(PRINTJOB_TIMER_AUTOSTART)
40
-  #include "../../module/printcounter.h"
41
-#endif
42
-
43
-#if ENABLED(PRINTER_EVENT_LEDS)
44
-  #include "../../feature/leds/leds.h"
45
-#endif
46
-
47
-#include "../../MarlinCore.h" // for wait_for_heatup, idle, startOrResumeJob
48
-
49 37
 /**
50 38
  * M141: Set chamber temperature
51 39
  */

+ 67
- 0
Marlin/src/gcode/temp/M143_M193.cpp 查看文件

@@ -0,0 +1,67 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
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.
12
+ *
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.
17
+ *
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/>.
20
+ *
21
+ */
22
+
23
+/**
24
+ * gcode/temp/M143_M193.cpp
25
+ *
26
+ * Laser Cooler target temperature control
27
+ */
28
+
29
+#include "../../inc/MarlinConfig.h"
30
+
31
+#if HAS_COOLER
32
+
33
+#include "../../feature/cooler.h"
34
+extern Cooler cooler;
35
+
36
+#include "../gcode.h"
37
+#include "../../module/temperature.h"
38
+#include "../../lcd/marlinui.h"
39
+
40
+/**
41
+ * M143: Set cooler temperature
42
+ */
43
+void GcodeSuite::M143() {
44
+  if (DEBUGGING(DRYRUN)) return;
45
+  if (parser.seenval('S')) {
46
+    thermalManager.setTargetCooler(parser.value_celsius());
47
+    parser.value_celsius() ? cooler.enable() : cooler.disable();
48
+  }
49
+}
50
+
51
+/**
52
+ * M193: Sxxx Wait for laser current temp to reach target temp. Waits only when cooling.
53
+ */
54
+void GcodeSuite::M193() {
55
+  if (DEBUGGING(DRYRUN)) return;
56
+
57
+  if (parser.seenval('S')) {
58
+    cooler.enable();
59
+    thermalManager.setTargetCooler(parser.value_celsius());
60
+    if (thermalManager.isLaserCooling()) {
61
+      ui.set_status_P(GET_TEXT(MSG_LASER_COOLING));
62
+      thermalManager.wait_for_cooler(true);
63
+    }
64
+  }
65
+}
66
+
67
+#endif // HAS_COOLER

+ 4
- 0
Marlin/src/inc/Conditionals_adv.h 查看文件

@@ -114,6 +114,10 @@
114 114
   #undef THERMAL_PROTECTION_CHAMBER
115 115
 #endif
116 116
 
117
+#if TEMP_SENSOR_COOLER == 0
118
+  #undef THERMAL_PROTECTION_COOLER
119
+#endif
120
+
117 121
 #if ENABLED(MIXING_EXTRUDER) && (ENABLED(RETRACT_SYNC_MIXING) || BOTH(FILAMENT_LOAD_UNLOAD_GCODES, FILAMENT_UNLOAD_ALL_EXTRUDERS))
118 122
   #define HAS_MIXER_SYNC_CHANNEL 1
119 123
 #endif

+ 55
- 5
Marlin/src/inc/Conditionals_post.h 查看文件

@@ -399,7 +399,7 @@
399 399
  * Temp Sensor defines
400 400
  */
401 401
 
402
-#define ANY_TEMP_SENSOR_IS(n) (TEMP_SENSOR_0 == (n) || TEMP_SENSOR_1 == (n) || TEMP_SENSOR_2 == (n) || TEMP_SENSOR_3 == (n) || TEMP_SENSOR_4 == (n) || TEMP_SENSOR_5 == (n) || TEMP_SENSOR_6 == (n) || TEMP_SENSOR_7 == (n) || TEMP_SENSOR_BED == (n) || TEMP_SENSOR_PROBE == (n) || TEMP_SENSOR_CHAMBER == (n))
402
+#define ANY_TEMP_SENSOR_IS(n) (TEMP_SENSOR_0 == (n) || TEMP_SENSOR_1 == (n) || TEMP_SENSOR_2 == (n) || TEMP_SENSOR_3 == (n) || TEMP_SENSOR_4 == (n) || TEMP_SENSOR_5 == (n) || TEMP_SENSOR_6 == (n) || TEMP_SENSOR_7 == (n) || TEMP_SENSOR_BED == (n) || TEMP_SENSOR_PROBE == (n) || TEMP_SENSOR_CHAMBER == (n) || TEMP_SENSOR_COOLER == (n))
403 403
 
404 404
 #if ANY_TEMP_SENSOR_IS(1000)
405 405
   #define HAS_USER_THERMISTORS 1
@@ -744,6 +744,27 @@
744 744
   #undef CHAMBER_MAXTEMP
745 745
 #endif
746 746
 
747
+#if TEMP_SENSOR_COOLER == -4
748
+  #define COOLER_USES_AD8495 1
749
+#elif TEMP_SENSOR_COOLER == -3
750
+  #error "MAX31855 Thermocouples (-3) not supported for TEMP_SENSOR_COOLER."
751
+#elif TEMP_SENSOR_COOLER == -2
752
+  #error "MAX6675 Thermocouples (-2) not supported for TEMP_SENSOR_COOLER."
753
+#elif TEMP_SENSOR_COOLER == -1
754
+  #define COOLER_USES_AD595 1
755
+#elif TEMP_SENSOR_COOLER > 0
756
+  #define TEMP_SENSOR_COOLER_THERMISTOR_ID TEMP_SENSOR_COOLER
757
+  #define TEMP_SENSOR_COOLER_IS_THERMISTOR 1
758
+  #if TEMP_SENSOR_COOLER == 1000
759
+    #define COOLER_USER_THERMISTOR 1
760
+  #elif TEMP_SENSOR_COOLER == 998 || TEMP_SENSOR_COOLER == 999
761
+    #define COOLER_DUMMY_THERMISTOR 1
762
+  #endif
763
+#else
764
+  #undef COOLER_MINTEMP
765
+  #undef COOLER_MAXTEMP
766
+#endif
767
+
747 768
 #if TEMP_SENSOR_PROBE == -4
748 769
   #define TEMP_SENSOR_PROBE_IS_AD8495 1
749 770
 #elif TEMP_SENSOR_PROBE == -3
@@ -1928,6 +1949,9 @@
1928 1949
 #if HAS_ADC_TEST(CHAMBER)
1929 1950
   #define HAS_TEMP_ADC_CHAMBER 1
1930 1951
 #endif
1952
+#if HAS_ADC_TEST(COOLER)
1953
+  #define HAS_TEMP_ADC_COOLER 1
1954
+#endif
1931 1955
 
1932 1956
 #define HAS_TEMP(N) ANY(HAS_TEMP_ADC_##N, TEMP_SENSOR_##N##_IS_MAX_TC, TEMP_SENSOR_##N##_IS_DUMMY)
1933 1957
 #if HAS_HOTEND && HAS_TEMP(0)
@@ -1942,6 +1966,9 @@
1942 1966
 #if HAS_TEMP(CHAMBER)
1943 1967
   #define HAS_TEMP_CHAMBER 1
1944 1968
 #endif
1969
+#if HAS_TEMP(COOLER)
1970
+  #define HAS_TEMP_COOLER 1
1971
+#endif
1945 1972
 
1946 1973
 #if ENABLED(JOYSTICK)
1947 1974
   #if PIN_EXISTS(JOY_X)
@@ -2001,7 +2028,10 @@
2001 2028
 #if HAS_HEATED_BED || HAS_TEMP_CHAMBER
2002 2029
   #define BED_OR_CHAMBER 1
2003 2030
 #endif
2004
-#if HAS_TEMP_HOTEND || BED_OR_CHAMBER || HAS_TEMP_PROBE
2031
+#if HAS_TEMP_COOLER && PIN_EXISTS(COOLER)
2032
+  #define HAS_COOLER 1
2033
+#endif
2034
+#if HAS_TEMP_HOTEND || BED_OR_CHAMBER || HAS_TEMP_PROBE || HAS_TEMP_COOLER
2005 2035
   #define HAS_TEMP_SENSOR 1
2006 2036
 #endif
2007 2037
 
@@ -2033,9 +2063,13 @@
2033 2063
 #if BOTH(HAS_HEATED_CHAMBER, THERMAL_PROTECTION_CHAMBER) && WATCH_CHAMBER_TEMP_PERIOD > 0
2034 2064
   #define WATCH_CHAMBER 1
2035 2065
 #endif
2066
+#if BOTH(HAS_COOLER, THERMAL_PROTECTION_COOLER) && WATCH_COOLER_TEMP_PERIOD > 0
2067
+  #define WATCH_COOLER 1
2068
+#endif
2036 2069
 #if  (ENABLED(THERMAL_PROTECTION_HOTENDS) || !EXTRUDERS) \
2037 2070
   && (ENABLED(THERMAL_PROTECTION_BED)     || !HAS_HEATED_BED) \
2038
-  && (ENABLED(THERMAL_PROTECTION_CHAMBER) || !HAS_HEATED_CHAMBER)
2071
+  && (ENABLED(THERMAL_PROTECTION_CHAMBER) || !HAS_HEATED_CHAMBER) \
2072
+  && (ENABLED(THERMAL_PROTECTION_COOLER) || !HAS_COOLER)
2039 2073
   #define THERMALLY_SAFE 1
2040 2074
 #endif
2041 2075
 
@@ -2067,8 +2101,11 @@
2067 2101
 #if HAS_TEMP_CHAMBER && PIN_EXISTS(CHAMBER_AUTO_FAN)
2068 2102
   #define HAS_AUTO_CHAMBER_FAN 1
2069 2103
 #endif
2104
+#if HAS_TEMP_COOLER && PIN_EXISTS(COOLER_AUTO_FAN)
2105
+  #define HAS_AUTO_COOLER_FAN 1
2106
+#endif
2070 2107
 
2071
-#if ANY(HAS_AUTO_FAN_0, HAS_AUTO_FAN_1, HAS_AUTO_FAN_2, HAS_AUTO_FAN_3, HAS_AUTO_FAN_4, HAS_AUTO_FAN_5, HAS_AUTO_FAN_6, HAS_AUTO_FAN_7, HAS_AUTO_CHAMBER_FAN)
2108
+#if ANY(HAS_AUTO_FAN_0, HAS_AUTO_FAN_1, HAS_AUTO_FAN_2, HAS_AUTO_FAN_3, HAS_AUTO_FAN_4, HAS_AUTO_FAN_5, HAS_AUTO_FAN_6, HAS_AUTO_FAN_7, HAS_AUTO_CHAMBER_FAN, HAS_AUTO_COOLER_FAN)
2072 2109
   #define HAS_AUTO_FAN 1
2073 2110
 #endif
2074 2111
 #define _FANOVERLAP(A,B) (A##_AUTO_FAN_PIN == E##B##_AUTO_FAN_PIN)
@@ -2364,7 +2401,20 @@
2364 2401
   #define WRITE_HEATER_CHAMBER(v) WRITE(HEATER_CHAMBER_PIN, (v) ^ HEATER_CHAMBER_INVERTING)
2365 2402
 #endif
2366 2403
 
2367
-#if HAS_HOTEND || HAS_HEATED_BED || HAS_HEATED_CHAMBER
2404
+/**
2405
+ * Laser Cooling requires settings
2406
+ */
2407
+#if HAS_COOLER
2408
+  #ifndef MAX_COOLER_POWER
2409
+    #define MAX_COOLER_POWER 255
2410
+  #endif
2411
+  #ifndef COOLER_INVERTING
2412
+    #define COOLER_INVERTING true
2413
+  #endif
2414
+  #define WRITE_HEATER_COOLER(v) WRITE(COOLER_PIN, (v) ^ COOLER_INVERTING)
2415
+#endif
2416
+
2417
+#if HAS_HOTEND || HAS_HEATED_BED || HAS_HEATED_CHAMBER || HAS_COOLER
2368 2418
   #define HAS_TEMPERATURE 1
2369 2419
 #endif
2370 2420
 

+ 4
- 0
Marlin/src/inc/SanityCheck.h 查看文件

@@ -1876,6 +1876,10 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal
1876 1876
   #error "TEMP_SENSOR_CHAMBER requires TEMP_CHAMBER_PIN."
1877 1877
 #endif
1878 1878
 
1879
+#if TEMP_SENSOR_COOLER && !(PIN_EXISTS(TEMP_COOLER) && ENABLED(LASER_FEATURE))
1880
+  #error "TEMP_SENSOR_COOLER requires LASER_FEATURE and TEMP_COOLER_PIN."
1881
+#endif
1882
+
1879 1883
 #if ENABLED(CHAMBER_FAN) && !(defined(CHAMBER_FAN_MODE) && WITHIN(CHAMBER_FAN_MODE, 0, 2))
1880 1884
   #error "CHAMBER_FAN_MODE must be between 0 and 2."
1881 1885
 #endif

+ 58
- 0
Marlin/src/lcd/dogm/dogm_Statusscreen.h 查看文件

@@ -79,6 +79,16 @@
79 79
 #endif
80 80
 
81 81
 //
82
+// Laser Cooler
83
+//
84
+#if !STATUS_COOLER_WIDTH && HAS_COOLER
85
+  #include "status/cooler.h"
86
+#endif
87
+#ifndef STATUS_COOLER_WIDTH
88
+  #define STATUS_COOLER_WIDTH 0
89
+#endif
90
+
91
+//
82 92
 // Bed
83 93
 //
84 94
 #if !STATUS_BED_WIDTH && HAS_HEATED_BED && DISABLED(STATUS_COMBINE_HEATERS)
@@ -499,6 +509,47 @@
499 509
 #endif
500 510
 
501 511
 //
512
+// Cooler Bitmap Properties
513
+//
514
+#ifndef STATUS_COOLER_BYTEWIDTH
515
+  #define STATUS_COOLER_BYTEWIDTH BW(STATUS_COOLER_WIDTH)
516
+#endif
517
+#if STATUS_COOLER_WIDTH
518
+
519
+  #ifndef STATUS_COOLER_X
520
+    #define STATUS_COOLER_X (LCD_PIXEL_WIDTH - (STATUS_COOLER_BYTEWIDTH + STATUS_FAN_BYTEWIDTH + STATUS_CUTTER_BYTEWIDTH) * 8)
521
+  #endif
522
+
523
+  #ifndef STATUS_COOLER_HEIGHT
524
+    #ifdef STATUS_COOLER_ANIM
525
+      #define STATUS_COOLER_HEIGHT(S) ((S) ? sizeof(status_cooler_on_bmp) / (STATUS_COOLER_BYTEWIDTH) : sizeof(status_cooler_bmp) / (STATUS_COOLER_BYTEWIDTH))
526
+    #else
527
+      #define STATUS_COOLER_HEIGHT(S) (sizeof(status_cooler_bmp) / (STATUS_COOLER_BYTEWIDTH))
528
+    #endif
529
+  #endif
530
+
531
+  #ifndef STATUS_COOLER_Y
532
+    #define STATUS_COOLER_Y(S) (18 - STATUS_COOLER_HEIGHT(S))
533
+  #endif
534
+
535
+  #ifndef STATUS_COOLER_TEXT_X
536
+    #define STATUS_COOLER_TEXT_X (STATUS_COOLER_X + 8)
537
+  #endif
538
+
539
+  static_assert(
540
+    sizeof(status_cooler_bmp) == (STATUS_COOLER_BYTEWIDTH) * (STATUS_COOLER_HEIGHT(0)),
541
+    "Status cooler bitmap (status_cooler_bmp) dimensions don't match data."
542
+  );
543
+  #ifdef STATUS_COOLER_ANIM
544
+    static_assert(
545
+      sizeof(status_cooler_on_bmp) == (STATUS_COOLER_BYTEWIDTH) * (STATUS_COOLER_HEIGHT(1)),
546
+      "Status cooler bitmap (status_cooler_on_bmp) dimensions don't match data."
547
+    );
548
+  #endif
549
+
550
+#endif
551
+
552
+//
502 553
 // Bed Bitmap Properties
503 554
 //
504 555
 #ifndef STATUS_BED_BYTEWIDTH
@@ -585,6 +636,10 @@
585 636
 #if HAS_CUTTER && !DO_DRAW_BED
586 637
   #define DO_DRAW_CUTTER 1
587 638
 #endif
639
+#if HAS_COOLER
640
+  #define DO_DRAW_COOLER 1
641
+#endif
642
+
588 643
 #if HAS_TEMP_CHAMBER && STATUS_CHAMBER_WIDTH && HOTENDS <= 4
589 644
   #define DO_DRAW_CHAMBER 1
590 645
 #endif
@@ -603,6 +658,9 @@
603 658
 #if BOTH(DO_DRAW_CUTTER, STATUS_CUTTER_ANIM)
604 659
   #define ANIM_CUTTER 1
605 660
 #endif
661
+#if BOTH(DO_DRAW_COOLER, STATUS_COOLER_ANIM)
662
+  #define ANIM_COOLER 1
663
+#endif
606 664
 #if ANIM_HOTEND || ANIM_BED || ANIM_CHAMBER || ANIM_CUTTER
607 665
   #define ANIM_HBCC 1
608 666
 #endif

+ 70
- 0
Marlin/src/lcd/dogm/status/cooler.h 查看文件

@@ -0,0 +1,70 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
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.
12
+ *
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.
17
+ *
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/>.
20
+ *
21
+ */
22
+#pragma once
23
+
24
+//
25
+// lcd/dogm/status/cooler.h - Status Screen Laser Cooler bitmaps
26
+//
27
+
28
+#define STATUS_COOLER_WIDTH 16
29
+
30
+#ifdef STATUS_COOLER_ANIM
31
+
32
+  const unsigned char status_cooler_on_bmp[] PROGMEM = {
33
+    B00010000,B00001000,
34
+    B00010010,B01001001,
35
+    B01010100,B00101010,
36
+    B00111000,B00011100,
37
+    B11111110,B11111111,
38
+    B00111000,B00011100,
39
+    B01010100,B00101010,
40
+    B10010000,B10001001,
41
+    B00010000,B10000000,
42
+    B00000100,B10010000,
43
+    B00000010,B10100000,
44
+    B00000001,B11000000,
45
+    B00011111,B11111100,
46
+    B00000001,B11000000,
47
+    B00000010,B10100000,
48
+    B00000100,B10010000
49
+  };
50
+
51
+#endif
52
+
53
+const unsigned char status_cooler_bmp[] PROGMEM = {
54
+  B00010000,B00001000,
55
+  B00010010,B01001001,
56
+  B01010100,B00101010,
57
+  B00101000,B00010100,
58
+  B11000111,B01100011,
59
+  B00101000,B00010100,
60
+  B01010100,B00101010,
61
+  B10010000,B10001001,
62
+  B00010000,B10000000,
63
+  B00000100,B10010000,
64
+  B00000010,B10100000,
65
+  B00000001,B01000000,
66
+  B00011110,B00111100,
67
+  B00000001,B01000000,
68
+  B00000010,B10100000,
69
+  B00000100,B10010000
70
+};

+ 32
- 3
Marlin/src/lcd/dogm/status_screen_DOGM.cpp 查看文件

@@ -86,6 +86,7 @@
86 86
     HEATBIT_HOTEND,
87 87
     HEATBIT_BED = HOTENDS,
88 88
     HEATBIT_CHAMBER,
89
+    HEATBIT_COOLER,
89 90
     HEATBIT_CUTTER
90 91
   };
91 92
   IF<(HEATBIT_CUTTER > 7), uint16_t, uint8_t>::type heat_bits;
@@ -111,6 +112,11 @@
111 112
 #else
112 113
   #define CUTTER_ALT() false
113 114
 #endif
115
+#if ANIM_COOLER
116
+  #define COOLER_ALT(N) TEST(heat_bits, HEATBIT_COOLER)
117
+#else
118
+  #define COOLER_ALT() false
119
+#endif
114 120
 
115 121
 #if DO_DRAW_HOTENDS
116 122
   #define MAX_HOTEND_DRAW _MIN(HOTENDS, ((LCD_PIXEL_WIDTH - (STATUS_LOGO_BYTEWIDTH + STATUS_FAN_BYTEWIDTH) * 8) / (STATUS_HEATERS_XSPACE)))
@@ -361,18 +367,22 @@ FORCE_INLINE void _draw_centered_temp(const int16_t temp, const uint8_t tx, cons
361 367
 #endif // DO_DRAW_BED
362 368
 
363 369
 #if DO_DRAW_CHAMBER
364
-
365 370
   FORCE_INLINE void _draw_chamber_status() {
366 371
     #if HAS_HEATED_CHAMBER
367 372
       if (PAGE_UNDER(7))
368 373
         _draw_centered_temp(thermalManager.degTargetChamber() + 0.5f, STATUS_CHAMBER_TEXT_X, 7);
369 374
     #endif
370
-
371 375
     if (PAGE_CONTAINS(28 - INFO_FONT_ASCENT, 28 - 1))
372 376
       _draw_centered_temp(thermalManager.degChamber() + 0.5f, STATUS_CHAMBER_TEXT_X, 28);
373 377
   }
378
+#endif
374 379
 
375
-#endif // DO_DRAW_CHAMBER
380
+#if DO_DRAW_COOLER
381
+  FORCE_INLINE void _draw_cooler_status() {
382
+    if (PAGE_CONTAINS(28 - INFO_FONT_ASCENT, 28 - 1))
383
+      _draw_centered_temp(thermalManager.degCooler(), STATUS_COOLER_TEXT_X, 28);
384
+  }
385
+#endif
376 386
 
377 387
 //
378 388
 // Before homing, blink '123' <-> '???'.
@@ -447,6 +457,9 @@ void MarlinUI::draw_status_screen() {
447 457
       #if DO_DRAW_CHAMBER && HAS_HEATED_CHAMBER
448 458
         if (thermalManager.isHeatingChamber()) SBI(new_bits, HEATBIT_CHAMBER);
449 459
       #endif
460
+      #if DO_DRAW_COOLER && HAS_COOLER
461
+        if (thermalManager.isLaserCooling()) SBI(new_bits, HEATBIT_COOLER);
462
+      #endif
450 463
       if (TERN0(ANIM_CUTTER, cutter.enabled())) SBI(new_bits, HEATBIT_CUTTER);
451 464
       heat_bits = new_bits;
452 465
     #endif
@@ -631,12 +644,28 @@ void MarlinUI::draw_status_screen() {
631 644
       }
632 645
     #endif
633 646
 
647
+    // Laser Cooler
648
+    #if DO_DRAW_COOLER
649
+      #if ANIM_COOLER
650
+        #define COOLER_BITMAP(S) ((S) ? status_cooler_bmp : status_cooler_on_bmp)
651
+      #else
652
+        #define COOLER_BITMAP(S) status_cooler_bmp
653
+      #endif
654
+      const uint8_t coolery = STATUS_COOLER_Y(COOLER_ALT()),
655
+                    coolerh = STATUS_COOLER_HEIGHT(COOLER_ALT());
656
+      if (PAGE_CONTAINS(coolery, coolery + coolerh - 1))
657
+        u8g.drawBitmapP(STATUS_COOLER_X, coolery, STATUS_COOLER_BYTEWIDTH, coolerh, COOLER_BITMAP(COOLER_ALT()));
658
+    #endif
659
+
634 660
     // Heated Bed
635 661
     TERN_(DO_DRAW_BED, _draw_bed_status(blink));
636 662
 
637 663
     // Heated Chamber
638 664
     TERN_(DO_DRAW_CHAMBER, _draw_chamber_status());
639 665
 
666
+    // Cooler
667
+    TERN_(DO_DRAW_COOLER, _draw_cooler_status());
668
+
640 669
     // Fan, if a bitmap was provided
641 670
     #if DO_DRAW_FAN
642 671
       if (PAGE_CONTAINS(STATUS_FAN_TEXT_Y - INFO_FONT_ASCENT, STATUS_FAN_TEXT_Y - 1)) {

+ 14
- 12
Marlin/src/lcd/extui/ui_api.cpp 查看文件

@@ -176,6 +176,7 @@ namespace ExtUI {
176 176
           case BED: thermalManager.reset_bed_idle_timer(); return;
177 177
         #endif
178 178
         TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return); // Chamber has no idle timer
179
+        TERN_(HAS_COOLER, case COOLER: return); // Cooler has no idle timer
179 180
         default:
180 181
           TERN_(HAS_HOTEND, thermalManager.reset_hotend_idle_timer(heater - H0));
181 182
           break;
@@ -904,22 +905,23 @@ namespace ExtUI {
904 905
       value *= TOUCH_UI_LCD_TEMP_SCALING;
905 906
     #endif
906 907
     enableHeater(heater);
907
-    #if HAS_HEATED_CHAMBER
908
-      if (heater == CHAMBER)
909
-        thermalManager.setTargetChamber(LROUND(constrain(value, 0, CHAMBER_MAXTEMP - 10)));
910
-      else
911
-    #endif
912
-    #if HAS_HEATED_BED
913
-      if (heater == BED)
914
-        thermalManager.setTargetBed(LROUND(constrain(value, 0, BED_MAX_TARGET)));
915
-      else
916
-    #endif
917
-      {
908
+    switch (heater) {
909
+      #if HAS_HEATED_CHAMBER
910
+        case CHAMBER: thermalManager.setTargetChamber(LROUND(constrain(value, 0, CHAMBER_MAXTEMP - 10))); break;
911
+      #endif
912
+      #if HAS_COOLER
913
+        case COOLER: thermalManager.setTargetCooler(LROUND(constrain(value, 0, COOLER_MAXTEMP))); break;
914
+      #endif
915
+      #if HAS_HEATED_BED
916
+        case BED: thermalManager.setTargetBed(LROUND(constrain(value, 0, BED_MAX_TARGET))); break;
917
+      #endif
918
+      default: {
918 919
         #if HAS_HOTEND
919 920
           const int16_t e = heater - H0;
920 921
           thermalManager.setTargetHotend(LROUND(constrain(value, 0, thermalManager.heater_maxtemp[e] - HOTEND_OVERSHOOT)), e);
921 922
         #endif
922
-      }
923
+      } break;
924
+    }
923 925
   }
924 926
 
925 927
   void setTargetTemp_celsius(float value, const extruder_t extruder) {

+ 1
- 1
Marlin/src/lcd/extui/ui_api.h 查看文件

@@ -55,7 +55,7 @@ namespace ExtUI {
55 55
 
56 56
   enum axis_t     : uint8_t { X, Y, Z, X2, Y2, Z2, Z3, Z4 };
57 57
   enum extruder_t : uint8_t { E0, E1, E2, E3, E4, E5, E6, E7 };
58
-  enum heater_t   : uint8_t { H0, H1, H2, H3, H4, H5, BED, CHAMBER };
58
+  enum heater_t   : uint8_t { H0, H1, H2, H3, H4, H5, BED, CHAMBER, COOLER };
59 59
   enum fan_t      : uint8_t { FAN0, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7 };
60 60
   enum result_t   : uint8_t { PID_BAD_EXTRUDER_NUM, PID_TEMP_TOO_HIGH, PID_TUNING_TIMEOUT, PID_DONE };
61 61
 

+ 6
- 0
Marlin/src/lcd/language/language_en.h 查看文件

@@ -276,6 +276,9 @@ namespace Language_en {
276 276
   PROGMEM Language_Str MSG_NOZZLE_STANDBY                  = _UxGT("Nozzle Standby");
277 277
   PROGMEM Language_Str MSG_BED                             = _UxGT("Bed");
278 278
   PROGMEM Language_Str MSG_CHAMBER                         = _UxGT("Enclosure");
279
+  PROGMEM Language_Str MSG_COOLER                          = _UxGT("Laser Coolant");
280
+  PROGMEM Language_Str MSG_COOLER_TOGGLE                   = _UxGT("Toggle Cooler");
281
+  PROGMEM Language_Str MSG_LASER                           = _UxGT("Laser");
279 282
   PROGMEM Language_Str MSG_FAN_SPEED                       = _UxGT("Fan Speed");
280 283
   PROGMEM Language_Str MSG_FAN_SPEED_N                     = _UxGT("Fan Speed ~");
281 284
   PROGMEM Language_Str MSG_STORED_FAN_N                    = _UxGT("Stored Fan ~");
@@ -482,6 +485,8 @@ namespace Language_en {
482 485
   PROGMEM Language_Str MSG_THERMAL_RUNAWAY                 = _UxGT("THERMAL RUNAWAY");
483 486
   PROGMEM Language_Str MSG_THERMAL_RUNAWAY_BED             = _UxGT("BED THERMAL RUNAWAY");
484 487
   PROGMEM Language_Str MSG_THERMAL_RUNAWAY_CHAMBER         = _UxGT("CHAMBER T. RUNAWAY");
488
+  PROGMEM Language_Str MSG_THERMAL_RUNAWAY_COOLER          = _UxGT("Cooler Runaway");
489
+  PROGMEM Language_Str MSG_COOLING_FAILED                  = _UxGT("Cooling Failed");
485 490
   PROGMEM Language_Str MSG_ERR_MAXTEMP                     = _UxGT("Err: MAXTEMP");
486 491
   PROGMEM Language_Str MSG_ERR_MINTEMP                     = _UxGT("Err: MINTEMP");
487 492
   PROGMEM Language_Str MSG_HALTED                          = _UxGT("PRINTER HALTED");
@@ -497,6 +502,7 @@ namespace Language_en {
497 502
   PROGMEM Language_Str MSG_PROBE_COOLING                   = _UxGT("Probe Cooling...");
498 503
   PROGMEM Language_Str MSG_CHAMBER_HEATING                 = _UxGT("Chamber Heating...");
499 504
   PROGMEM Language_Str MSG_CHAMBER_COOLING                 = _UxGT("Chamber Cooling...");
505
+  PROGMEM Language_Str MSG_LASER_COOLING                   = _UxGT("Laser Cooling...");
500 506
   PROGMEM Language_Str MSG_DELTA_CALIBRATE                 = _UxGT("Delta Calibration");
501 507
   PROGMEM Language_Str MSG_DELTA_CALIBRATE_X               = _UxGT("Calibrate X");
502 508
   PROGMEM Language_Str MSG_DELTA_CALIBRATE_Y               = _UxGT("Calibrate Y");

+ 10
- 0
Marlin/src/lcd/menu/menu_info.cpp 查看文件

@@ -195,6 +195,16 @@ void menu_info_thermistors() {
195 195
     STATIC_ITEM(TERN(WATCH_CHAMBER, MSG_INFO_RUNAWAY_ON, MSG_INFO_RUNAWAY_OFF), SS_LEFT);
196 196
   #endif
197 197
 
198
+  #if HAS_COOLER
199
+    #undef THERMISTOR_ID
200
+    #define THERMISTOR_ID TEMP_SENSOR_COOLER
201
+    #include "../thermistornames.h"
202
+    STATIC_ITEM_P(PSTR("COOL: " THERMISTOR_NAME), SS_INVERT);
203
+    PSTRING_ITEM(MSG_INFO_MIN_TEMP, STRINGIFY(COOLER_MINTEMP), SS_LEFT);
204
+    PSTRING_ITEM(MSG_INFO_MAX_TEMP, STRINGIFY(COOLER_MAXTEMP), SS_LEFT);
205
+    STATIC_ITEM(TERN(WATCH_COOLER, MSG_INFO_RUNAWAY_ON, MSG_INFO_RUNAWAY_OFF), SS_LEFT);
206
+  #endif
207
+
198 208
   END_SCREEN();
199 209
 }
200 210
 

+ 22
- 1
Marlin/src/lcd/menu/menu_temperature.cpp 查看文件

@@ -35,6 +35,10 @@
35 35
   #include "../../module/motion.h"
36 36
 #endif
37 37
 
38
+#if HAS_COOLER
39
+  #include "../../feature/cooler.h"
40
+#endif
41
+
38 42
 #if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
39 43
   #include "../../module/tool_change.h"
40 44
 #endif
@@ -68,6 +72,10 @@ void Temperature::lcd_preheat(const int16_t e, const int8_t indh, const int8_t i
68 72
   #if HAS_HEATED_BED
69 73
     inline void _preheat_bed(const uint8_t m) { thermalManager.lcd_preheat(-1, -1, m); }
70 74
   #endif
75
+  #if HAS_COOLER
76
+    inline void _precool_laser(const uint8_t m, const uint8_t e) { thermalManager.lcd_preheat(e, m, -1); }
77
+    void do_precool_laser_m() { _precool_laser(editable.int8, thermalManager.temp_cooler.target); }
78
+  #endif
71 79
 
72 80
   #if HAS_TEMP_HOTEND && HAS_HEATED_BED
73 81
     inline void _preheat_both(const uint8_t m, const uint8_t e) { thermalManager.lcd_preheat(e, m, m); }
@@ -143,6 +151,10 @@ void menu_temperature() {
143 151
     #endif
144 152
   #endif
145 153
 
154
+  #if HAS_COOLER
155
+    if (thermalManager.temp_cooler.target == 0) thermalManager.temp_cooler.target = COOLER_DEFAULT_TEMP;
156
+  #endif
157
+
146 158
   START_MENU();
147 159
   BACK_ITEM(MSG_MAIN);
148 160
 
@@ -177,6 +189,15 @@ void menu_temperature() {
177 189
   #endif
178 190
 
179 191
   //
192
+  // Cooler:
193
+  //
194
+  #if HAS_COOLER
195
+    editable.state = cooler.is_enabled();
196
+    EDIT_ITEM(bool, MSG_COOLER(TOGGLE), &cooler.state, []{ if (editable.state) cooler.disable(); else cooler.enable(); });
197
+    EDIT_ITEM_FAST(int3, MSG_COOLER, &thermalManager.temp_cooler.target, COOLER_MINTEMP + 2, COOLER_MAXTEMP - 2, thermalManager.start_watching_cooler);
198
+  #endif
199
+
200
+  //
180 201
   // Fan Speed:
181 202
   //
182 203
   #if HAS_FAN
@@ -232,7 +253,7 @@ void menu_temperature() {
232 253
       editable.int8 = m;
233 254
       #if HOTENDS > 1 || HAS_HEATED_BED
234 255
         SUBMENU_S(ui.get_preheat_label(m), MSG_PREHEAT_M, menu_preheat_m);
235
-      #else
256
+      #elif HAS_HOTEND
236 257
         ACTION_ITEM_S(ui.get_preheat_label(m), MSG_PREHEAT_M, do_preheat_end_m);
237 258
       #endif
238 259
     }

+ 3
- 0
Marlin/src/lcd/tft/tft_color.h 查看文件

@@ -94,6 +94,9 @@
94 94
 #ifndef COLOR_CHAMBER
95 95
   #define COLOR_CHAMBER           COLOR_DARK_ORANGE
96 96
 #endif
97
+#ifndef COLOR_COOLER
98
+  #define COLOR_COOLER            COLOR_DARK_ORANGE
99
+#endif
97 100
 #ifndef COLOR_FAN
98 101
   #define COLOR_FAN               COLOR_AQUA
99 102
 #endif

+ 6
- 0
Marlin/src/lcd/tft/touch.cpp 查看文件

@@ -202,6 +202,12 @@ void Touch::touch(touch_control_t *control) {
202 202
           MenuItem_int3::action((const char *)GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAXTEMP - 10, thermalManager.start_watching_chamber);
203 203
         }
204 204
       #endif
205
+      #if HAS_COOLER
206
+        else if (heater == H_COOLER) {
207
+          MenuItem_int3::action((const char *)GET_TEXT_F(MSG_COOLER), &thermalManager.temp_cooler.target, 0, COOLER_MAXTEMP - 8, thermalManager.start_watching_cooler);
208
+        }
209
+      #endif
210
+
205 211
       break;
206 212
     case FAN:
207 213
       ui.clear_lcd();

+ 13
- 0
Marlin/src/lcd/tft/ui_320x240.cpp 查看文件

@@ -136,6 +136,12 @@ void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater) {
136 136
       #endif
137 137
     }
138 138
   #endif
139
+  #if HAS_TEMP_COOLER
140
+    else if (Heater == H_COOLER) {
141
+      currentTemperature = thermalManager.degCooler();
142
+      targetTemperature = TERN(HAS_COOLER, thermalManager.degTargetCooler(), ABSOLUTE_ZERO);
143
+    }
144
+  #endif
139 145
   else return;
140 146
 
141 147
   TERN_(TOUCH_SCREEN, if (targetTemperature >= 0) touch.add_control(HEATER, x, y, 64, 100, Heater));
@@ -159,6 +165,13 @@ void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater) {
159 165
       image = targetTemperature > 0 ? imgChamberHeated : imgChamber;
160 166
     }
161 167
   #endif
168
+  #if HAS_TEMP_COOLER
169
+    else if (Heater == H_COOLER) {
170
+      if (currentTemperature <= 26) Color = COLOR_COLD;
171
+      if (currentTemperature > 26) Color = COLOR_RED;
172
+      image = targetTemperature > 26 ? imgCoolerHot : imgCooler;
173
+    }
174
+  #endif
162 175
 
163 176
   tft.add_image(0, 18, image, Color);
164 177
 

+ 6
- 0
Marlin/src/lcd/tft/ui_480x320.cpp 查看文件

@@ -136,6 +136,12 @@ void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater) {
136 136
       #endif
137 137
     }
138 138
   #endif
139
+  #if HAS_TEMP_COOLER
140
+    else if (Heater == H_COOLER) {
141
+      currentTemperature = thermalManager.degCooler();
142
+      targetTemperature = TERN(HAS_COOLER, thermalManager.degTargetCooler(), ABSOLUTE_ZERO);
143
+    }
144
+  #endif
139 145
   else return;
140 146
 
141 147
   TERN_(TOUCH_SCREEN, if (targetTemperature >= 0) touch.add_control(HEATER, x, y, 80, 120, Heater));

+ 4
- 0
Marlin/src/lcd/tft/ui_common.h 查看文件

@@ -62,6 +62,10 @@ void menu_item(const uint8_t row, bool sel = false);
62 62
   #define ITEM_CHAMBER    2
63 63
   #define ITEM_FAN        3
64 64
   #define ITEMS_COUNT     4
65
+#elif HAS_TEMP_COOLER
66
+  #define ITEM_COOLER     0
67
+  #define ITEM_FAN        1
68
+  #define ITEMS_COUNT     2
65 69
 #elif HOTENDS > 1
66 70
   #define ITEM_E0         0
67 71
   #define ITEM_E1         1

+ 342
- 38
Marlin/src/module/temperature.cpp 查看文件

@@ -35,6 +35,11 @@
35 35
 #include "endstops.h"
36 36
 #include "planner.h"
37 37
 
38
+#if HAS_COOLER
39
+  #include "../feature/cooler.h"
40
+  #include "../feature/spindle_laser.h"
41
+#endif
42
+
38 43
 #if ENABLED(EMERGENCY_PARSER)
39 44
   #include "motion.h"
40 45
 #endif
@@ -232,8 +237,13 @@ const char str_t_thermal_runaway[] PROGMEM = STR_T_THERMAL_RUNAWAY,
232 237
 #else
233 238
   #define _CHAMBER_PSTR(h)
234 239
 #endif
240
+#if HAS_COOLER
241
+  #define _COOLER_PSTR(h) (h) == H_COOLER ? GET_TEXT(MSG_COOLER) :
242
+#else
243
+  #define _COOLER_PSTR(h)
244
+#endif
235 245
 #define _E_PSTR(h,N) ((HOTENDS) > N && (h) == N) ? PSTR(LCD_STR_E##N) :
236
-#define HEATER_PSTR(h) _BED_PSTR(h) _CHAMBER_PSTR(h) _E_PSTR(h,1) _E_PSTR(h,2) _E_PSTR(h,3) _E_PSTR(h,4) _E_PSTR(h,5) PSTR(LCD_STR_E0)
246
+#define HEATER_PSTR(h) _BED_PSTR(h) _CHAMBER_PSTR(h) _COOLER_PSTR(h) _E_PSTR(h,1) _E_PSTR(h,2) _E_PSTR(h,3) _E_PSTR(h,4) _E_PSTR(h,5) PSTR(LCD_STR_E0)
237 247
 
238 248
 // public:
239 249
 
@@ -254,6 +264,9 @@ const char str_t_thermal_runaway[] PROGMEM = STR_T_THERMAL_RUNAWAY,
254 264
   uint8_t Temperature::chamberfan_speed; // = 0
255 265
 #endif
256 266
 
267
+#if ENABLED(AUTO_POWER_COOLER_FAN)
268
+  uint8_t Temperature::coolerfan_speed; // = 0
269
+#endif
257 270
 #if HAS_FAN
258 271
 
259 272
   uint8_t Temperature::fan_speed[FAN_COUNT]; // = { 0 }
@@ -355,14 +368,11 @@ const char str_t_thermal_runaway[] PROGMEM = STR_T_THERMAL_RUNAWAY,
355 368
   #endif
356 369
   TERN_(WATCH_BED, bed_watch_t Temperature::watch_bed); // = { 0 }
357 370
   IF_DISABLED(PIDTEMPBED, millis_t Temperature::next_bed_check_ms);
358
-#endif // HAS_HEATED_BED
371
+#endif
359 372
 
360 373
 #if HAS_TEMP_CHAMBER
361 374
   chamber_info_t Temperature::temp_chamber; // = { 0 }
362 375
   #if HAS_HEATED_CHAMBER
363
-    int16_t fan_chamber_pwm;
364
-    bool flag_chamber_off;
365
-    bool flag_chamber_excess_heat = false;
366 376
     millis_t next_cool_check_ms_2 = 0;
367 377
     float old_temp = 9999;
368 378
     #ifdef CHAMBER_MINTEMP
@@ -373,8 +383,27 @@ const char str_t_thermal_runaway[] PROGMEM = STR_T_THERMAL_RUNAWAY,
373 383
     #endif
374 384
     TERN_(WATCH_CHAMBER, chamber_watch_t Temperature::watch_chamber{0});
375 385
     IF_DISABLED(PIDTEMPCHAMBER, millis_t Temperature::next_chamber_check_ms);
376
-  #endif // HAS_HEATED_CHAMBER
377
-#endif // HAS_TEMP_CHAMBER
386
+  #endif
387
+#endif
388
+
389
+#if HAS_TEMP_COOLER
390
+  cooler_info_t Temperature::temp_cooler; // = { 0 }
391
+  #if HAS_COOLER
392
+    bool flag_cooler_state;
393
+    //bool flag_cooler_excess = false;
394
+    float previous_temp = 9999;
395
+    #ifdef COOLER_MINTEMP
396
+      int16_t Temperature::mintemp_raw_COOLER = TEMP_SENSOR_COOLER_RAW_LO_TEMP;
397
+    #endif
398
+    #ifdef COOLER_MAXTEMP
399
+      int16_t Temperature::maxtemp_raw_COOLER = TEMP_SENSOR_COOLER_RAW_HI_TEMP;
400
+    #endif
401
+    #if WATCH_COOLER
402
+      cooler_watch_t Temperature::watch_cooler{0};
403
+    #endif
404
+    millis_t Temperature::next_cooler_check_ms, Temperature::cooler_fan_flush_ms;
405
+  #endif
406
+#endif
378 407
 
379 408
 #if HAS_TEMP_PROBE
380 409
   probe_info_t Temperature::temp_probe; // = { 0 }
@@ -744,6 +773,9 @@ int16_t Temperature::getHeaterPower(const heater_id_t heater_id) {
744 773
     #if HAS_HEATED_CHAMBER
745 774
       case H_CHAMBER: return temp_chamber.soft_pwm_amount;
746 775
     #endif
776
+    #if HAS_COOLER
777
+      case H_COOLER: return temp_cooler.soft_pwm_amount;
778
+    #endif
747 779
     default:
748 780
       return TERN0(HAS_HOTEND, temp_hotend[heater_id].soft_pwm_amount);
749 781
   }
@@ -779,6 +811,11 @@ int16_t Temperature::getHeaterPower(const heater_id_t heater_id) {
779 811
         SBI(fanState, pgm_read_byte(&fanBit[CHAMBER_FAN_INDEX]));
780 812
     #endif
781 813
 
814
+    #if HAS_AUTO_COOLER_FAN
815
+      if (temp_cooler.celsius >= COOLER_AUTO_FAN_TEMPERATURE)
816
+        SBI(fanState, pgm_read_byte(&fanBit[COOLER_FAN_INDEX]));
817
+    #endif
818
+
782 819
     #define _UPDATE_AUTO_FAN(P,D,A) do{                  \
783 820
       if (PWM_PIN(P##_AUTO_FAN_PIN) && A < 255)          \
784 821
         analogWrite(pin_t(P##_AUTO_FAN_PIN), D ? A : 0); \
@@ -874,6 +911,8 @@ void Temperature::_temp_error(const heater_id_t heater_id, PGM_P const serial_ms
874 911
       SERIAL_ECHO(heater_id);
875 912
     else if (TERN0(HAS_HEATED_CHAMBER, heater_id == H_CHAMBER))
876 913
       SERIAL_ECHOPGM(STR_HEATER_CHAMBER);
914
+    else if (TERN0(HAS_COOLER, heater_id == H_COOLER))
915
+      SERIAL_ECHOPGM(STR_COOLER);
877 916
     else
878 917
       SERIAL_ECHOPGM(STR_HEATER_BED);
879 918
     SERIAL_EOL();
@@ -1347,11 +1386,18 @@ void Temperature::manage_heater() {
1347 1386
       }
1348 1387
     #endif
1349 1388
 
1389
+    #if EITHER(CHAMBER_FAN, CHAMBER_VENT) || DISABLED(PIDTEMPCHAMBER)
1390
+      static bool flag_chamber_excess_heat; // = false;
1391
+    #endif
1392
+
1350 1393
     #if EITHER(CHAMBER_FAN, CHAMBER_VENT)
1394
+      static bool flag_chamber_off; // = false
1395
+
1351 1396
       if (temp_chamber.target > CHAMBER_MINTEMP) {
1352 1397
         flag_chamber_off = false;
1353 1398
 
1354 1399
         #if ENABLED(CHAMBER_FAN)
1400
+          int16_t fan_chamber_pwm;
1355 1401
           #if CHAMBER_FAN_MODE == 0
1356 1402
             fan_chamber_pwm = CHAMBER_FAN_BASE;
1357 1403
           #elif CHAMBER_FAN_MODE == 1
@@ -1376,7 +1422,8 @@ void Temperature::manage_heater() {
1376 1422
             // Open vent after MIN_COOLING_SLOPE_TIME_CHAMBER_VENT seconds if the
1377 1423
             // temperature didn't drop at least MIN_COOLING_SLOPE_DEG_CHAMBER_VENT
1378 1424
             if (next_cool_check_ms_2 == 0 || ELAPSED(ms, next_cool_check_ms_2)) {
1379
-              if (old_temp - temp_chamber.celsius < float(MIN_COOLING_SLOPE_DEG_CHAMBER_VENT)) flag_chamber_excess_heat = true; //the bed is heating the chamber too much
1425
+              if (temp_chamber.celsius - old_temp > MIN_COOLING_SLOPE_DEG_CHAMBER_VENT)
1426
+                flag_chamber_excess_heat = true; // the bed is heating the chamber too much
1380 1427
               next_cool_check_ms_2 = ms + SEC_TO_MS(MIN_COOLING_SLOPE_TIME_CHAMBER_VENT);
1381 1428
               old_temp = temp_chamber.celsius;
1382 1429
             }
@@ -1385,9 +1432,8 @@ void Temperature::manage_heater() {
1385 1432
             next_cool_check_ms_2 = 0;
1386 1433
             old_temp = 9999;
1387 1434
           }
1388
-          if (flag_chamber_excess_heat && (temp_chamber.celsius - temp_chamber.target <= -LOW_EXCESS_HEAT_LIMIT) ) {
1435
+          if (flag_chamber_excess_heat && (temp_chamber.target - temp_chamber.celsius >= LOW_EXCESS_HEAT_LIMIT))
1389 1436
             flag_chamber_excess_heat = false;
1390
-          }
1391 1437
         #endif
1392 1438
       }
1393 1439
       else if (!flag_chamber_off) {
@@ -1402,17 +1448,14 @@ void Temperature::manage_heater() {
1402 1448
       }
1403 1449
     #endif
1404 1450
 
1405
-
1406
-
1407
-
1408 1451
     #if ENABLED(PIDTEMPCHAMBER)
1409 1452
       // PIDTEMPCHAMBER doens't support a CHAMBER_VENT yet.
1410 1453
       temp_chamber.soft_pwm_amount = WITHIN(temp_chamber.celsius, CHAMBER_MINTEMP, CHAMBER_MAXTEMP) ? (int)get_pid_output_chamber() >> 1 : 0;
1411 1454
     #else
1412
-    if (ELAPSED(ms, next_chamber_check_ms)) {
1413
-      next_chamber_check_ms = ms + CHAMBER_CHECK_INTERVAL;
1455
+      if (ELAPSED(ms, next_chamber_check_ms)) {
1456
+        next_chamber_check_ms = ms + CHAMBER_CHECK_INTERVAL;
1414 1457
 
1415
-      if (WITHIN(temp_chamber.celsius, CHAMBER_MINTEMP, CHAMBER_MAXTEMP)) {
1458
+        if (WITHIN(temp_chamber.celsius, CHAMBER_MINTEMP, CHAMBER_MAXTEMP)) {
1416 1459
           if (flag_chamber_excess_heat) {
1417 1460
             temp_chamber.soft_pwm_amount = 0;
1418 1461
             #if ENABLED(CHAMBER_VENT)
@@ -1437,7 +1480,6 @@ void Temperature::manage_heater() {
1437 1480
           temp_chamber.soft_pwm_amount = 0;
1438 1481
           WRITE_HEATER_CHAMBER(LOW);
1439 1482
         }
1440
-
1441 1483
      }
1442 1484
      #if ENABLED(THERMAL_PROTECTION_CHAMBER)
1443 1485
        tr_state_machine[RUNAWAY_IND_CHAMBER].run(temp_chamber.celsius, temp_chamber.target, H_CHAMBER, THERMAL_PROTECTION_CHAMBER_PERIOD, THERMAL_PROTECTION_CHAMBER_HYSTERESIS);
@@ -1446,6 +1488,66 @@ void Temperature::manage_heater() {
1446 1488
 
1447 1489
   #endif // HAS_HEATED_CHAMBER
1448 1490
 
1491
+  #if HAS_COOLER
1492
+
1493
+    #ifndef COOLER_CHECK_INTERVAL
1494
+      #define COOLER_CHECK_INTERVAL 2000UL
1495
+    #endif
1496
+
1497
+    #if ENABLED(THERMAL_PROTECTION_COOLER)
1498
+      if (degCooler() > COOLER_MAXTEMP) max_temp_error(H_COOLER);
1499
+    #endif
1500
+
1501
+    #if WATCH_COOLER
1502
+      // Make sure temperature is decreasing
1503
+      if (watch_cooler.elapsed(ms)) {             // Time to check the cooler?
1504
+        if (degCooler() > watch_cooler.target)    // Failed to decrease enough?
1505
+          _temp_error(H_COOLER, GET_TEXT(MSG_COOLING_FAILED), GET_TEXT(MSG_COOLING_FAILED));
1506
+        else
1507
+          start_watching_cooler();                 // Start again if the target is still far off
1508
+      }
1509
+    #endif
1510
+
1511
+    static bool flag_cooler_state; // = false
1512
+
1513
+    if (cooler.is_enabled()) {
1514
+      flag_cooler_state = true; // used to allow M106 fan control when cooler is disabled
1515
+      if (temp_cooler.target == 0) temp_cooler.target = COOLER_MINTEMP;
1516
+      if (ELAPSED(ms, next_cooler_check_ms)) {
1517
+        next_cooler_check_ms = ms + COOLER_CHECK_INTERVAL;
1518
+        if (temp_cooler.celsius > temp_cooler.target) {
1519
+          temp_cooler.soft_pwm_amount = temp_cooler.celsius > temp_cooler.target ? MAX_COOLER_POWER : 0;
1520
+          flag_cooler_state = temp_cooler.soft_pwm_amount > 0 ? true : false; // used to allow M106 fan control when cooler is disabled
1521
+          #if ENABLED(COOLER_FAN)
1522
+            int16_t fan_cooler_pwm = (COOLER_FAN_BASE) + (COOLER_FAN_FACTOR) * ABS(temp_cooler.celsius - temp_cooler.target);
1523
+            NOMORE(fan_cooler_pwm, 255);
1524
+            set_fan_speed(COOLER_FAN_INDEX, fan_cooler_pwm); // Set cooler fan pwm
1525
+            cooler_fan_flush_ms = ms + 5000;
1526
+          #endif
1527
+        }
1528
+        else {
1529
+          temp_cooler.soft_pwm_amount = 0;
1530
+          #if ENABLED(COOLER_FAN)
1531
+            set_fan_speed(COOLER_FAN_INDEX, temp_cooler.celsius > temp_cooler.target - 2 ? COOLER_FAN_BASE : 0);
1532
+          #endif
1533
+          WRITE_HEATER_COOLER(LOW);
1534
+        }
1535
+      }
1536
+    }
1537
+    else {
1538
+      temp_cooler.soft_pwm_amount = 0;
1539
+      if (flag_cooler_state) {
1540
+        flag_cooler_state = false;
1541
+        thermalManager.set_fan_speed(COOLER_FAN_INDEX, 0);
1542
+      }
1543
+      WRITE_HEATER_COOLER(LOW);
1544
+    }
1545
+
1546
+    #if ENABLED(THERMAL_PROTECTION_COOLER)
1547
+      tr_state_machine[RUNAWAY_IND_COOLER].run(temp_cooler.celsius, temp_cooler.target, H_COOLER, THERMAL_PROTECTION_COOLER_PERIOD, THERMAL_PROTECTION_COOLER_HYSTERESIS);
1548
+    #endif
1549
+  #endif // HAS_COOLER
1550
+
1449 1551
   UNUSED(ms);
1450 1552
 }
1451 1553
 
@@ -1510,6 +1612,9 @@ void Temperature::manage_heater() {
1510 1612
       #if TEMP_SENSOR_CHAMBER_IS_CUSTOM
1511 1613
         { true, 0, 0, CHAMBER_PULLUP_RESISTOR_OHMS, CHAMBER_RESISTANCE_25C_OHMS, 0, 0, CHAMBER_BETA, 0 }
1512 1614
       #endif
1615
+      #if TEMP_SENSOR_COOLER_IS_CUSTOM
1616
+        { true, 0, 0, COOLER_PULLUP_RESISTOR_OHMS, COOLER_RESISTANCE_25C_OHMS, 0, 0, COOLER_BETA, 0 }
1617
+      #endif
1513 1618
       #if TEMP_SENSOR_PROBE_IS_CUSTOM
1514 1619
         { true, 0, 0, PROBE_PULLUP_RESISTOR_OHMS, PROBE_RESISTANCE_25C_OHMS, 0, 0, PROBE_BETA, 0 }
1515 1620
       #endif
@@ -1543,6 +1648,7 @@ void Temperature::manage_heater() {
1543 1648
       TERN_(TEMP_SENSOR_7_IS_CUSTOM, t_index == CTI_HOTEND_7 ? PSTR("HOTEND 7") :)
1544 1649
       TERN_(TEMP_SENSOR_BED_IS_CUSTOM, t_index == CTI_BED ? PSTR("BED") :)
1545 1650
       TERN_(TEMP_SENSOR_CHAMBER_IS_CUSTOM, t_index == CTI_CHAMBER ? PSTR("CHAMBER") :)
1651
+      TERN_(TEMP_SENSOR_COOLER_IS_CUSTOM, t_index == CTI_COOLER ? PSTR("COOLER") :)
1546 1652
       TERN_(TEMP_SENSOR_PROBE_IS_CUSTOM, t_index == CTI_PROBE ? PSTR("PROBE") :)
1547 1653
       nullptr
1548 1654
     );
@@ -1706,7 +1812,6 @@ void Temperature::manage_heater() {
1706 1812
 #endif // HAS_HOTEND
1707 1813
 
1708 1814
 #if HAS_HEATED_BED
1709
-  // Derived from RepRap FiveD extruder::getTemperature()
1710 1815
   // For bed temperature measurement.
1711 1816
   float Temperature::analog_to_celsius_bed(const int raw) {
1712 1817
     #if TEMP_SENSOR_BED_IS_CUSTOM
@@ -1725,7 +1830,6 @@ void Temperature::manage_heater() {
1725 1830
 #endif // HAS_HEATED_BED
1726 1831
 
1727 1832
 #if HAS_TEMP_CHAMBER
1728
-  // Derived from RepRap FiveD extruder::getTemperature()
1729 1833
   // For chamber temperature measurement.
1730 1834
   float Temperature::analog_to_celsius_chamber(const int raw) {
1731 1835
     #if TEMP_SENSOR_CHAMBER_IS_CUSTOM
@@ -1743,8 +1847,25 @@ void Temperature::manage_heater() {
1743 1847
   }
1744 1848
 #endif // HAS_TEMP_CHAMBER
1745 1849
 
1850
+#if HAS_TEMP_COOLER
1851
+  // For cooler temperature measurement.
1852
+  float Temperature::analog_to_celsius_cooler(const int raw) {
1853
+    #if TEMP_SENSOR_COOLER_IS_CUSTOM
1854
+      return user_thermistor_to_deg_c(CTI_COOLER, raw);
1855
+    #elif TEMP_SENSOR_COOLER_IS_THERMISTOR
1856
+      SCAN_THERMISTOR_TABLE(TEMPTABLE_COOLER, TEMPTABLE_COOLER_LEN);
1857
+    #elif TEMP_SENSOR_COOLER_IS_AD595
1858
+      return TEMP_AD595(raw);
1859
+    #elif TEMP_SENSOR_COOLER_IS_AD8495
1860
+      return TEMP_AD8495(raw);
1861
+    #else
1862
+      UNUSED(raw);
1863
+      return 0;
1864
+    #endif
1865
+  }
1866
+#endif // HAS_TEMP_COOLER
1867
+
1746 1868
 #if HAS_TEMP_PROBE
1747
-  // Derived from RepRap FiveD extruder::getTemperature()
1748 1869
   // For probe temperature measurement.
1749 1870
   float Temperature::analog_to_celsius_probe(const int raw) {
1750 1871
     #if TEMP_SENSOR_PROBE_IS_CUSTOM
@@ -1776,6 +1897,7 @@ void Temperature::updateTemperaturesFromRawValues() {
1776 1897
   #endif
1777 1898
   TERN_(HAS_HEATED_BED, temp_bed.celsius = analog_to_celsius_bed(temp_bed.raw));
1778 1899
   TERN_(HAS_TEMP_CHAMBER, temp_chamber.celsius = analog_to_celsius_chamber(temp_chamber.raw));
1900
+  TERN_(HAS_TEMP_COOLER, temp_cooler.celsius = analog_to_celsius_cooler(temp_cooler.raw));
1779 1901
   TERN_(HAS_TEMP_PROBE, temp_probe.celsius = analog_to_celsius_probe(temp_probe.raw));
1780 1902
   TERN_(TEMP_SENSOR_1_AS_REDUNDANT, redundant_temperature = analog_to_celsius_hotend(redundant_temperature_raw, 1));
1781 1903
   TERN_(FILAMENT_WIDTH_SENSOR, filwidth.update_measured_mm());
@@ -1927,6 +2049,10 @@ void Temperature::init() {
1927 2049
     OUT_WRITE(HEATER_CHAMBER_PIN, HEATER_CHAMBER_INVERTING);
1928 2050
   #endif
1929 2051
 
2052
+  #if HAS_COOLER
2053
+    OUT_WRITE(COOLER_PIN, COOLER_INVERTING);
2054
+  #endif
2055
+
1930 2056
   #if HAS_FAN0
1931 2057
     INIT_FAN_PIN(FAN_PIN);
1932 2058
   #endif
@@ -2001,6 +2127,9 @@ void Temperature::init() {
2001 2127
   #if HAS_TEMP_ADC_CHAMBER
2002 2128
     HAL_ANALOG_SELECT(TEMP_CHAMBER_PIN);
2003 2129
   #endif
2130
+  #if HAS_TEMP_ADC_COOLER
2131
+    HAL_ANALOG_SELECT(TEMP_COOLER_PIN);
2132
+  #endif
2004 2133
   #if HAS_TEMP_ADC_PROBE
2005 2134
     HAL_ANALOG_SELECT(TEMP_PROBE_PIN);
2006 2135
   #endif
@@ -2137,6 +2266,15 @@ void Temperature::init() {
2137 2266
     #endif
2138 2267
   #endif
2139 2268
 
2269
+  #if HAS_COOLER
2270
+    #ifdef COOLER_MINTEMP
2271
+      while (analog_to_celsius_cooler(mintemp_raw_COOLER) > COOLER_MINTEMP) mintemp_raw_COOLER += TEMPDIR(COOLER) * (OVERSAMPLENR);
2272
+    #endif
2273
+    #ifdef COOLER_MAXTEMP
2274
+      while (analog_to_celsius_cooler(maxtemp_raw_COOLER) < COOLER_MAXTEMP) maxtemp_raw_COOLER -= TEMPDIR(COOLER) * (OVERSAMPLENR);
2275
+    #endif
2276
+  #endif
2277
+
2140 2278
   TERN_(PROBING_HEATERS_OFF, paused = false);
2141 2279
 }
2142 2280
 
@@ -2174,6 +2312,17 @@ void Temperature::init() {
2174 2312
   }
2175 2313
 #endif
2176 2314
 
2315
+#if WATCH_COOLER
2316
+  /**
2317
+   * Start Cooling Sanity Check for cooler that is above
2318
+   * its target temperature by a configurable margin.
2319
+   * This is called when the temperature is set. (M143, M193)
2320
+   */
2321
+  void Temperature::start_watching_cooler() {
2322
+    watch_cooler.restart(degCooler(), degTargetCooler());
2323
+  }
2324
+#endif
2325
+
2177 2326
 #if HAS_THERMAL_PROTECTION
2178 2327
 
2179 2328
   Temperature::tr_state_machine_t Temperature::tr_state_machine[NR_HEATER_RUNAWAY]; // = { { TRInactive, 0 } };
@@ -2301,10 +2450,18 @@ void Temperature::disable_all_heaters() {
2301 2450
     temp_chamber.soft_pwm_amount = 0;
2302 2451
     WRITE_HEATER_CHAMBER(LOW);
2303 2452
   #endif
2453
+
2454
+  #if HAS_COOLER
2455
+    setTargetCooler(0);
2456
+    temp_cooler.soft_pwm_amount = 0;
2457
+    WRITE_HEATER_COOLER(LOW);
2458
+  #endif
2304 2459
 }
2305 2460
 
2306 2461
 #if ENABLED(PRINTJOB_TIMER_AUTOSTART)
2307 2462
 
2463
+  #include "printcounter.h"
2464
+
2308 2465
   bool Temperature::auto_job_over_threshold() {
2309 2466
     #if HAS_HOTEND
2310 2467
       HOTEND_LOOP() if (degTargetHotend(e) > (EXTRUDE_MINTEMP) / 2) return true;
@@ -2564,6 +2721,7 @@ void Temperature::update_raw_temperatures() {
2564 2721
   TERN_(HAS_TEMP_ADC_BED, temp_bed.update());
2565 2722
   TERN_(HAS_TEMP_ADC_CHAMBER, temp_chamber.update());
2566 2723
   TERN_(HAS_TEMP_ADC_PROBE, temp_probe.update());
2724
+  TERN_(HAS_TEMP_ADC_COOLER, temp_cooler.update());
2567 2725
 
2568 2726
   TERN_(HAS_JOY_ADC_X, joystick.x.update());
2569 2727
   TERN_(HAS_JOY_ADC_Y, joystick.y.update());
@@ -2588,6 +2746,7 @@ void Temperature::readings_ready() {
2588 2746
   TERN_(HAS_HEATED_BED, temp_bed.reset());
2589 2747
   TERN_(HAS_TEMP_CHAMBER, temp_chamber.reset());
2590 2748
   TERN_(HAS_TEMP_PROBE, temp_probe.reset());
2749
+  TERN_(HAS_TEMP_COOLER, temp_cooler.reset());
2591 2750
 
2592 2751
   TERN_(HAS_JOY_ADC_X, joystick.x.reset());
2593 2752
   TERN_(HAS_JOY_ADC_Y, joystick.y.reset());
@@ -2650,6 +2809,18 @@ void Temperature::readings_ready() {
2650 2809
     if (CHAMBERCMP(temp_chamber.raw, maxtemp_raw_CHAMBER)) max_temp_error(H_CHAMBER);
2651 2810
     if (chamber_on && CHAMBERCMP(mintemp_raw_CHAMBER, temp_chamber.raw)) min_temp_error(H_CHAMBER);
2652 2811
   #endif
2812
+
2813
+  #if BOTH(HAS_COOLER, THERMAL_PROTECTION_COOLER)
2814
+    #if TEMPDIR(COOLER) < 0
2815
+      #define COOLERCMP(A,B) ((A)<(B))
2816
+    #else
2817
+      #define COOLERCMP(A,B) ((A)>(B))
2818
+    #endif
2819
+    if (cutter.unitPower > 0) {
2820
+      if (COOLERCMP(temp_cooler.raw, maxtemp_raw_COOLER)) max_temp_error(H_COOLER);
2821
+    }
2822
+    if (COOLERCMP(mintemp_raw_COOLER, temp_cooler.raw)) min_temp_error(H_COOLER);
2823
+  #endif
2653 2824
 }
2654 2825
 
2655 2826
 /**
@@ -2735,11 +2906,15 @@ void Temperature::tick() {
2735 2906
     static SoftPWM soft_pwm_chamber;
2736 2907
   #endif
2737 2908
 
2909
+  #if HAS_COOLER
2910
+    static SoftPWM soft_pwm_cooler;
2911
+  #endif
2912
+
2738 2913
   #define WRITE_FAN(n, v) WRITE(FAN##n##_PIN, (v) ^ FAN_INVERTING)
2739 2914
 
2740 2915
   #if DISABLED(SLOW_PWM_HEATERS)
2741 2916
 
2742
-    #if ANY(HAS_HOTEND, HAS_HEATED_BED, HAS_HEATED_CHAMBER, FAN_SOFT_PWM)
2917
+    #if ANY(HAS_HOTEND, HAS_HEATED_BED, HAS_HEATED_CHAMBER, HAS_COOLER, FAN_SOFT_PWM)
2743 2918
       constexpr uint8_t pwm_mask = TERN0(SOFT_PWM_DITHER, _BV(SOFT_PWM_SCALE) - 1);
2744 2919
       #define _PWM_MOD(N,S,T) do{                           \
2745 2920
         const bool on = S.add(pwm_mask, T.soft_pwm_amount); \
@@ -2766,6 +2941,10 @@ void Temperature::tick() {
2766 2941
         _PWM_MOD(CHAMBER,soft_pwm_chamber,temp_chamber);
2767 2942
       #endif
2768 2943
 
2944
+      #if HAS_COOLER
2945
+        _PWM_MOD(COOLER,soft_pwm_cooler,temp_cooler);
2946
+      #endif
2947
+
2769 2948
       #if ENABLED(FAN_SOFT_PWM)
2770 2949
         #define _FAN_PWM(N) do{                                     \
2771 2950
           uint8_t &spcf = soft_pwm_count_fan[N];                    \
@@ -2813,6 +2992,10 @@ void Temperature::tick() {
2813 2992
         _PWM_LOW(CHAMBER, soft_pwm_chamber);
2814 2993
       #endif
2815 2994
 
2995
+      #if HAS_COOLER
2996
+        _PWM_LOW(COOLER, soft_pwm_cooler);
2997
+      #endif
2998
+
2816 2999
       #if ENABLED(FAN_SOFT_PWM)
2817 3000
         #if HAS_FAN0
2818 3001
           if (soft_pwm_count_fan[0] <= pwm_count_tmp) WRITE_FAN(0, LOW);
@@ -2879,6 +3062,10 @@ void Temperature::tick() {
2879 3062
         _SLOW_PWM(CHAMBER, soft_pwm_chamber, temp_chamber);
2880 3063
       #endif
2881 3064
 
3065
+      #if HAS_COOLER
3066
+        _SLOW_PWM(COOLER, soft_pwm_cooler, temp_cooler);
3067
+      #endif
3068
+
2882 3069
     } // slow_pwm_count == 0
2883 3070
 
2884 3071
     #if HAS_HOTEND
@@ -2894,6 +3081,10 @@ void Temperature::tick() {
2894 3081
       _PWM_OFF(CHAMBER, soft_pwm_chamber);
2895 3082
     #endif
2896 3083
 
3084
+    #if HAS_COOLER
3085
+      _PWM_OFF(COOLER, soft_pwm_cooler, temp_cooler);
3086
+    #endif
3087
+
2897 3088
     #if ENABLED(FAN_SOFT_PWM)
2898 3089
       if (pwm_count_tmp >= 127) {
2899 3090
         pwm_count_tmp = 0;
@@ -2973,6 +3164,7 @@ void Temperature::tick() {
2973 3164
       #endif
2974 3165
       TERN_(HAS_HEATED_BED, soft_pwm_bed.dec());
2975 3166
       TERN_(HAS_HEATED_CHAMBER, soft_pwm_chamber.dec());
3167
+      TERN_(HAS_COOLER, soft_pwm_cooler.dec());
2976 3168
     }
2977 3169
 
2978 3170
   #endif // SLOW_PWM_HEATERS
@@ -3040,6 +3232,11 @@ void Temperature::tick() {
3040 3232
       case MeasureTemp_CHAMBER: ACCUMULATE_ADC(temp_chamber); break;
3041 3233
     #endif
3042 3234
 
3235
+    #if HAS_TEMP_ADC_COOLER
3236
+      case PrepareTemp_COOLER: HAL_START_ADC(TEMP_COOLER_PIN); break;
3237
+      case MeasureTemp_COOLER: ACCUMULATE_ADC(temp_cooler); break;
3238
+    #endif
3239
+
3043 3240
     #if HAS_TEMP_ADC_PROBE
3044 3241
       case PrepareTemp_PROBE: HAL_START_ADC(TEMP_PROBE_PIN); break;
3045 3242
       case MeasureTemp_PROBE: ACCUMULATE_ADC(temp_probe); break;
@@ -3183,22 +3380,24 @@ void Temperature::tick() {
3183 3380
   ) {
3184 3381
     char k;
3185 3382
     switch (e) {
3383
+      default:
3384
+        #if HAS_TEMP_HOTEND
3385
+          k = 'T'; break;
3386
+        #endif
3387
+      #if HAS_TEMP_BED
3388
+        case H_BED: k = 'B'; break;
3389
+      #endif
3186 3390
       #if HAS_TEMP_CHAMBER
3187 3391
         case H_CHAMBER: k = 'C'; break;
3188 3392
       #endif
3189 3393
       #if HAS_TEMP_PROBE
3190 3394
         case H_PROBE: k = 'P'; break;
3191 3395
       #endif
3192
-      #if HAS_TEMP_HOTEND
3193
-        default: k = 'T'; break;
3194
-        #if HAS_HEATED_BED
3195
-          case H_BED: k = 'B'; break;
3196
-        #endif
3197
-        #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
3198
-          case H_REDUNDANT: k = 'R'; break;
3199
-        #endif
3200
-      #elif HAS_HEATED_BED
3201
-        default: k = 'B'; break;
3396
+      #if HAS_TEMP_COOLER
3397
+        case H_COOLER: k = 'L'; break;
3398
+      #endif
3399
+      #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
3400
+        case H_REDUNDANT: k = 'R'; break;
3202 3401
       #endif
3203 3402
     }
3204 3403
     SERIAL_CHAR(' ', k);
@@ -3251,18 +3450,21 @@ void Temperature::tick() {
3251 3450
       );
3252 3451
     #endif
3253 3452
     #if HAS_TEMP_CHAMBER
3254
-      print_heater_state(degChamber()
3255
-        #if HAS_HEATED_CHAMBER
3256
-          , degTargetChamber()
3257
-        #else
3258
-          , 0
3259
-        #endif
3453
+      print_heater_state(degChamber(), TERN0(HAS_HEATED_CHAMBER, degTargetChamber())
3260 3454
         #if ENABLED(SHOW_TEMP_ADC_VALUES)
3261 3455
           , rawChamberTemp()
3262 3456
         #endif
3263 3457
         , H_CHAMBER
3264 3458
       );
3265
-    #endif
3459
+    #endif // HAS_TEMP_CHAMBER
3460
+    #if HAS_TEMP_COOLER
3461
+      print_heater_state(degCooler(), TERN0(HAS_COOLER, degTargetCooler())
3462
+        #if ENABLED(SHOW_TEMP_ADC_VALUES)
3463
+          , rawCoolerTemp()
3464
+        #endif
3465
+        , H_COOLER
3466
+      );
3467
+    #endif // HAS_TEMP_COOLER
3266 3468
     #if HAS_TEMP_PROBE
3267 3469
       print_heater_state(degProbe(), 0
3268 3470
         #if ENABLED(SHOW_TEMP_ADC_VALUES)
@@ -3286,6 +3488,9 @@ void Temperature::tick() {
3286 3488
     #if HAS_HEATED_CHAMBER
3287 3489
       SERIAL_ECHOPAIR(" C@:", getHeaterPower(H_CHAMBER));
3288 3490
     #endif
3491
+    #if HAS_COOLER
3492
+      SERIAL_ECHOPAIR(" C@:", getHeaterPower(H_COOLER));
3493
+    #endif
3289 3494
     #if HAS_MULTI_HOTEND
3290 3495
       HOTEND_LOOP() {
3291 3496
         SERIAL_ECHOPAIR(" @", e);
@@ -3759,4 +3964,103 @@ void Temperature::tick() {
3759 3964
 
3760 3965
   #endif // HAS_HEATED_CHAMBER
3761 3966
 
3967
+  #if HAS_COOLER
3968
+
3969
+    #ifndef MIN_COOLING_SLOPE_DEG_COOLER
3970
+      #define MIN_COOLING_SLOPE_DEG_COOLER 1.50
3971
+    #endif
3972
+    #ifndef MIN_COOLING_SLOPE_TIME_COOLER
3973
+      #define MIN_COOLING_SLOPE_TIME_COOLER 120
3974
+    #endif
3975
+
3976
+    bool Temperature::wait_for_cooler(const bool no_wait_for_cooling/*=true*/) {
3977
+
3978
+      #if TEMP_COOLER_RESIDENCY_TIME > 0
3979
+        millis_t residency_start_ms = 0;
3980
+        bool first_loop = true;
3981
+        // Loop until the temperature has stabilized
3982
+        #define TEMP_COOLER_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + SEC_TO_MS(TEMP_COOLER_RESIDENCY_TIME)))
3983
+      #else
3984
+        // Loop until the temperature is very close target
3985
+        #define TEMP_COOLER_CONDITIONS (wants_to_cool ? isLaserHeating() : isLaserCooling())
3986
+      #endif
3987
+
3988
+      #if DISABLED(BUSY_WHILE_HEATING) && ENABLED(HOST_KEEPALIVE_FEATURE)
3989
+        KEEPALIVE_STATE(NOT_BUSY);
3990
+      #endif
3991
+
3992
+      bool wants_to_cool = false;
3993
+      float target_temp = -1, previous_temp = 9999;
3994
+      millis_t now, next_temp_ms = 0, next_cooling_check_ms = 0;
3995
+      wait_for_heatup = true;
3996
+      do {
3997
+        // Target temperature might be changed during the loop
3998
+        if (target_temp != degTargetCooler()) {
3999
+          wants_to_cool = isLaserHeating();
4000
+          target_temp = degTargetCooler();
4001
+
4002
+          // Exit if S<lower>, continue if S<higher>, R<lower>, or R<higher>
4003
+          if (no_wait_for_cooling && wants_to_cool) break;
4004
+        }
4005
+
4006
+        now = millis();
4007
+        if (ELAPSED(now, next_temp_ms)) { // Print Temp Reading every 1 second while heating up.
4008
+          next_temp_ms = now + 1000UL;
4009
+          print_heater_states(active_extruder);
4010
+          #if TEMP_COOLER_RESIDENCY_TIME > 0
4011
+            SERIAL_ECHOPGM(" W:");
4012
+            if (residency_start_ms)
4013
+              SERIAL_ECHO(long((SEC_TO_MS(TEMP_COOLER_RESIDENCY_TIME) - (now - residency_start_ms)) / 1000UL));
4014
+            else
4015
+              SERIAL_CHAR('?');
4016
+          #endif
4017
+          SERIAL_EOL();
4018
+        }
4019
+
4020
+        idle();
4021
+        gcode.reset_stepper_timeout(); // Keep steppers powered
4022
+
4023
+        const float current_temp = degCooler();
4024
+
4025
+        #if TEMP_COOLER_RESIDENCY_TIME > 0
4026
+
4027
+          const float temp_diff = ABS(target_temp - temp);
4028
+
4029
+          if (!residency_start_ms) {
4030
+            // Start the TEMP_COOLER_RESIDENCY_TIME timer when we reach target temp for the first time.
4031
+            if (temp_diff < TEMP_COOLER_WINDOW)
4032
+              residency_start_ms = now + (first_loop ? SEC_TO_MS(TEMP_COOLER_RESIDENCY_TIME) / 3 : 0);
4033
+          }
4034
+          else if (temp_diff > TEMP_COOLER_HYSTERESIS) {
4035
+            // Restart the timer whenever the temperature falls outside the hysteresis.
4036
+            residency_start_ms = now;
4037
+          }
4038
+
4039
+          first_loop = false;
4040
+        #endif // TEMP_COOLER_RESIDENCY_TIME > 0
4041
+
4042
+        if (wants_to_cool) {
4043
+          // Break after MIN_COOLING_SLOPE_TIME_CHAMBER seconds
4044
+          // if the temperature did not drop at least MIN_COOLING_SLOPE_DEG_CHAMBER
4045
+          if (!next_cooling_check_ms || ELAPSED(now, next_cooling_check_ms)) {
4046
+            if (previous_temp - current_temp < float(MIN_COOLING_SLOPE_DEG_COOLER)) break;
4047
+            next_cooling_check_ms = now + SEC_TO_MS(MIN_COOLING_SLOPE_TIME_COOLER);
4048
+            previous_temp = current_temp;
4049
+          }
4050
+        }
4051
+
4052
+      } while (wait_for_heatup && TEMP_COOLER_CONDITIONS);
4053
+
4054
+      // Prevent a wait-forever situation if R is misused i.e. M191 R0
4055
+      if (wait_for_heatup) {
4056
+        wait_for_heatup = false;
4057
+        ui.reset_status();
4058
+        return true;
4059
+      }
4060
+
4061
+      return false;
4062
+    }
4063
+
4064
+  #endif // HAS_COOLER
4065
+
3762 4066
 #endif // HAS_TEMP_SENSOR

+ 70
- 5
Marlin/src/module/temperature.h 查看文件

@@ -44,10 +44,10 @@
44 44
 #define HOTEND_INDEX TERN(HAS_MULTI_HOTEND, e, 0)
45 45
 #define E_NAME TERN_(HAS_MULTI_HOTEND, e)
46 46
 
47
-// Heater identifiers. Positive values are hotends. Negative values are other heaters.
47
+// Element identifiers. Positive values are hotends. Negative values are other heaters or coolers.
48 48
 typedef enum : int8_t {
49
-  INDEX_NONE = -5,
50
-  H_PROBE, H_REDUNDANT, H_CHAMBER, H_BED,
49
+  INDEX_NONE = -6,
50
+  H_COOLER, H_PROBE, H_REDUNDANT, H_CHAMBER, H_BED,
51 51
   H_E0, H_E1, H_E2, H_E3, H_E4, H_E5, H_E6, H_E7
52 52
 } heater_id_t;
53 53
 
@@ -99,6 +99,9 @@ enum ADCSensorState : char {
99 99
   #if HAS_TEMP_ADC_CHAMBER
100 100
     PrepareTemp_CHAMBER, MeasureTemp_CHAMBER,
101 101
   #endif
102
+  #if HAS_TEMP_ADC_COOLER
103
+    PrepareTemp_COOLER, MeasureTemp_COOLER,
104
+  #endif
102 105
   #if HAS_TEMP_ADC_PROBE
103 106
     PrepareTemp_PROBE, MeasureTemp_PROBE,
104 107
   #endif
@@ -218,6 +221,9 @@ struct PIDHeaterInfo : public HeaterInfo {
218 221
 #elif HAS_TEMP_CHAMBER
219 222
   typedef temp_info_t chamber_info_t;
220 223
 #endif
224
+#if EITHER(HAS_COOLER, HAS_TEMP_COOLER)
225
+  typedef heater_info_t cooler_info_t;
226
+#endif
221 227
 
222 228
 // Heater watch handling
223 229
 template <int INCREASE, int HYSTERESIS, millis_t PERIOD>
@@ -249,6 +255,9 @@ struct HeaterWatch {
249 255
 #if WATCH_CHAMBER
250 256
   typedef struct HeaterWatch<WATCH_CHAMBER_TEMP_INCREASE, TEMP_CHAMBER_HYSTERESIS, WATCH_CHAMBER_TEMP_PERIOD> chamber_watch_t;
251 257
 #endif
258
+#if WATCH_COOLER
259
+  typedef struct HeaterWatch<WATCH_COOLER_TEMP_INCREASE, TEMP_COOLER_HYSTERESIS, WATCH_COOLER_TEMP_PERIOD> cooler_watch_t;
260
+#endif
252 261
 
253 262
 // Temperature sensor read value ranges
254 263
 typedef struct { int16_t raw_min, raw_max; } raw_range_t;
@@ -288,6 +297,9 @@ typedef struct { int16_t raw_min, raw_max, mintemp, maxtemp; } temp_range_t;
288 297
     #if TEMP_SENSOR_CHAMBER_IS_CUSTOM
289 298
       CTI_CHAMBER,
290 299
     #endif
300
+    #if COOLER_USER_THERMISTOR
301
+      CTI_COOLER,
302
+    #endif
291 303
     USER_THERMISTORS
292 304
   };
293 305
 
@@ -316,9 +328,11 @@ class Temperature {
316 328
     TERN_(HAS_HEATED_BED, static bed_info_t temp_bed);
317 329
     TERN_(HAS_TEMP_PROBE, static probe_info_t temp_probe);
318 330
     TERN_(HAS_TEMP_CHAMBER, static chamber_info_t temp_chamber);
331
+    TERN_(HAS_TEMP_COOLER, static cooler_info_t temp_cooler);
319 332
 
320 333
     TERN_(AUTO_POWER_E_FANS, static uint8_t autofan_speed[HOTENDS]);
321 334
     TERN_(AUTO_POWER_CHAMBER_FAN, static uint8_t chamberfan_speed);
335
+    TERN_(AUTO_POWER_COOLER_FAN, static uint8_t coolerfan_speed);
322 336
 
323 337
     #if ENABLED(FAN_SOFT_PWM)
324 338
       static uint8_t soft_pwm_amount_fan[FAN_COUNT],
@@ -428,6 +442,17 @@ class Temperature {
428 442
       #endif
429 443
     #endif
430 444
 
445
+    #if HAS_COOLER
446
+      TERN_(WATCH_COOLER, static cooler_watch_t watch_cooler);
447
+      static millis_t next_cooler_check_ms, cooler_fan_flush_ms;
448
+      #ifdef COOLER_MINTEMP
449
+        static int16_t mintemp_raw_COOLER;
450
+      #endif
451
+      #ifdef COOLER_MAXTEMP
452
+        static int16_t maxtemp_raw_COOLER;
453
+      #endif
454
+    #endif
455
+
431 456
     #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
432 457
       static uint8_t consecutive_low_temperature_error[HOTENDS];
433 458
     #endif
@@ -492,7 +517,6 @@ class Temperature {
492 517
     #if HAS_HOTEND
493 518
       static float analog_to_celsius_hotend(const int raw, const uint8_t e);
494 519
     #endif
495
-
496 520
     #if HAS_HEATED_BED
497 521
       static float analog_to_celsius_bed(const int raw);
498 522
     #endif
@@ -502,6 +526,9 @@ class Temperature {
502 526
     #if HAS_TEMP_CHAMBER
503 527
       static float analog_to_celsius_chamber(const int raw);
504 528
     #endif
529
+    #if HAS_TEMP_COOLER
530
+      static float analog_to_celsius_cooler(const int raw);
531
+    #endif
505 532
 
506 533
     #if HAS_FAN
507 534
 
@@ -737,6 +764,38 @@ class Temperature {
737 764
       }
738 765
     #endif
739 766
 
767
+    #if HAS_TEMP_COOLER
768
+      #if ENABLED(SHOW_TEMP_ADC_VALUES)
769
+        FORCE_INLINE static int16_t rawCoolerTemp()    { return temp_cooler.raw; }
770
+      #endif
771
+      FORCE_INLINE static float degCooler()            { return temp_cooler.celsius; }
772
+      #if HAS_COOLER
773
+        FORCE_INLINE static int16_t degTargetCooler()  { return temp_cooler.target; }
774
+        FORCE_INLINE static bool isLaserHeating()     { return temp_cooler.target > temp_cooler.celsius; }
775
+        FORCE_INLINE static bool isLaserCooling()     { return temp_cooler.target < temp_cooler.celsius; }
776
+        static bool wait_for_cooler(const bool no_wait_for_cooling=true);
777
+      #endif
778
+    #endif
779
+
780
+    #if WATCH_COOLER
781
+      static void start_watching_cooler();
782
+    #else
783
+      static inline void start_watching_cooler() {}
784
+    #endif
785
+
786
+    #if HAS_COOLER
787
+      static void setTargetCooler(const int16_t celsius) {
788
+        temp_cooler.target =
789
+          #ifdef COOLER_MAXTEMP
790
+            _MIN(celsius, COOLER_MAXTEMP - 10)
791
+          #else
792
+            celsius
793
+          #endif
794
+        ;
795
+        start_watching_cooler();
796
+      }
797
+    #endif
798
+
740 799
     /**
741 800
      * The software PWM power for a heater
742 801
      */
@@ -847,7 +906,7 @@ class Temperature {
847 906
     static void min_temp_error(const heater_id_t e);
848 907
     static void max_temp_error(const heater_id_t e);
849 908
 
850
-    #define HAS_THERMAL_PROTECTION ANY(THERMAL_PROTECTION_HOTENDS, THERMAL_PROTECTION_CHAMBER, HAS_THERMALLY_PROTECTED_BED)
909
+    #define HAS_THERMAL_PROTECTION ANY(THERMAL_PROTECTION_HOTENDS, THERMAL_PROTECTION_CHAMBER, HAS_THERMALLY_PROTECTED_BED, THERMAL_PROTECTION_COOLER)
851 910
 
852 911
     #if HAS_THERMAL_PROTECTION
853 912
 
@@ -863,6 +922,9 @@ class Temperature {
863 922
         #if ENABLED(THERMAL_PROTECTION_CHAMBER)
864 923
           RUNAWAY_IND_CHAMBER,
865 924
         #endif
925
+        #if ENABLED(THERMAL_PROTECTION_COOLER)
926
+          RUNAWAY_IND_COOLER,
927
+        #endif
866 928
         NR_HEATER_RUNAWAY
867 929
       };
868 930
       #undef _ENUM_FOR_E
@@ -872,6 +934,9 @@ class Temperature {
872 934
         #if HAS_THERMALLY_PROTECTED_CHAMBER
873 935
           if (heater_id == H_CHAMBER) return RUNAWAY_IND_CHAMBER;
874 936
         #endif
937
+        #if HAS_THERMALLY_PROTECTED_CHAMBER
938
+          if (heater_id == H_COOLER) return RUNAWAY_IND_COOLER;
939
+        #endif
875 940
         #if HAS_THERMALLY_PROTECTED_BED
876 941
           if (heater_id == H_BED) return RUNAWAY_IND_BED;
877 942
         #endif

+ 19
- 2
Marlin/src/module/thermistor/thermistors.h 查看文件

@@ -42,7 +42,7 @@
42 42
 #define OV_SCALE(N) (N)
43 43
 #define OV(N) int16_t(OV_SCALE(N) * (OVERSAMPLENR) * (THERMISTOR_TABLE_SCALE))
44 44
 
45
-#define ANY_THERMISTOR_IS(n) (TEMP_SENSOR_0_THERMISTOR_ID == n || TEMP_SENSOR_1_THERMISTOR_ID == n || TEMP_SENSOR_2_THERMISTOR_ID == n || TEMP_SENSOR_3_THERMISTOR_ID == n || TEMP_SENSOR_4_THERMISTOR_ID == n || TEMP_SENSOR_5_THERMISTOR_ID == n || TEMP_SENSOR_6_THERMISTOR_ID == n || TEMP_SENSOR_7_THERMISTOR_ID == n || TEMP_SENSOR_BED_THERMISTOR_ID == n || TEMP_SENSOR_CHAMBER_THERMISTOR_ID == n || TEMP_SENSOR_PROBE_THERMISTOR_ID == n)
45
+#define ANY_THERMISTOR_IS(n) (TEMP_SENSOR_0_THERMISTOR_ID == n || TEMP_SENSOR_1_THERMISTOR_ID == n || TEMP_SENSOR_2_THERMISTOR_ID == n || TEMP_SENSOR_3_THERMISTOR_ID == n || TEMP_SENSOR_4_THERMISTOR_ID == n || TEMP_SENSOR_5_THERMISTOR_ID == n || TEMP_SENSOR_6_THERMISTOR_ID == n || TEMP_SENSOR_7_THERMISTOR_ID == n || TEMP_SENSOR_BED_THERMISTOR_ID == n || TEMP_SENSOR_CHAMBER_THERMISTOR_ID == n || TEMP_SENSOR_COOLER_THERMISTOR_ID == n || TEMP_SENSOR_PROBE_THERMISTOR_ID == n)
46 46
 
47 47
 typedef struct { int16_t value, celsius; } temp_entry_t;
48 48
 
@@ -303,6 +303,14 @@ typedef struct { int16_t value, celsius; } temp_entry_t;
303 303
   #define TEMPTABLE_CHAMBER_LEN 0
304 304
 #endif
305 305
 
306
+#ifdef TEMP_SENSOR_COOLER_THERMISTOR_ID
307
+  #define TEMPTABLE_COOLER TT_NAME(TEMP_SENSOR_COOLER_THERMISTOR_ID)
308
+  #define TEMPTABLE_COOLER_LEN COUNT(TEMPTABLE_COOLER)
309
+#elif TEMP_SENSOR_COOLER_IS_THERMISTOR
310
+  #error "No cooler thermistor table specified"
311
+#else
312
+  #define TEMPTABLE_COOLER_LEN 0
313
+#endif
306 314
 #ifdef TEMP_SENSOR_PROBE_THERMISTOR_ID
307 315
   #define TEMPTABLE_PROBE TT_NAME(TEMP_SENSOR_PROBE_THERMISTOR_ID)
308 316
   #define TEMPTABLE_PROBE_LEN COUNT(TEMPTABLE_PROBE)
@@ -319,7 +327,7 @@ static_assert(
319 327
   && TEMPTABLE_4_LEN < 256 && TEMPTABLE_5_LEN < 256
320 328
   && TEMPTABLE_6_LEN < 256 && TEMPTABLE_7_LEN < 256
321 329
   && TEMPTABLE_BED_LEN < 256 && TEMPTABLE_CHAMBER_LEN < 256
322
-  && TEMPTABLE_PROBE_LEN < 256,
330
+  && TEMPTABLE_COOLER_LEN < 256 && TEMPTABLE_PROBE_LEN < 256,
323 331
   "Temperature conversion tables over 255 entries need special consideration."
324 332
 );
325 333
 
@@ -495,6 +503,15 @@ static_assert(
495 503
     #define TEMP_SENSOR_CHAMBER_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
496 504
   #endif
497 505
 #endif
506
+#ifndef TEMP_SENSOR_COOLER_RAW_HI_TEMP
507
+  #if TT_REVRAW(COOLER)
508
+    #define TEMP_SENSOR_COOLER_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
509
+    #define TEMP_SENSOR_COOLER_RAW_LO_TEMP 0
510
+  #else
511
+    #define TEMP_SENSOR_COOLER_RAW_HI_TEMP 0
512
+    #define TEMP_SENSOR_COOLER_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
513
+  #endif
514
+#endif
498 515
 #ifndef TEMP_SENSOR_PROBE_RAW_HI_TEMP
499 516
   #if TT_REVRAW(PROBE)
500 517
     #define TEMP_SENSOR_PROBE_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE

+ 6
- 0
Marlin/src/pins/pinsDebug_list.h 查看文件

@@ -91,6 +91,9 @@
91 91
 #if PIN_EXISTS(TEMP_CHAMBER) && ANALOG_OK(TEMP_CHAMBER_PIN)
92 92
   REPORT_NAME_ANALOG(__LINE__, TEMP_CHAMBER_PIN)
93 93
 #endif
94
+#if PIN_EXISTS(TEMP_COOLER) && ANALOG_OK(TEMP_COOLER_PIN)
95
+  REPORT_NAME_ANALOG(__LINE__, TEMP_COOLER_PIN)
96
+#endif
94 97
 #if PIN_EXISTS(ADC_KEYPAD) && ANALOG_OK(ADC_KEYPAD_PIN)
95 98
   REPORT_NAME_ANALOG(__LINE__, ADC_KEYPAD_PIN)
96 99
 #endif
@@ -706,6 +709,9 @@
706 709
 #if PIN_EXISTS(HEATER_CHAMBER)
707 710
   REPORT_NAME_DIGITAL(__LINE__, HEATER_CHAMBER_PIN)
708 711
 #endif
712
+#if PIN_EXISTS(COOLER)
713
+  REPORT_NAME_DIGITAL(__LINE__, COOLER_PIN)
714
+#endif
709 715
 #if PIN_EXISTS(HOME)
710 716
   REPORT_NAME_DIGITAL(__LINE__, HOME_PIN)
711 717
 #endif

+ 19
- 1
Marlin/src/pins/sensitive_pins.h 查看文件

@@ -676,6 +676,24 @@
676 676
   #define _CHAMBER_FAN
677 677
 #endif
678 678
 
679
+#if TEMP_SENSOR_COOLER && PIN_EXISTS(TEMP_COOLER)
680
+  #define _COOLER_TEMP analogInputToDigitalPin(TEMP_COOLER_PIN),
681
+#else
682
+  #define _COOLER_TEMP
683
+#endif
684
+
685
+#if TEMP_SENSOR_COOLER && PIN_EXISTS(COOLER)
686
+  #define _COOLER COOLER_PIN,
687
+#else
688
+  #define _COOLER
689
+#endif
690
+
691
+#if TEMP_SENSOR_COOLER && PINS_EXIST(TEMP_COOLER, COOLER_AUTO_FAN)
692
+  #define _COOLER_FAN COOLER_AUTO_FAN_PIN,
693
+#else
694
+  #define _COOLER_FAN
695
+#endif
696
+
679 697
 #ifndef HAL_SENSITIVE_PINS
680 698
   #define HAL_SENSITIVE_PINS
681 699
 #endif
@@ -685,5 +703,5 @@
685 703
   _E0_PINS _E1_PINS _E2_PINS _E3_PINS _E4_PINS _E5_PINS _E6_PINS _E7_PINS \
686 704
   _H0_PINS _H1_PINS _H2_PINS _H3_PINS _H4_PINS _H5_PINS _H6_PINS _H7_PINS \
687 705
   _PS_ON _FAN0 _FAN1 _FAN2 _FAN3 _FAN4 _FAN5 _FAN6 _FAN7 _FANC \
688
-  _BED_PINS _CHAMBER_TEMP _CHAMBER_HEATER _CHAMBER_FAN HAL_SENSITIVE_PINS \
706
+  _BED_PINS _COOLER _CHAMBER_TEMP _CHAMBER_HEATER _CHAMBER_FAN HAL_SENSITIVE_PINS \
689 707
 }

+ 6
- 5
buildroot/tests/BIGTREE_SKR_PRO 查看文件

@@ -11,7 +11,7 @@ set -e
11 11
 #
12 12
 restore_configs
13 13
 opt_set MOTHERBOARD BOARD_BTT_SKR_PRO_V1_1 SERIAL_PORT 1
14
-exec_test $1 $2 "BigTreeTech SKR Pro Default Configuration" "$3"
14
+exec_test $1 $2 "BigTreeTech SKR Pro | Default Configuration" "$3"
15 15
 
16 16
 restore_configs
17 17
 opt_set MOTHERBOARD BOARD_BTT_SKR_PRO_V1_1 SERIAL_PORT -1 \
@@ -19,14 +19,15 @@ opt_set MOTHERBOARD BOARD_BTT_SKR_PRO_V1_1 SERIAL_PORT -1 \
19 19
         E0_AUTO_FAN_PIN PC10 E1_AUTO_FAN_PIN PC11 E2_AUTO_FAN_PIN PC12 \
20 20
         X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2130
21 21
 opt_enable BLTOUCH EEPROM_SETTINGS AUTO_BED_LEVELING_3POINT Z_SAFE_HOMING PINS_DEBUGGING
22
-exec_test $1 $2 "BigTreeTech SKR Pro 3 Extruders, Auto-Fan, BLTOUCH, mixed TMC drivers" "$3"
22
+exec_test $1 $2 "BigTreeTech SKR Pro | 3 Extruders | Auto-Fan | BLTOUCH | Mixed TMC" "$3"
23 23
 
24 24
 restore_configs
25 25
 opt_set MOTHERBOARD BOARD_BTT_SKR_PRO_V1_1 SERIAL_PORT -1 \
26 26
         CUTTER_POWER_UNIT PERCENT \
27
-        SPINDLE_LASER_PWM_PIN HEATER_1_PIN SPINDLE_LASER_ENA_PIN HEATER_2_PIN
28
-opt_enable LASER_FEATURE REPRAP_DISCOUNT_SMART_CONTROLLER
29
-exec_test $1 $2 "Laser, LCD, PERCENT power unit" "$3"
27
+        SPINDLE_LASER_PWM_PIN HEATER_1_PIN SPINDLE_LASER_ENA_PIN HEATER_2_PIN \
28
+        TEMP_SENSOR_COOLER 1000 TEMP_COOLER_PIN PD13
29
+opt_enable LASER_FEATURE REPRAP_DISCOUNT_SMART_CONTROLLER 
30
+exec_test $1 $2 "BigTreeTech SKR Pro | Laser (Percent) | Cooling | LCD" "$3"
30 31
 
31 32
 # clean up
32 33
 restore_configs

+ 2
- 0
platformio.ini 查看文件

@@ -196,6 +196,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
196 196
   -<src/gcode/sd/M32.cpp>
197 197
   -<src/gcode/sd/M808.cpp>
198 198
   -<src/gcode/temp/M104_M109.cpp>
199
+  -<src/gcode/temp/M143_M193.cpp>
199 200
   -<src/gcode/temp/M155.cpp>
200 201
   -<src/gcode/units/G20_G21.cpp>
201 202
   -<src/gcode/units/M149.cpp>
@@ -406,6 +407,7 @@ SDSUPPORT               = src_filter=+<src/sd/cardreader.cpp> +<src/sd/Sd2Card.c
406 407
 HAS_MEDIA_SUBCALLS      = src_filter=+<src/gcode/sd/M32.cpp>
407 408
 GCODE_REPEAT_MARKERS    = src_filter=+<src/feature/repeat.cpp> +<src/gcode/sd/M808.cpp>
408 409
 HAS_EXTRUDERS           = src_filter=+<src/gcode/temp/M104_M109.cpp> +<src/gcode/config/M221.cpp>
410
+HAS_COOLER              = src_filter=-<src/gcode/temp/M143_M193.cpp>
409 411
 AUTO_REPORT_TEMPERATURES = src_filter=+<src/gcode/temp/M155.cpp>
410 412
 INCH_MODE_SUPPORT       = src_filter=+<src/gcode/units/G20_G21.cpp>
411 413
 TEMPERATURE_UNITS_SUPPORT = src_filter=+<src/gcode/units/M149.cpp>

Loading…
取消
儲存