heater.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. /*
  2. Reprap heater funtions based on Sprinter
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. This softwarepart for Heatercontrol is based on Sprinter
  15. big thanks to kliment (https://github.com/kliment/Sprinter)
  16. */
  17. #include <avr/pgmspace.h>
  18. #include "heater.h"
  19. #include "fastio.h"
  20. #include "pins.h"
  21. #include "Sprinter.h"
  22. #ifdef CONTROLLERFAN_PIN
  23. void controllerFan(void);
  24. #endif
  25. // Manage heater variables. For a thermistor or AD595 thermocouple, raw values refer to the
  26. // reading from the analog pin. For a MAX6675 thermocouple, the raw value is the temperature in 0.25
  27. // degree increments (i.e. 100=25 deg).
  28. int target_raw = 0;
  29. int target_temp = 0;
  30. int current_raw = 0;
  31. int current_raw_maxval = -32000;
  32. int current_raw_minval = 32000;
  33. int tt_maxval;
  34. int tt_minval;
  35. int target_bed_raw = 0;
  36. int current_bed_raw = 0;
  37. unsigned long previous_millis_heater, previous_millis_bed_heater, previous_millis_monitor;
  38. #ifdef PIDTEMP
  39. volatile unsigned char g_heater_pwm_val = 0;
  40. unsigned char PWM_off_time = 0;
  41. unsigned char PWM_out_on = 0;
  42. int temp_iState = 0;
  43. int temp_dState = 0;
  44. int prev_temp = 0;
  45. int pTerm;
  46. int iTerm;
  47. int dTerm;
  48. //int output;
  49. int error;
  50. int heater_duty = 0;
  51. const int temp_iState_min = 256L * -PID_INTEGRAL_DRIVE_MAX / PID_IGAIN;
  52. const int temp_iState_max = 256L * PID_INTEGRAL_DRIVE_MAX / PID_IGAIN;
  53. #endif
  54. #ifdef AUTOTEMP
  55. float autotemp_max=AUTO_TEMP_MAX;
  56. float autotemp_min=AUTO_TEMP_MIN;
  57. float autotemp_factor=AUTO_TEMP_FACTOR;
  58. int autotemp_setpoint=0;
  59. bool autotemp_enabled=true;
  60. #endif
  61. #ifndef HEATER_CURRENT
  62. #define HEATER_CURRENT 255
  63. #endif
  64. #ifdef SMOOTHING
  65. uint32_t nma = 0;
  66. #endif
  67. #ifdef WATCHPERIOD
  68. int watch_raw = -1000;
  69. unsigned long watchmillis = 0;
  70. #endif
  71. #ifdef MINTEMP
  72. int minttemp = temp2analogh(MINTEMP);
  73. #endif
  74. #ifdef MAXTEMP
  75. int maxttemp = temp2analogh(MAXTEMP);
  76. #endif
  77. #define HEAT_INTERVAL 250
  78. #ifdef HEATER_USES_MAX6675
  79. unsigned long max6675_previous_millis = 0;
  80. int max6675_temp = 2000;
  81. int read_max6675()
  82. {
  83. if (millis() - max6675_previous_millis < HEAT_INTERVAL)
  84. return max6675_temp;
  85. max6675_previous_millis = millis();
  86. max6675_temp = 0;
  87. #ifdef PRR
  88. PRR &= ~(1<<PRSPI);
  89. #elif defined PRR0
  90. PRR0 &= ~(1<<PRSPI);
  91. #endif
  92. SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPR0);
  93. // enable TT_MAX6675
  94. WRITE(MAX6675_SS, 0);
  95. // ensure 100ns delay - a bit extra is fine
  96. delay(1);
  97. // read MSB
  98. SPDR = 0;
  99. for (;(SPSR & (1<<SPIF)) == 0;);
  100. max6675_temp = SPDR;
  101. max6675_temp <<= 8;
  102. // read LSB
  103. SPDR = 0;
  104. for (;(SPSR & (1<<SPIF)) == 0;);
  105. max6675_temp |= SPDR;
  106. // disable TT_MAX6675
  107. WRITE(MAX6675_SS, 1);
  108. if (max6675_temp & 4)
  109. {
  110. // thermocouple open
  111. max6675_temp = 2000;
  112. }
  113. else
  114. {
  115. max6675_temp = max6675_temp >> 3;
  116. }
  117. return max6675_temp;
  118. }
  119. #endif
  120. #ifdef PID_SOFT_PWM
  121. void init_Timer2_softpwm(void)
  122. {
  123. // This is a simple SOFT PWM with 500 Hz for Extruder Heating
  124. TIFR2 = (1 << TOV2); // clear interrupt flag
  125. TCCR2B = (1 << CS22) | (1 << CS20); // start timer (ck/128 prescalar)
  126. TCCR2A = (1 << WGM21); // CTC mode
  127. OCR2A = 128; // We want to have at least 30Hz or else it gets choppy
  128. TIMSK2 = (1 << OCIE2A); // enable timer2 output compare match interrupt
  129. }
  130. ISR(TIMER2_COMPA_vect)
  131. {
  132. if(g_heater_pwm_val < 2)
  133. {
  134. #if LED_PIN > -1
  135. WRITE(LED_PIN,LOW);
  136. #endif
  137. WRITE(HEATER_0_PIN,LOW);
  138. PWM_out_on = 0;
  139. OCR2A = 128;
  140. }
  141. else if(g_heater_pwm_val > 253)
  142. {
  143. #if LED_PIN > -1
  144. WRITE(LED_PIN,HIGH);
  145. #endif
  146. WRITE(HEATER_0_PIN,HIGH);
  147. PWM_out_on = 1;
  148. OCR2A = 128;
  149. }
  150. else
  151. {
  152. if(PWM_out_on == 1)
  153. {
  154. #if LED_PIN > -1
  155. WRITE(LED_PIN,LOW);
  156. #endif
  157. WRITE(HEATER_0_PIN,LOW);
  158. PWM_out_on = 0;
  159. OCR2A = PWM_off_time;
  160. }
  161. else
  162. {
  163. #if LED_PIN > -1
  164. WRITE(LED_PIN,HIGH);
  165. #endif
  166. WRITE(HEATER_0_PIN,HIGH);
  167. PWM_out_on = 1;
  168. if(g_heater_pwm_val > 253)
  169. {
  170. OCR2A = 253;
  171. PWM_off_time = 2;
  172. }
  173. else if(g_heater_pwm_val < 2)
  174. {
  175. OCR2A = 2;
  176. PWM_off_time = 253;
  177. }
  178. else
  179. {
  180. OCR2A = g_heater_pwm_val;
  181. PWM_off_time = 255 - g_heater_pwm_val;
  182. }
  183. }
  184. }
  185. }
  186. #endif
  187. void manage_heater()
  188. {
  189. //Temperatur Monitor for repetier
  190. if((millis() - previous_millis_monitor) > 250 )
  191. {
  192. previous_millis_monitor = millis();
  193. if(manage_monitor <= 1)
  194. {
  195. showString(PSTR("MTEMP:"));
  196. Serial.print(millis());
  197. if(manage_monitor<1)
  198. {
  199. showString(PSTR(" "));
  200. Serial.print(analog2temp(current_raw));
  201. showString(PSTR(" "));
  202. Serial.print(target_temp);
  203. showString(PSTR(" "));
  204. #ifdef PIDTEMP
  205. Serial.println(heater_duty);
  206. #else
  207. #if (HEATER_0_PIN > -1)
  208. if(READ(HEATER_0_PIN))
  209. Serial.println(255);
  210. else
  211. Serial.println(0);
  212. #else
  213. Serial.println(0);
  214. #endif
  215. #endif
  216. }
  217. #if THERMISTORBED!=0
  218. else
  219. {
  220. showString(PSTR(" "));
  221. Serial.print(analog2tempBed(current_bed_raw));
  222. showString(PSTR(" "));
  223. Serial.print(analog2tempBed(target_bed_raw));
  224. showString(PSTR(" "));
  225. #if (HEATER_1_PIN > -1)
  226. if(READ(HEATER_1_PIN))
  227. Serial.println(255);
  228. else
  229. Serial.println(0);
  230. #else
  231. Serial.println(0);
  232. #endif
  233. }
  234. #endif
  235. }
  236. }
  237. // ENDE Temperatur Monitor for repetier
  238. if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL )
  239. return;
  240. previous_millis_heater = millis();
  241. #ifdef HEATER_USES_THERMISTOR
  242. current_raw = analogRead(TEMP_0_PIN);
  243. #ifdef DEBUG_HEAT_MGMT
  244. log_int("_HEAT_MGMT - analogRead(TEMP_0_PIN)", current_raw);
  245. log_int("_HEAT_MGMT - NUMTEMPS", NUMTEMPS);
  246. #endif
  247. // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target,
  248. // this switches it up so that the reading appears lower than target for the control logic.
  249. current_raw = 1023 - current_raw;
  250. #elif defined HEATER_USES_AD595
  251. current_raw = analogRead(TEMP_0_PIN);
  252. #elif defined HEATER_USES_MAX6675
  253. current_raw = read_max6675();
  254. #endif
  255. //MIN / MAX save to display the jitter of Heaterbarrel
  256. if(current_raw > current_raw_maxval)
  257. current_raw_maxval = current_raw;
  258. if(current_raw < current_raw_minval)
  259. current_raw_minval = current_raw;
  260. #ifdef SMOOTHING
  261. if (!nma) nma = SMOOTHFACTOR * current_raw;
  262. nma = (nma + current_raw) - (nma / SMOOTHFACTOR);
  263. current_raw = nma / SMOOTHFACTOR;
  264. #endif
  265. #ifdef WATCHPERIOD
  266. if(watchmillis && millis() - watchmillis > WATCHPERIOD)
  267. {
  268. if(watch_raw + 1 >= current_raw)
  269. {
  270. target_temp = target_raw = 0;
  271. WRITE(HEATER_0_PIN,LOW);
  272. #ifdef PID_SOFT_PWM
  273. g_heater_pwm_val = 0;
  274. #else
  275. analogWrite(HEATER_0_PIN, 0);
  276. #if LED_PIN>-1
  277. WRITE(LED_PIN,LOW);
  278. #endif
  279. #endif
  280. }
  281. else
  282. {
  283. watchmillis = 0;
  284. }
  285. }
  286. #endif
  287. //If tmp is lower then MINTEMP stop the Heater
  288. //or it os better to deaktivate the uutput PIN or PWM ?
  289. #ifdef MINTEMP
  290. if(current_raw <= minttemp)
  291. target_temp = target_raw = 0;
  292. #endif
  293. #ifdef MAXTEMP
  294. if(current_raw >= maxttemp)
  295. {
  296. target_temp = target_raw = 0;
  297. #if (ALARM_PIN > -1)
  298. WRITE(ALARM_PIN,HIGH);
  299. #endif
  300. }
  301. #endif
  302. #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) || defined (HEATER_USES_AD595)
  303. #ifdef PIDTEMP
  304. int current_temp = analog2temp(current_raw);
  305. error = target_temp - current_temp;
  306. int delta_temp = current_temp - prev_temp;
  307. prev_temp = current_temp;
  308. pTerm = ((long)PID_PGAIN * error) / 256;
  309. const int H0 = min(HEATER_DUTY_FOR_SETPOINT(target_temp),HEATER_CURRENT);
  310. heater_duty = H0 + pTerm;
  311. if(error < 30)
  312. {
  313. temp_iState += error;
  314. temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max);
  315. iTerm = ((long)PID_IGAIN * temp_iState) / 256;
  316. heater_duty += iTerm;
  317. }
  318. int prev_error = abs(target_temp - prev_temp);
  319. int log3 = 1; // discrete logarithm base 3, plus 1
  320. if(prev_error > 81){ prev_error /= 81; log3 += 4; }
  321. if(prev_error > 9){ prev_error /= 9; log3 += 2; }
  322. if(prev_error > 3){ prev_error /= 3; log3 ++; }
  323. dTerm = ((long)PID_DGAIN * delta_temp) / (256*log3);
  324. heater_duty += dTerm;
  325. heater_duty = constrain(heater_duty, 0, HEATER_CURRENT);
  326. #ifdef PID_SOFT_PWM
  327. g_heater_pwm_val = (unsigned char)heater_duty;
  328. #else
  329. analogWrite(HEATER_0_PIN, heater_duty);
  330. #if LED_PIN>-1
  331. analogWrite(LED_PIN, constrain(LED_PWM_FOR_BRIGHTNESS(heater_duty),0,255));
  332. #endif
  333. #endif
  334. #else
  335. if(current_raw >= target_raw)
  336. {
  337. WRITE(HEATER_0_PIN,LOW);
  338. #if LED_PIN>-1
  339. WRITE(LED_PIN,LOW);
  340. #endif
  341. }
  342. else
  343. {
  344. WRITE(HEATER_0_PIN,HIGH);
  345. #if LED_PIN > -1
  346. WRITE(LED_PIN,HIGH);
  347. #endif
  348. }
  349. #endif
  350. #endif
  351. if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL)
  352. return;
  353. previous_millis_bed_heater = millis();
  354. #ifndef TEMP_1_PIN
  355. return;
  356. #endif
  357. #if TEMP_1_PIN == -1
  358. return;
  359. #else
  360. #ifdef BED_USES_THERMISTOR
  361. current_bed_raw = analogRead(TEMP_1_PIN);
  362. #ifdef DEBUG_HEAT_MGMT
  363. log_int("_HEAT_MGMT - analogRead(TEMP_1_PIN)", current_bed_raw);
  364. log_int("_HEAT_MGMT - BNUMTEMPS", BNUMTEMPS);
  365. #endif
  366. // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target,
  367. // this switches it up so that the reading appears lower than target for the control logic.
  368. current_bed_raw = 1023 - current_bed_raw;
  369. #elif defined BED_USES_AD595
  370. current_bed_raw = analogRead(TEMP_1_PIN);
  371. #endif
  372. #ifdef MINTEMP
  373. if(current_bed_raw >= target_bed_raw || current_bed_raw < minttemp)
  374. #else
  375. if(current_bed_raw >= target_bed_raw)
  376. #endif
  377. {
  378. WRITE(HEATER_1_PIN,LOW);
  379. }
  380. else
  381. {
  382. WRITE(HEATER_1_PIN,HIGH);
  383. }
  384. #endif
  385. #ifdef CONTROLLERFAN_PIN
  386. controllerFan(); //Check if fan should be turned on to cool stepper drivers down
  387. #endif
  388. }
  389. #if defined (HEATER_USES_THERMISTOR) || defined (BED_USES_THERMISTOR)
  390. int temp2analog_thermistor(int celsius, const short table[][2], int numtemps)
  391. {
  392. int raw = 0;
  393. byte i;
  394. for (i=1; i<numtemps; i++)
  395. {
  396. if (table[i][1] < celsius)
  397. {
  398. raw = table[i-1][0] +
  399. (celsius - table[i-1][1]) *
  400. (table[i][0] - table[i-1][0]) /
  401. (table[i][1] - table[i-1][1]);
  402. break;
  403. }
  404. }
  405. // Overflow: Set to last value in the table
  406. if (i == numtemps) raw = table[i-1][0];
  407. return 1023 - raw;
  408. }
  409. #endif
  410. #if defined (HEATER_USES_AD595) || defined (BED_USES_AD595)
  411. int temp2analog_ad595(int celsius)
  412. {
  413. return celsius * 1024 / (500);
  414. }
  415. #endif
  416. #if defined (HEATER_USES_MAX6675) || defined (BED_USES_MAX6675)
  417. int temp2analog_max6675(int celsius)
  418. {
  419. return celsius * 4;
  420. }
  421. #endif
  422. #if defined (HEATER_USES_THERMISTOR) || defined (BED_USES_THERMISTOR)
  423. int analog2temp_thermistor(int raw,const short table[][2], int numtemps) {
  424. int celsius = 0;
  425. byte i;
  426. raw = 1023 - raw;
  427. for (i=1; i<numtemps; i++)
  428. {
  429. if (table[i][0] > raw)
  430. {
  431. celsius = table[i-1][1] +
  432. (raw - table[i-1][0]) *
  433. (table[i][1] - table[i-1][1]) /
  434. (table[i][0] - table[i-1][0]);
  435. break;
  436. }
  437. }
  438. // Overflow: Set to last value in the table
  439. if (i == numtemps) celsius = table[i-1][1];
  440. return celsius;
  441. }
  442. #endif
  443. #if defined (HEATER_USES_AD595) || defined (BED_USES_AD595)
  444. int analog2temp_ad595(int raw)
  445. {
  446. return raw * 500 / 1024;
  447. }
  448. #endif
  449. #if defined (HEATER_USES_MAX6675) || defined (BED_USES_MAX6675)
  450. int analog2temp_max6675(int raw)
  451. {
  452. return raw / 4;
  453. }
  454. #endif
  455. #ifdef CONTROLLERFAN_PIN
  456. unsigned long lastMotor = 0; //Save the time for when a motor was turned on last
  457. unsigned long lastMotorCheck = 0;
  458. void controllerFan()
  459. {
  460. if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms
  461. {
  462. lastMotorCheck = millis();
  463. if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN) || !READ(E_ENABLE_PIN)) //If any of the drivers are enabled...
  464. {
  465. lastMotor = millis(); //... set time to NOW so the fan will turn on
  466. }
  467. if ((millis() - lastMotor) >= (CONTROLLERFAN_SEC*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC...
  468. {
  469. WRITE(CONTROLLERFAN_PIN, LOW); //... turn the fan off
  470. }
  471. else
  472. {
  473. WRITE(CONTROLLERFAN_PIN, HIGH); //... turn the fan on
  474. }
  475. }
  476. }
  477. #endif