瀏覽代碼

♻️ Encapsulate PID in class (#24389)

Scott Lahteine 2 年之前
父節點
當前提交
54e7b933cd
No account linked to committer's email address

+ 1
- 1
Marlin/src/MarlinCore.cpp 查看文件

@@ -789,7 +789,7 @@ void idle(bool no_stepper_sleep/*=false*/) {
789 789
   manage_inactivity(no_stepper_sleep);
790 790
 
791 791
   // Manage Heaters (and Watchdog)
792
-  thermalManager.manage_heater();
792
+  thermalManager.task();
793 793
 
794 794
   // Max7219 heartbeat, animation, etc
795 795
   TERN_(MAX7219_DEBUG, max7219.idle_tasks());

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

@@ -227,10 +227,6 @@
227 227
 #define STR_PID_DEBUG                       " PID_DEBUG "
228 228
 #define STR_PID_DEBUG_INPUT                 ": Input "
229 229
 #define STR_PID_DEBUG_OUTPUT                " Output "
230
-#define STR_PID_DEBUG_PTERM                 " pTerm "
231
-#define STR_PID_DEBUG_ITERM                 " iTerm "
232
-#define STR_PID_DEBUG_DTERM                 " dTerm "
233
-#define STR_PID_DEBUG_CTERM                 " cTerm "
234 230
 #define STR_INVALID_EXTRUDER_NUM            " - Invalid extruder number !"
235 231
 #define STR_MPC_AUTOTUNE                    "MPC Autotune"
236 232
 #define STR_MPC_AUTOTUNE_START              " start for " STR_E

+ 2
- 2
Marlin/src/core/utility.cpp 查看文件

@@ -29,10 +29,10 @@ void safe_delay(millis_t ms) {
29 29
   while (ms > 50) {
30 30
     ms -= 50;
31 31
     delay(50);
32
-    thermalManager.manage_heater();
32
+    thermalManager.task();
33 33
   }
34 34
   delay(ms);
35
-  thermalManager.manage_heater(); // This keeps us safe if too many small safe_delay() calls are made
35
+  thermalManager.task(); // This keeps us safe if too many small safe_delay() calls are made
36 36
 }
37 37
 
38 38
 // A delay to provide brittle hosts time to receive bytes

+ 1
- 1
Marlin/src/gcode/motion/G2_G3.cpp 查看文件

@@ -290,7 +290,7 @@ void plan_arc(
290 290
 
291 291
     for (uint16_t i = 1; i < segments; i++) { // Iterate (segments-1) times
292 292
 
293
-      thermalManager.manage_heater();
293
+      thermalManager.task();
294 294
       const millis_t ms = millis();
295 295
       if (ELAPSED(ms, next_idle_ms)) {
296 296
         next_idle_ms = ms + 200UL;

+ 1
- 1
Marlin/src/gcode/queue.cpp 查看文件

@@ -384,7 +384,7 @@ inline bool process_line_done(uint8_t &sis, char (&buff)[MAX_CMD_SIZE], int &ind
384 384
   buff[ind] = '\0';                   // Of course, I'm a Terminator.
385 385
   const bool is_empty = (ind == 0);   // An empty line?
386 386
   if (is_empty)
387
-    thermalManager.manage_heater();   // Keep sensors satisfied
387
+    thermalManager.task();            // Keep sensors satisfied
388 388
   else
389 389
     ind = 0;                          // Start a new line
390 390
   return is_empty;                    // Inform the caller

+ 6
- 6
Marlin/src/lcd/e3v2/jyersui/dwin.cpp 查看文件

@@ -1202,7 +1202,7 @@ void CrealityDWINClass::Menu_Item_Handler(uint8_t menu, uint8_t item, bool draw/
1202 1202
                 if (thermalManager.temp_hotend[0].target < thermalManager.extrude_min_temp)
1203 1203
                   Popup_Handler(ETemp);
1204 1204
                 else {
1205
-                  if (thermalManager.temp_hotend[0].celsius < thermalManager.temp_hotend[0].target - 2) {
1205
+                  if (thermalManager.temp_hotend[0].is_below_target(-2)) {
1206 1206
                     Popup_Handler(Heating);
1207 1207
                     thermalManager.wait_for_hotend(0);
1208 1208
                   }
@@ -1345,7 +1345,7 @@ void CrealityDWINClass::Menu_Item_Handler(uint8_t menu, uint8_t item, bool draw/
1345 1345
                 Popup_Handler(ETemp);
1346 1346
               }
1347 1347
               else {
1348
-                if (thermalManager.temp_hotend[0].celsius < thermalManager.temp_hotend[0].target - 2) {
1348
+                if (thermalManager.temp_hotend[0].is_below_target(-2)) {
1349 1349
                   Popup_Handler(Heating);
1350 1350
                   thermalManager.wait_for_hotend(0);
1351 1351
                   Redraw_Menu();
@@ -1732,7 +1732,7 @@ void CrealityDWINClass::Menu_Item_Handler(uint8_t menu, uint8_t item, bool draw/
1732 1732
               if (thermalManager.temp_hotend[0].target < thermalManager.extrude_min_temp)
1733 1733
                 Popup_Handler(ETemp);
1734 1734
               else {
1735
-                if (thermalManager.temp_hotend[0].celsius < thermalManager.temp_hotend[0].target - 2) {
1735
+                if (thermalManager.temp_hotend[0].is_below_target(-2)) {
1736 1736
                   Popup_Handler(Heating);
1737 1737
                   thermalManager.wait_for_hotend(0);
1738 1738
                 }
@@ -1751,7 +1751,7 @@ void CrealityDWINClass::Menu_Item_Handler(uint8_t menu, uint8_t item, bool draw/
1751 1751
                 Popup_Handler(ETemp);
1752 1752
               }
1753 1753
               else {
1754
-                if (thermalManager.temp_hotend[0].celsius < thermalManager.temp_hotend[0].target - 2) {
1754
+                if (thermalManager.temp_hotend[0].is_below_target(-2)) {
1755 1755
                   Popup_Handler(Heating);
1756 1756
                   thermalManager.wait_for_hotend(0);
1757 1757
                 }
@@ -1769,7 +1769,7 @@ void CrealityDWINClass::Menu_Item_Handler(uint8_t menu, uint8_t item, bool draw/
1769 1769
               if (thermalManager.temp_hotend[0].target < thermalManager.extrude_min_temp)
1770 1770
                 Popup_Handler(ETemp);
1771 1771
               else {
1772
-                if (thermalManager.temp_hotend[0].celsius < thermalManager.temp_hotend[0].target - 2) {
1772
+                if (thermalManager.temp_hotend[0].is_below_target(-2)) {
1773 1773
                   Popup_Handler(Heating);
1774 1774
                   thermalManager.wait_for_hotend(0);
1775 1775
                 }
@@ -4404,7 +4404,7 @@ void CrealityDWINClass::Popup_Control() {
4404 4404
             if (thermalManager.temp_hotend[0].target < thermalManager.extrude_min_temp)
4405 4405
               Popup_Handler(ETemp);
4406 4406
             else {
4407
-              if (thermalManager.temp_hotend[0].celsius < thermalManager.temp_hotend[0].target - 2) {
4407
+              if (thermalManager.temp_hotend[0].is_below_target(-2)) {
4408 4408
                 Popup_Handler(Heating);
4409 4409
                 thermalManager.wait_for_hotend(0);
4410 4410
               }

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

@@ -169,7 +169,7 @@ namespace ExtUI {
169 169
   }
170 170
 
171 171
   void yield() {
172
-    if (!flags.printer_killed) thermalManager.manage_heater();
172
+    if (!flags.printer_killed) thermalManager.task();
173 173
   }
174 174
 
175 175
   void enableHeater(const extruder_t extruder) {

+ 1
- 1
Marlin/src/libs/buzzer.cpp 查看文件

@@ -48,7 +48,7 @@ void Buzzer::tone(const uint16_t duration, const uint16_t frequency/*=0*/) {
48 48
   if (!ui.sound_on) return;
49 49
   while (buffer.isFull()) {
50 50
     tick();
51
-    thermalManager.manage_heater();
51
+    thermalManager.task();
52 52
   }
53 53
   tone_t tone = { duration, frequency };
54 54
   buffer.enqueue(tone);

+ 1
- 1
Marlin/src/module/motion.cpp 查看文件

@@ -966,7 +966,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
966 966
     next_idle_ms = ms + 200UL;
967 967
     return idle();
968 968
   }
969
-  thermalManager.manage_heater();  // Returns immediately on most calls
969
+  thermalManager.task();  // Returns immediately on most calls
970 970
 }
971 971
 
972 972
 #if IS_KINEMATIC

+ 1
- 1
Marlin/src/module/planner_bezier.cpp 查看文件

@@ -123,7 +123,7 @@ void cubic_b_spline(
123 123
 
124 124
   for (float t = 0; t < 1;) {
125 125
 
126
-    thermalManager.manage_heater();
126
+    thermalManager.task();
127 127
     millis_t now = millis();
128 128
     if (ELAPSED(now, next_idle_ms)) {
129 129
       next_idle_ms = now + 200UL;

+ 189
- 273
Marlin/src/module/temperature.cpp 查看文件

@@ -1318,104 +1318,101 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
1318 1318
 }
1319 1319
 
1320 1320
 #if ANY(PID_DEBUG, PID_BED_DEBUG, PID_CHAMBER_DEBUG)
1321
-  bool Temperature::pid_debug_flag; // = 0
1321
+  #define HAS_PID_DEBUG 1
1322
+  bool Temperature::pid_debug_flag; // = false
1322 1323
 #endif
1323 1324
 
1324
-#if HAS_HOTEND
1325
+#if HAS_PID_HEATING
1325 1326
 
1326
-  float Temperature::get_pid_output_hotend(const uint8_t E_NAME) {
1327
-    const uint8_t ee = HOTEND_INDEX;
1328
-    #if ENABLED(PIDTEMP)
1329
-      #if DISABLED(PID_OPENLOOP)
1330
-        static hotend_pid_t work_pid[HOTENDS];
1331
-        static float temp_iState[HOTENDS] = { 0 },
1332
-                     temp_dState[HOTENDS] = { 0 };
1333
-        static Flags<HOTENDS> pid_reset;
1334
-        const float pid_error = temp_hotend[ee].target - temp_hotend[ee].celsius;
1335
-
1336
-        float pid_output;
1337
-
1338
-        if (temp_hotend[ee].target == 0
1339
-          || pid_error < -(PID_FUNCTIONAL_RANGE)
1340
-          || TERN0(HEATER_IDLE_HANDLER, heater_idle[ee].timed_out)
1341
-        ) {
1342
-          pid_output = 0;
1343
-          pid_reset.set(ee);
1327
+  template<typename TT, int MIN_POW, int MAX_POW>
1328
+  class PIDRunner {
1329
+  public:
1330
+    TT &tempinfo;
1331
+    __typeof__(TT::pid) work_pid{0};
1332
+    float temp_iState = 0, temp_dState = 0;
1333
+    bool pid_reset = true;
1334
+
1335
+    PIDRunner(TT &t) : tempinfo(t) { }
1336
+
1337
+    float get_pid_output() {
1338
+
1339
+      #if ENABLED(PID_OPENLOOP)
1340
+
1341
+        return constrain(tempinfo.target, 0, MAX_POW);
1342
+
1343
+      #else // !PID_OPENLOOP
1344
+
1345
+        const float pid_error = tempinfo.target - tempinfo.celsius;
1346
+        if (!tempinfo.target || pid_error < -(PID_FUNCTIONAL_RANGE)) {
1347
+          pid_reset = true;
1348
+          return 0;
1344 1349
         }
1345 1350
         else if (pid_error > PID_FUNCTIONAL_RANGE) {
1346
-          pid_output = PID_MAX;
1347
-          pid_reset.set(ee);
1351
+          pid_reset = true;
1352
+          return MAX_POW;
1348 1353
         }
1349
-        else {
1350
-          if (pid_reset[ee]) {
1351
-            temp_iState[ee] = 0.0;
1352
-            work_pid[ee].Kd = 0.0;
1353
-            pid_reset.clear(ee);
1354
-          }
1355 1354
 
1356
-          work_pid[ee].Kd = work_pid[ee].Kd + PID_K2 * (PID_PARAM(Kd, ee) * (temp_dState[ee] - temp_hotend[ee].celsius) - work_pid[ee].Kd);
1357
-          const float max_power_over_i_gain = float(PID_MAX) / PID_PARAM(Ki, ee) - float(MIN_POWER);
1358
-          temp_iState[ee] = constrain(temp_iState[ee] + pid_error, 0, max_power_over_i_gain);
1359
-          work_pid[ee].Kp = PID_PARAM(Kp, ee) * pid_error;
1360
-          work_pid[ee].Ki = PID_PARAM(Ki, ee) * temp_iState[ee];
1355
+        if (pid_reset) {
1356
+          pid_reset = false;
1357
+          temp_iState = 0.0;
1358
+          work_pid.Kd = 0.0;
1359
+        }
1361 1360
 
1362
-          pid_output = work_pid[ee].Kp + work_pid[ee].Ki + work_pid[ee].Kd + float(MIN_POWER);
1361
+        const float max_power_over_i_gain = float(MAX_POW) / tempinfo.pid.Ki - float(MIN_POW);
1362
+        temp_iState = constrain(temp_iState + pid_error, 0, max_power_over_i_gain);
1363 1363
 
1364
-          #if ENABLED(PID_EXTRUSION_SCALING)
1365
-            #if HOTENDS == 1
1366
-              constexpr bool this_hotend = true;
1367
-            #else
1368
-              const bool this_hotend = (ee == active_extruder);
1369
-            #endif
1370
-            work_pid[ee].Kc = 0;
1371
-            if (this_hotend) {
1372
-              const long e_position = stepper.position(E_AXIS);
1373
-              if (e_position > pes_e_position) {
1374
-                lpq[lpq_ptr] = e_position - pes_e_position;
1375
-                pes_e_position = e_position;
1376
-              }
1377
-              else
1378
-                lpq[lpq_ptr] = 0;
1364
+        work_pid.Kp = tempinfo.pid.Kp * pid_error;
1365
+        work_pid.Ki = tempinfo.pid.Ki * temp_iState;
1366
+        work_pid.Kd = work_pid.Kd + PID_K2 * (tempinfo.pid.Kd * (temp_dState - tempinfo.celsius) - work_pid.Kd);
1379 1367
 
1380
-              if (++lpq_ptr >= lpq_len) lpq_ptr = 0;
1381
-              work_pid[ee].Kc = (lpq[lpq_ptr] * planner.mm_per_step[E_AXIS]) * PID_PARAM(Kc, ee);
1382
-              pid_output += work_pid[ee].Kc;
1383
-            }
1384
-          #endif // PID_EXTRUSION_SCALING
1385
-          #if ENABLED(PID_FAN_SCALING)
1386
-            if (fan_speed[active_extruder] > PID_FAN_SCALING_MIN_SPEED) {
1387
-              work_pid[ee].Kf = PID_PARAM(Kf, ee) + (PID_FAN_SCALING_LIN_FACTOR) * fan_speed[active_extruder];
1388
-              pid_output += work_pid[ee].Kf;
1389
-            }
1390
-            //pid_output -= work_pid[ee].Ki;
1391
-            //pid_output += work_pid[ee].Ki * work_pid[ee].Kf
1392
-          #endif // PID_FAN_SCALING
1393
-          LIMIT(pid_output, 0, PID_MAX);
1394
-        }
1395
-        temp_dState[ee] = temp_hotend[ee].celsius;
1368
+        temp_dState = tempinfo.celsius;
1396 1369
 
1397
-      #else // PID_OPENLOOP
1370
+        return constrain(work_pid.Kp + work_pid.Ki + work_pid.Kd + float(MIN_POW), 0, MAX_POW);
1398 1371
 
1399
-        const float pid_output = constrain(temp_hotend[ee].target, 0, PID_MAX);
1372
+      #endif // !PID_OPENLOOP
1373
+    }
1400 1374
 
1401
-      #endif // PID_OPENLOOP
1375
+    FORCE_INLINE void debug(const_celsius_float_t c, const_float_t pid_out, FSTR_P const name=nullptr, const int8_t index=-1) {
1376
+      if (TERN0(HAS_PID_DEBUG, thermalManager.pid_debug_flag)) {
1377
+        SERIAL_ECHO_START();
1378
+        if (name) SERIAL_ECHOLNF(name);
1379
+        if (index >= 0) SERIAL_ECHO(index);
1380
+        SERIAL_ECHOLNPGM(
1381
+          STR_PID_DEBUG_INPUT, c,
1382
+          STR_PID_DEBUG_OUTPUT, pid_out
1383
+          #if DISABLED(PID_OPENLOOP)
1384
+            , "pTerm", work_pid.Kp, "iTerm", work_pid.Ki, "dTerm", work_pid.Kd
1385
+          #endif
1386
+        );
1387
+      }
1388
+    }
1389
+  };
1390
+
1391
+#endif // HAS_PID_HEATING
1392
+
1393
+#if HAS_HOTEND
1394
+
1395
+  float Temperature::get_pid_output_hotend(const uint8_t E_NAME) {
1396
+    const uint8_t ee = HOTEND_INDEX;
1397
+
1398
+    #if ENABLED(PIDTEMP)
1399
+
1400
+      typedef PIDRunner<hotend_info_t, 0, PID_MAX> PIDRunnerHotend;
1401
+
1402
+      static PIDRunnerHotend hotend_pid[HOTENDS] = {
1403
+        #define _HOTENDPID(E) temp_hotend[E],
1404
+        REPEAT(HOTENDS, _HOTENDPID)
1405
+      };
1406
+
1407
+      const float pid_output = hotend_pid[ee].get_pid_output();
1402 1408
 
1403 1409
       #if ENABLED(PID_DEBUG)
1404
-        if (ee == active_extruder && pid_debug_flag) {
1405
-          SERIAL_ECHO_MSG(STR_PID_DEBUG, ee, STR_PID_DEBUG_INPUT, temp_hotend[ee].celsius, STR_PID_DEBUG_OUTPUT, pid_output
1406
-            #if DISABLED(PID_OPENLOOP)
1407
-              , STR_PID_DEBUG_PTERM, work_pid[ee].Kp
1408
-              , STR_PID_DEBUG_ITERM, work_pid[ee].Ki
1409
-              , STR_PID_DEBUG_DTERM, work_pid[ee].Kd
1410
-              #if ENABLED(PID_EXTRUSION_SCALING)
1411
-                , STR_PID_DEBUG_CTERM, work_pid[ee].Kc
1412
-              #endif
1413
-            #endif
1414
-          );
1415
-        }
1410
+        if (ee == active_extruder)
1411
+          hotend_pid[ee].debug(temp_hotend[ee].celsius, pid_output, F("E"), ee);
1416 1412
       #endif
1417 1413
 
1418 1414
     #elif ENABLED(MPCTEMP)
1415
+
1419 1416
       MPCHeaterInfo &hotend = temp_hotend[ee];
1420 1417
       MPC_t &constants = hotend.constants;
1421 1418
 
@@ -1497,7 +1494,7 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
1497 1494
     #else // No PID or MPC enabled
1498 1495
 
1499 1496
       const bool is_idling = TERN0(HEATER_IDLE_HANDLER, heater_idle[ee].timed_out);
1500
-      const float pid_output = (!is_idling && temp_hotend[ee].celsius < temp_hotend[ee].target) ? BANG_MAX : 0;
1497
+      const float pid_output = (!is_idling && temp_hotend[ee].is_below_target()) ? BANG_MAX : 0;
1501 1498
 
1502 1499
     #endif
1503 1500
 
@@ -1509,61 +1506,9 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
1509 1506
 #if ENABLED(PIDTEMPBED)
1510 1507
 
1511 1508
   float Temperature::get_pid_output_bed() {
1512
-
1513
-    #if DISABLED(PID_OPENLOOP)
1514
-
1515
-      static PID_t work_pid{0};
1516
-      static float temp_iState = 0, temp_dState = 0;
1517
-      static bool pid_reset = true;
1518
-      float pid_output = 0;
1519
-      const float max_power_over_i_gain = float(MAX_BED_POWER) / temp_bed.pid.Ki - float(MIN_BED_POWER),
1520
-                  pid_error = temp_bed.target - temp_bed.celsius;
1521
-
1522
-      if (!temp_bed.target || pid_error < -(PID_FUNCTIONAL_RANGE)) {
1523
-        pid_output = 0;
1524
-        pid_reset = true;
1525
-      }
1526
-      else if (pid_error > PID_FUNCTIONAL_RANGE) {
1527
-        pid_output = MAX_BED_POWER;
1528
-        pid_reset = true;
1529
-      }
1530
-      else {
1531
-        if (pid_reset) {
1532
-          temp_iState = 0.0;
1533
-          work_pid.Kd = 0.0;
1534
-          pid_reset = false;
1535
-        }
1536
-
1537
-        temp_iState = constrain(temp_iState + pid_error, 0, max_power_over_i_gain);
1538
-
1539
-        work_pid.Kp = temp_bed.pid.Kp * pid_error;
1540
-        work_pid.Ki = temp_bed.pid.Ki * temp_iState;
1541
-        work_pid.Kd = work_pid.Kd + PID_K2 * (temp_bed.pid.Kd * (temp_dState - temp_bed.celsius) - work_pid.Kd);
1542
-
1543
-        temp_dState = temp_bed.celsius;
1544
-
1545
-        pid_output = constrain(work_pid.Kp + work_pid.Ki + work_pid.Kd + float(MIN_BED_POWER), 0, MAX_BED_POWER);
1546
-      }
1547
-
1548
-    #else // PID_OPENLOOP
1549
-
1550
-      const float pid_output = constrain(temp_bed.target, 0, MAX_BED_POWER);
1551
-
1552
-    #endif // PID_OPENLOOP
1553
-
1554
-    #if ENABLED(PID_BED_DEBUG)
1555
-      if (pid_debug_flag) {
1556
-        SERIAL_ECHO_MSG(
1557
-          " PID_BED_DEBUG : Input ", temp_bed.celsius, " Output ", pid_output
1558
-          #if DISABLED(PID_OPENLOOP)
1559
-            , STR_PID_DEBUG_PTERM, work_pid.Kp
1560
-            , STR_PID_DEBUG_ITERM, work_pid.Ki
1561
-            , STR_PID_DEBUG_DTERM, work_pid.Kd
1562
-          #endif
1563
-        );
1564
-      }
1565
-    #endif
1566
-
1509
+    static PIDRunner<bed_info_t, MIN_BED_POWER, MAX_BED_POWER> bed_pid(temp_bed);
1510
+    const float pid_output = bed_pid.get_pid_output();
1511
+    TERN_(PID_BED_DEBUG, bed_pid.debug(temp_bed.celsius, pid_output, F("(Bed)")));
1567 1512
     return pid_output;
1568 1513
   }
1569 1514
 
@@ -1572,114 +1517,17 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
1572 1517
 #if ENABLED(PIDTEMPCHAMBER)
1573 1518
 
1574 1519
   float Temperature::get_pid_output_chamber() {
1575
-
1576
-    #if DISABLED(PID_OPENLOOP)
1577
-
1578
-      static PID_t work_pid{0};
1579
-      static float temp_iState = 0, temp_dState = 0;
1580
-      static bool pid_reset = true;
1581
-      float pid_output = 0;
1582
-      const float max_power_over_i_gain = float(MAX_CHAMBER_POWER) / temp_chamber.pid.Ki - float(MIN_CHAMBER_POWER),
1583
-                  pid_error = temp_chamber.target - temp_chamber.celsius;
1584
-
1585
-      if (!temp_chamber.target || pid_error < -(PID_FUNCTIONAL_RANGE)) {
1586
-        pid_output = 0;
1587
-        pid_reset = true;
1588
-      }
1589
-      else if (pid_error > PID_FUNCTIONAL_RANGE) {
1590
-        pid_output = MAX_CHAMBER_POWER;
1591
-        pid_reset = true;
1592
-      }
1593
-      else {
1594
-        if (pid_reset) {
1595
-          temp_iState = 0.0;
1596
-          work_pid.Kd = 0.0;
1597
-          pid_reset = false;
1598
-        }
1599
-
1600
-        temp_iState = constrain(temp_iState + pid_error, 0, max_power_over_i_gain);
1601
-
1602
-        work_pid.Kp = temp_chamber.pid.Kp * pid_error;
1603
-        work_pid.Ki = temp_chamber.pid.Ki * temp_iState;
1604
-        work_pid.Kd = work_pid.Kd + PID_K2 * (temp_chamber.pid.Kd * (temp_dState - temp_chamber.celsius) - work_pid.Kd);
1605
-
1606
-        temp_dState = temp_chamber.celsius;
1607
-
1608
-        pid_output = constrain(work_pid.Kp + work_pid.Ki + work_pid.Kd + float(MIN_CHAMBER_POWER), 0, MAX_CHAMBER_POWER);
1609
-      }
1610
-
1611
-    #else // PID_OPENLOOP
1612
-
1613
-      const float pid_output = constrain(temp_chamber.target, 0, MAX_CHAMBER_POWER);
1614
-
1615
-    #endif // PID_OPENLOOP
1616
-
1617
-    #if ENABLED(PID_CHAMBER_DEBUG)
1618
-    {
1619
-      SERIAL_ECHO_MSG(
1620
-        " PID_CHAMBER_DEBUG : Input ", temp_chamber.celsius, " Output ", pid_output
1621
-        #if DISABLED(PID_OPENLOOP)
1622
-          , STR_PID_DEBUG_PTERM, work_pid.Kp
1623
-          , STR_PID_DEBUG_ITERM, work_pid.Ki
1624
-          , STR_PID_DEBUG_DTERM, work_pid.Kd
1625
-        #endif
1626
-      );
1627
-    }
1628
-    #endif
1629
-
1520
+    static PIDRunner<chamber_info_t, MIN_CHAMBER_POWER, MAX_CHAMBER_POWER> chamber_pid(temp_chamber);
1521
+    const float pid_output = chamber_pid.get_pid_output();
1522
+    TERN_(PID_CHAMBER_DEBUG, chamber_pid.debug(temp_chamber.celsius, pid_output, F("(Chamber)")));
1630 1523
     return pid_output;
1631 1524
   }
1632 1525
 
1633 1526
 #endif // PIDTEMPCHAMBER
1634 1527
 
1635
-/**
1636
- * Manage heating activities for extruder hot-ends and a heated bed
1637
- *  - Acquire updated temperature readings
1638
- *    - Also resets the watchdog timer
1639
- *  - Invoke thermal runaway protection
1640
- *  - Manage extruder auto-fan
1641
- *  - Apply filament width to the extrusion rate (may move)
1642
- *  - Update the heated bed PID output value
1643
- */
1644
-void Temperature::manage_heater() {
1645
-  if (marlin_state == MF_INITIALIZING) return hal.watchdog_refresh(); // If Marlin isn't started, at least reset the watchdog!
1646
-
1647
-  static bool no_reentry = false;  // Prevent recursion
1648
-  if (no_reentry) return;
1649
-  REMEMBER(mh, no_reentry, true);
1650
-
1651
-  #if ENABLED(EMERGENCY_PARSER)
1652
-    if (emergency_parser.killed_by_M112) kill(FPSTR(M112_KILL_STR), nullptr, true);
1653
-
1654
-    if (emergency_parser.quickstop_by_M410) {
1655
-      emergency_parser.quickstop_by_M410 = false; // quickstop_stepper may call idle so clear this now!
1656
-      quickstop_stepper();
1657
-    }
1658
-  #endif
1659
-
1660
-  if (!updateTemperaturesIfReady()) return; // Will also reset the watchdog if temperatures are ready
1661
-
1662
-  #if DISABLED(IGNORE_THERMOCOUPLE_ERRORS)
1663
-    #if TEMP_SENSOR_0_IS_MAX_TC
1664
-      if (degHotend(0) > _MIN(HEATER_0_MAXTEMP, TEMP_SENSOR_0_MAX_TC_TMAX - 1.0)) max_temp_error(H_E0);
1665
-      if (degHotend(0) < _MAX(HEATER_0_MINTEMP, TEMP_SENSOR_0_MAX_TC_TMIN + .01)) min_temp_error(H_E0);
1666
-    #endif
1667
-    #if TEMP_SENSOR_1_IS_MAX_TC
1668
-      if (degHotend(1) > _MIN(HEATER_1_MAXTEMP, TEMP_SENSOR_1_MAX_TC_TMAX - 1.0)) max_temp_error(H_E1);
1669
-      if (degHotend(1) < _MAX(HEATER_1_MINTEMP, TEMP_SENSOR_1_MAX_TC_TMIN + .01)) min_temp_error(H_E1);
1670
-    #endif
1671
-    #if TEMP_SENSOR_REDUNDANT_IS_MAX_TC
1672
-      if (degRedundant() > TEMP_SENSOR_REDUNDANT_MAX_TC_TMAX - 1.0) max_temp_error(H_REDUNDANT);
1673
-      if (degRedundant() < TEMP_SENSOR_REDUNDANT_MAX_TC_TMIN + .01) min_temp_error(H_REDUNDANT);
1674
-    #endif
1675
-  #else
1676
-    #warning "Safety Alert! Disable IGNORE_THERMOCOUPLE_ERRORS for the final build!"
1677
-  #endif
1678
-
1679
-  millis_t ms = millis();
1680
-
1681
-  #if HAS_HOTEND
1528
+#if HAS_HOTEND
1682 1529
 
1530
+  void Temperature::manage_hotends(const millis_t &ms) {
1683 1531
     HOTEND_LOOP() {
1684 1532
       #if ENABLED(THERMAL_PROTECTION_HOTENDS)
1685 1533
         if (degHotend(e) > temp_range[e].maxtemp) max_temp_error((heater_id_t)e);
@@ -1707,25 +1555,13 @@ void Temperature::manage_heater() {
1707 1555
       #endif
1708 1556
 
1709 1557
     } // HOTEND_LOOP
1558
+  }
1710 1559
 
1711
-  #endif // HAS_HOTEND
1712
-
1713
-  #if HAS_TEMP_REDUNDANT
1714
-    // Make sure measured temperatures are close together
1715
-    if (ABS(degRedundantTarget() - degRedundant()) > TEMP_SENSOR_REDUNDANT_MAX_DIFF)
1716
-      _temp_error((heater_id_t)HEATER_ID(TEMP_SENSOR_REDUNDANT_TARGET), F(STR_REDUNDANCY), GET_TEXT_F(MSG_ERR_REDUNDANT_TEMP));
1717
-  #endif
1718
-
1719
-  // Manage extruder auto fans and/or read fan tachometers
1720
-  TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms));
1560
+#endif // HAS_HOTEND
1721 1561
 
1722
-  /**
1723
-   * Dynamically set the volumetric multiplier based
1724
-   * on the delayed Filament Width measurement.
1725
-   */
1726
-  TERN_(FILAMENT_WIDTH_SENSOR, filwidth.update_volumetric());
1562
+#if HAS_HEATED_BED
1727 1563
 
1728
-  #if HAS_HEATED_BED
1564
+  void Temperature::manage_heated_bed(const millis_t &ms) {
1729 1565
 
1730 1566
     #if ENABLED(THERMAL_PROTECTION_BED)
1731 1567
       if (degBed() > BED_MAXTEMP) max_temp_error(H_BED);
@@ -1770,9 +1606,7 @@ void Temperature::manage_heater() {
1770 1606
       #if HEATER_IDLE_HANDLER
1771 1607
         if (heater_idle[IDLE_INDEX_BED].timed_out) {
1772 1608
           temp_bed.soft_pwm_amount = 0;
1773
-          #if DISABLED(PIDTEMPBED)
1774
-            WRITE_HEATER_BED(LOW);
1775
-          #endif
1609
+          if (DISABLED(PIDTEMPBED)) WRITE_HEATER_BED(LOW);
1776 1610
         }
1777 1611
         else
1778 1612
       #endif
@@ -1785,10 +1619,10 @@ void Temperature::manage_heater() {
1785 1619
             #if ENABLED(BED_LIMIT_SWITCHING)
1786 1620
               if (temp_bed.celsius >= temp_bed.target + BED_HYSTERESIS)
1787 1621
                 temp_bed.soft_pwm_amount = 0;
1788
-              else if (temp_bed.celsius <= temp_bed.target - (BED_HYSTERESIS))
1622
+              else if (temp_bed.is_below_target(-(BED_HYSTERESIS) + 1))
1789 1623
                 temp_bed.soft_pwm_amount = MAX_BED_POWER >> 1;
1790 1624
             #else // !PIDTEMPBED && !BED_LIMIT_SWITCHING
1791
-              temp_bed.soft_pwm_amount = temp_bed.celsius < temp_bed.target ? MAX_BED_POWER >> 1 : 0;
1625
+              temp_bed.soft_pwm_amount = temp_bed.is_below_target() ? MAX_BED_POWER >> 1 : 0;
1792 1626
             #endif
1793 1627
           }
1794 1628
           else {
@@ -1799,10 +1633,13 @@ void Temperature::manage_heater() {
1799 1633
       }
1800 1634
 
1801 1635
     } while (false);
1636
+  }
1802 1637
 
1803
-  #endif // HAS_HEATED_BED
1638
+#endif // HAS_HEATED_BED
1804 1639
 
1805
-  #if HAS_HEATED_CHAMBER
1640
+#if HAS_HEATED_CHAMBER
1641
+
1642
+  void Temperature::manage_heated_chamber(const millis_t &ms) {
1806 1643
 
1807 1644
     #ifndef CHAMBER_CHECK_INTERVAL
1808 1645
       #define CHAMBER_CHECK_INTERVAL 1000UL
@@ -1897,17 +1734,17 @@ void Temperature::manage_heater() {
1897 1734
           if (flag_chamber_excess_heat) {
1898 1735
             temp_chamber.soft_pwm_amount = 0;
1899 1736
             #if ENABLED(CHAMBER_VENT)
1900
-              if (!flag_chamber_off) servo[CHAMBER_VENT_SERVO_NR].move(temp_chamber.celsius <= temp_chamber.target ? 0 : 90);
1737
+              if (!flag_chamber_off) servo[CHAMBER_VENT_SERVO_NR].move(temp_chamber.is_below_target() ? 0 : 90);
1901 1738
             #endif
1902 1739
           }
1903 1740
           else {
1904 1741
             #if ENABLED(CHAMBER_LIMIT_SWITCHING)
1905 1742
               if (temp_chamber.celsius >= temp_chamber.target + TEMP_CHAMBER_HYSTERESIS)
1906 1743
                 temp_chamber.soft_pwm_amount = 0;
1907
-              else if (temp_chamber.celsius <= temp_chamber.target - (TEMP_CHAMBER_HYSTERESIS))
1744
+              else if (temp_chamber.is_below_target(-(TEMP_CHAMBER_HYSTERESIS) + 1))
1908 1745
                 temp_chamber.soft_pwm_amount = (MAX_CHAMBER_POWER) >> 1;
1909 1746
             #else
1910
-              temp_chamber.soft_pwm_amount = temp_chamber.celsius < temp_chamber.target ? (MAX_CHAMBER_POWER) >> 1 : 0;
1747
+              temp_chamber.soft_pwm_amount = temp_chamber.is_below_target() ? (MAX_CHAMBER_POWER) >> 1 : 0;
1911 1748
             #endif
1912 1749
             #if ENABLED(CHAMBER_VENT)
1913 1750
               if (!flag_chamber_off) servo[CHAMBER_VENT_SERVO_NR].move(0);
@@ -1923,10 +1760,13 @@ void Temperature::manage_heater() {
1923 1760
        tr_state_machine[RUNAWAY_IND_CHAMBER].run(temp_chamber.celsius, temp_chamber.target, H_CHAMBER, THERMAL_PROTECTION_CHAMBER_PERIOD, THERMAL_PROTECTION_CHAMBER_HYSTERESIS);
1924 1761
      #endif
1925 1762
    #endif
1763
+  }
1926 1764
 
1927
-  #endif // HAS_HEATED_CHAMBER
1765
+#endif // HAS_HEATED_CHAMBER
1928 1766
 
1929
-  #if HAS_COOLER
1767
+#if HAS_COOLER
1768
+
1769
+  void Temperature::manage_cooler(const millis_t &ms) {
1930 1770
 
1931 1771
     #ifndef COOLER_CHECK_INTERVAL
1932 1772
       #define COOLER_CHECK_INTERVAL 2000UL
@@ -1984,8 +1824,82 @@ void Temperature::manage_heater() {
1984 1824
     #if ENABLED(THERMAL_PROTECTION_COOLER)
1985 1825
       tr_state_machine[RUNAWAY_IND_COOLER].run(temp_cooler.celsius, temp_cooler.target, H_COOLER, THERMAL_PROTECTION_COOLER_PERIOD, THERMAL_PROTECTION_COOLER_HYSTERESIS);
1986 1826
     #endif
1827
+  }
1987 1828
 
1988
-  #endif // HAS_COOLER
1829
+#endif // HAS_COOLER
1830
+
1831
+/**
1832
+ * Manage heating activities for extruder hot-ends and a heated bed
1833
+ *  - Acquire updated temperature readings
1834
+ *    - Also resets the watchdog timer
1835
+ *  - Invoke thermal runaway protection
1836
+ *  - Manage extruder auto-fan
1837
+ *  - Apply filament width to the extrusion rate (may move)
1838
+ *  - Update the heated bed PID output value
1839
+ */
1840
+void Temperature::task() {
1841
+  if (marlin_state == MF_INITIALIZING) return hal.watchdog_refresh(); // If Marlin isn't started, at least reset the watchdog!
1842
+
1843
+  static bool no_reentry = false;  // Prevent recursion
1844
+  if (no_reentry) return;
1845
+  REMEMBER(mh, no_reentry, true);
1846
+
1847
+  #if ENABLED(EMERGENCY_PARSER)
1848
+    if (emergency_parser.killed_by_M112) kill(FPSTR(M112_KILL_STR), nullptr, true);
1849
+
1850
+    if (emergency_parser.quickstop_by_M410) {
1851
+      emergency_parser.quickstop_by_M410 = false; // quickstop_stepper may call idle so clear this now!
1852
+      quickstop_stepper();
1853
+    }
1854
+  #endif
1855
+
1856
+  if (!updateTemperaturesIfReady()) return; // Will also reset the watchdog if temperatures are ready
1857
+
1858
+  #if DISABLED(IGNORE_THERMOCOUPLE_ERRORS)
1859
+    #if TEMP_SENSOR_0_IS_MAX_TC
1860
+      if (degHotend(0) > _MIN(HEATER_0_MAXTEMP, TEMP_SENSOR_0_MAX_TC_TMAX - 1.0)) max_temp_error(H_E0);
1861
+      if (degHotend(0) < _MAX(HEATER_0_MINTEMP, TEMP_SENSOR_0_MAX_TC_TMIN + .01)) min_temp_error(H_E0);
1862
+    #endif
1863
+    #if TEMP_SENSOR_1_IS_MAX_TC
1864
+      if (degHotend(1) > _MIN(HEATER_1_MAXTEMP, TEMP_SENSOR_1_MAX_TC_TMAX - 1.0)) max_temp_error(H_E1);
1865
+      if (degHotend(1) < _MAX(HEATER_1_MINTEMP, TEMP_SENSOR_1_MAX_TC_TMIN + .01)) min_temp_error(H_E1);
1866
+    #endif
1867
+    #if TEMP_SENSOR_REDUNDANT_IS_MAX_TC
1868
+      if (degRedundant() > TEMP_SENSOR_REDUNDANT_MAX_TC_TMAX - 1.0) max_temp_error(H_REDUNDANT);
1869
+      if (degRedundant() < TEMP_SENSOR_REDUNDANT_MAX_TC_TMIN + .01) min_temp_error(H_REDUNDANT);
1870
+    #endif
1871
+  #else
1872
+    #warning "Safety Alert! Disable IGNORE_THERMOCOUPLE_ERRORS for the final build!"
1873
+  #endif
1874
+
1875
+  const millis_t ms = millis();
1876
+
1877
+  // Handle Hotend Temp Errors, Heating Watch, etc.
1878
+  TERN_(HAS_HOTEND, manage_hotends(ms));
1879
+
1880
+  #if HAS_TEMP_REDUNDANT
1881
+    // Make sure measured temperatures are close together
1882
+    if (ABS(degRedundantTarget() - degRedundant()) > TEMP_SENSOR_REDUNDANT_MAX_DIFF)
1883
+      _temp_error((heater_id_t)HEATER_ID(TEMP_SENSOR_REDUNDANT_TARGET), F(STR_REDUNDANCY), GET_TEXT_F(MSG_ERR_REDUNDANT_TEMP));
1884
+  #endif
1885
+
1886
+  // Manage extruder auto fans and/or read fan tachometers
1887
+  TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms));
1888
+
1889
+  /**
1890
+   * Dynamically set the volumetric multiplier based
1891
+   * on the delayed Filament Width measurement.
1892
+   */
1893
+  TERN_(FILAMENT_WIDTH_SENSOR, filwidth.update_volumetric());
1894
+
1895
+  // Handle Bed Temp Errors, Heating Watch, etc.
1896
+  TERN_(HAS_HEATED_BED, manage_heated_bed(ms));
1897
+
1898
+  // Handle Heated Chamber Temp Errors, Heating Watch, etc.
1899
+  TERN_(HAS_HEATED_CHAMBER, manage_heated_chamber(ms));
1900
+
1901
+  // Handle Cooler Temp Errors, Cooling Watch, etc.
1902
+  TERN_(HAS_COOLER, manage_cooler(ms));
1989 1903
 
1990 1904
   #if ENABLED(LASER_COOLANT_FLOW_METER)
1991 1905
     cooler.flowmeter_task(ms);
@@ -2479,7 +2393,7 @@ void Temperature::updateTemperaturesFromRawValues() {
2479 2393
 /**
2480 2394
  * Initialize the temperature manager
2481 2395
  *
2482
- * The manager is implemented by periodic calls to manage_heater()
2396
+ * The manager is implemented by periodic calls to task()
2483 2397
  *
2484 2398
  *  - Init (and disable) SPI thermocouples like MAX6675 and MAX31865
2485 2399
  *  - Disable RUMBA JTAG to accommodate a thermocouple extension
@@ -3111,7 +3025,7 @@ void Temperature::disable_all_heaters() {
3111 3025
     static millis_t next_max_tc_ms[MAX_TC_COUNT] = { 0 };
3112 3026
 
3113 3027
     // Return last-read value between readings
3114
-    millis_t ms = millis();
3028
+    const millis_t ms = millis();
3115 3029
     if (PENDING(ms, next_max_tc_ms[hindex]))
3116 3030
       return THERMO_TEMP(hindex);
3117 3031
 
@@ -3419,16 +3333,18 @@ void Temperature::isr() {
3419 3333
         _PWM_MOD(COOLER, soft_pwm_cooler, temp_cooler);
3420 3334
       #endif
3421 3335
 
3422
-      #if BOTH(USE_CONTROLLER_FAN, FAN_SOFT_PWM)
3423
-        WRITE(CONTROLLER_FAN_PIN, soft_pwm_controller.add(pwm_mask, soft_pwm_controller_speed));
3424
-      #endif
3425
-
3426 3336
       #if ENABLED(FAN_SOFT_PWM)
3337
+
3338
+        #if ENABLED(USE_CONTROLLER_FAN)
3339
+          WRITE(CONTROLLER_FAN_PIN, soft_pwm_controller.add(pwm_mask, soft_pwm_controller_speed));
3340
+        #endif
3341
+
3427 3342
         #define _FAN_PWM(N) do{                                     \
3428 3343
           uint8_t &spcf = soft_pwm_count_fan[N];                    \
3429 3344
           spcf = (spcf & pwm_mask) + (soft_pwm_amount_fan[N] >> 1); \
3430 3345
           WRITE_FAN(N, spcf > pwm_mask ? HIGH : LOW);               \
3431 3346
         }while(0)
3347
+
3432 3348
         #if HAS_FAN0
3433 3349
           _FAN_PWM(0);
3434 3350
         #endif

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

@@ -232,6 +232,7 @@ public:
232 232
 typedef struct HeaterInfo : public TempInfo {
233 233
   celsius_t target;
234 234
   uint8_t soft_pwm_amount;
235
+  bool is_below_target(const celsius_t offs=0) const { return (celsius < (target + offs)); }
235 236
 } heater_info_t;
236 237
 
237 238
 // A heater with PID stabilization
@@ -715,9 +716,9 @@ class Temperature {
715 716
     static void readings_ready();
716 717
 
717 718
     /**
718
-     * Call periodically to manage heaters
719
+     * Call periodically to manage heaters and keep the watchdog fed
719 720
      */
720
-    static void manage_heater() __O2; // __O2 added to work around a compiler error
721
+    static void task();
721 722
 
722 723
     /**
723 724
      * Preheating hotends
@@ -807,6 +808,8 @@ class Temperature {
807 808
         #endif
808 809
       }
809 810
 
811
+      static void manage_hotends(const millis_t &ms);
812
+
810 813
     #endif // HAS_HOTEND
811 814
 
812 815
     #if HAS_HEATED_BED
@@ -819,6 +822,9 @@ class Temperature {
819 822
       static celsius_t degTargetBed()  { return temp_bed.target; }
820 823
       static bool isHeatingBed()       { return temp_bed.target > temp_bed.celsius; }
821 824
       static bool isCoolingBed()       { return temp_bed.target < temp_bed.celsius; }
825
+      static bool degBedNear(const celsius_t temp) {
826
+        return ABS(wholeDegBed() - temp) < (TEMP_BED_HYSTERESIS);
827
+      }
822 828
 
823 829
       // Start watching the Bed to make sure it's really heating up
824 830
       static void start_watching_bed() { TERN_(WATCH_BED, watch_bed.restart(degBed(), degTargetBed())); }
@@ -835,9 +841,7 @@ class Temperature {
835 841
 
836 842
       static void wait_for_bed_heating();
837 843
 
838
-      static bool degBedNear(const celsius_t temp) {
839
-        return ABS(wholeDegBed() - temp) < (TEMP_BED_HYSTERESIS);
840
-      }
844
+      static void manage_heated_bed(const millis_t &ms);
841 845
 
842 846
     #endif // HAS_HEATED_BED
843 847
 
@@ -863,6 +867,7 @@ class Temperature {
863 867
         static bool isHeatingChamber()       { return temp_chamber.target > temp_chamber.celsius; }
864 868
         static bool isCoolingChamber()       { return temp_chamber.target < temp_chamber.celsius; }
865 869
         static bool wait_for_chamber(const bool no_wait_for_cooling=true);
870
+        static void manage_heated_chamber(const millis_t &ms);
866 871
       #endif
867 872
     #endif
868 873
 
@@ -886,6 +891,7 @@ class Temperature {
886 891
         static bool isLaserHeating()       { return temp_cooler.target > temp_cooler.celsius; }
887 892
         static bool isLaserCooling()       { return temp_cooler.target < temp_cooler.celsius; }
888 893
         static bool wait_for_cooler(const bool no_wait_for_cooling=true);
894
+        static void manage_cooler(const millis_t &ms);
889 895
       #endif
890 896
     #endif
891 897
 

+ 1
- 1
Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp 查看文件

@@ -62,7 +62,7 @@
62 62
   #define USB_HOST_MANUAL_POLL // Optimization to shut off IRQ automatically
63 63
 
64 64
   // Workarounds to keep Marlin's watchdog timer from barking...
65
-  void marlin_yield() { thermalManager.manage_heater(); }
65
+  void marlin_yield() { thermalManager.task(); }
66 66
   #define SYSTEM_OR_SPECIAL_YIELD(...) marlin_yield();
67 67
   #define delay(x) safe_delay(x)
68 68
 

Loading…
取消
儲存