RepetierMAX/Repetier/Extruder.cpp
Jeff Epler 013bc037ca Fix compilation issues on Debian Wheezy
.. which uses Arduino 1.0.1 with gcc-avr 4.7.2-2.

SIG_USART0_RECV is forbidden to use, even in a #ifdef test.

PROGMEM data must additionally be const. (not all instances fixed,
for instance I didn't touch he NUM_EXTRUDER>2 case)

prog_char is deprecated but available by defining __PROG_TYPES_COMPAT__
before including pgmspace.h.
2013-07-14 16:25:09 -05:00

1084 lines
42 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
This file is part of Repetier-Firmware.
Repetier-Firmware is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Repetier-Firmware is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar. If not, see <http://www.gnu.org/licenses/>.
This firmware is a nearly complete rewrite of the sprinter firmware
by kliment (https://github.com/kliment/Sprinter)
which based on Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware.
*/
#define __PROG_TYPES_COMPAT__
#include "Reptier.h"
#include "pins_arduino.h"
#include "ui.h"
#if EEPROM_MODE!=0
#include "Eeprom.h"
#endif
Extruder *current_extruder;
#if NUM_EXTRUDER>0
prog_char const ext0_select_cmd[] PROGMEM = EXT0_SELECT_COMMANDS;
prog_char const ext0_deselect_cmd[] PROGMEM = EXT0_DESELECT_COMMANDS;
#endif
#if NUM_EXTRUDER>1
prog_char const ext1_select_cmd[] PROGMEM = EXT1_SELECT_COMMANDS;
prog_char const ext1_deselect_cmd[] PROGMEM = EXT1_DESELECT_COMMANDS;
#endif
#if NUM_EXTRUDER>2
prog_char ext2_select_cmd[] PROGMEM = EXT2_SELECT_COMMANDS;
prog_char ext2_deselect_cmd[] PROGMEM = EXT2_DESELECT_COMMANDS;
#endif
#if NUM_EXTRUDER>3
prog_char ext3_select_cmd[] PROGMEM = EXT3_SELECT_COMMANDS;
prog_char ext3_deselect_cmd[] PROGMEM = EXT3_DESELECT_COMMANDS;
#endif
#if NUM_EXTRUDER>4
prog_char ext4_select_cmd[] PROGMEM = EXT4_SELECT_COMMANDS;
prog_char ext4_deselect_cmd[] PROGMEM = EXT4_DESELECT_COMMANDS;
#endif
#if NUM_EXTRUDER>5
prog_char ext5_select_cmd[] PROGMEM = EXT5_SELECT_COMMANDS;
prog_char ext5_deselect_cmd[] PROGMEM = EXT5_DESELECT_COMMANDS;
#endif
Extruder extruder[NUM_EXTRUDER] = {
#if NUM_EXTRUDER>0
{0,EXT0_X_OFFSET,EXT0_Y_OFFSET,EXT0_STEPS_PER_MM,EXT0_ENABLE_PIN,EXT0_ENABLE_ON,
EXT0_MAX_FEEDRATE,EXT0_MAX_ACCELERATION,EXT0_MAX_START_FEEDRATE,0,EXT0_WATCHPERIOD
,EXT0_WAIT_RETRACT_TEMP,EXT0_WAIT_RETRACT_UNITS
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
,EXT0_ADVANCE_K
#endif
,EXT0_ADVANCE_L
#endif
,{0,EXT0_TEMPSENSOR_TYPE,EXT0_SENSOR_INDEX,0,0,0,0,0,EXT0_HEAT_MANAGER
#ifdef TEMP_PID
,0,EXT0_PID_INTEGRAL_DRIVE_MAX,EXT0_PID_INTEGRAL_DRIVE_MIN,EXT0_PID_P,EXT0_PID_I,EXT0_PID_D,EXT0_PID_MAX,0,0,0,{0,0,0,0}
#endif
}
,ext0_select_cmd,ext0_deselect_cmd,EXT0_EXTRUDER_COOLER_SPEED,0
}
#endif
#if NUM_EXTRUDER>1
,{1,EXT1_X_OFFSET,EXT1_Y_OFFSET,EXT1_STEPS_PER_MM,EXT1_ENABLE_PIN,EXT1_ENABLE_ON,
EXT1_MAX_FEEDRATE,EXT1_MAX_ACCELERATION,EXT1_MAX_START_FEEDRATE,0,EXT1_WATCHPERIOD
,EXT1_WAIT_RETRACT_TEMP,EXT1_WAIT_RETRACT_UNITS
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
,EXT1_ADVANCE_K
#endif
,EXT1_ADVANCE_L
#endif
,{1,EXT1_TEMPSENSOR_TYPE,EXT1_SENSOR_INDEX,0,0,0,0,0,EXT1_HEAT_MANAGER
#ifdef TEMP_PID
,0,EXT1_PID_INTEGRAL_DRIVE_MAX,EXT1_PID_INTEGRAL_DRIVE_MIN,EXT1_PID_P,EXT1_PID_I,EXT1_PID_D,EXT1_PID_MAX,0,0,0,{0,0,0,0}
#endif
}
,ext1_select_cmd,ext1_deselect_cmd,EXT1_EXTRUDER_COOLER_SPEED,0
}
#endif
#if NUM_EXTRUDER>2
,{2,EXT2_X_OFFSET,EXT2_Y_OFFSET,EXT2_STEPS_PER_MM,EXT2_ENABLE_PIN,EXT2_ENABLE_ON,
EXT2_MAX_FEEDRATE,EXT2_MAX_ACCELERATION,EXT2_MAX_START_FEEDRATE,0,EXT2_WATCHPERIOD
,EXT2_WAIT_RETRACT_TEMP,EXT2_WAIT_RETRACT_UNITS
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
,EXT2_ADVANCE_K
#endif
,EXT2_ADVANCE_L
#endif
,{2,EXT2_TEMPSENSOR_TYPE,EXT2_SENSOR_INDEX,0,0,0,0,0,EXT2_HEAT_MANAGER
#ifdef TEMP_PID
,0,EXT2_PID_INTEGRAL_DRIVE_MAX,EXT2_PID_INTEGRAL_DRIVE_MIN,EXT2_PID_P,EXT2_PID_I,EXT2_PID_D,EXT2_PID_MAX,0,0,0,{0,0,0,0}
#endif
}
,ext2_select_cmd,ext2_deselect_cmd,EXT2_EXTRUDER_COOLER_SPEED,0
}
#endif
#if NUM_EXTRUDER>3
,{3,EXT3_X_OFFSET,EXT3_Y_OFFSET,EXT3_STEPS_PER_MM,EXT3_ENABLE_PIN,EXT3_ENABLE_ON,
EXT3_MAX_FEEDRATE,EXT3_MAX_ACCELERATION,EXT3_MAX_START_FEEDRATE,0,EXT3_WATCHPERIOD
,EXT3_WAIT_RETRACT_TEMP,EXT3_WAIT_RETRACT_UNITS
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
,EXT3_ADVANCE_K
#endif
,EXT3_ADVANCE_L
#endif
,{3,EXT3_TEMPSENSOR_TYPE,EXT3_SENSOR_INDEX,0,0,0,0,0,EXT3_HEAT_MANAGER
#ifdef TEMP_PID
,0,EXT3_PID_INTEGRAL_DRIVE_MAX,EXT3_PID_INTEGRAL_DRIVE_MIN,EXT3_PID_P,EXT3_PID_I,EXT3_PID_D,EXT3_PID_MAX,0,0,0,{0,0,0,0}
#endif
}
,ext3_select_cmd,ext3_deselect_cmd,EXT3_EXTRUDER_COOLER_SPEED,0
}
#endif
#if NUM_EXTRUDER>4
,{4,EXT4_X_OFFSET,EXT4_Y_OFFSET,EXT4_STEPS_PER_MM,EXT4_ENABLE_PIN,EXT4_ENABLE_ON,
EXT4_MAX_FEEDRATE,EXT4_MAX_ACCELERATION,EXT4_MAX_START_FEEDRATE,0,EXT4_WATCHPERIOD
,EXT4_WAIT_RETRACT_TEMP,EXT4_WAIT_RETRACT_UNITS
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
,EXT4_ADVANCE_K
#endif
,EXT4_ADVANCE_L
#endif
,{4,EXT4_TEMPSENSOR_TYPE,EXT4_SENSOR_INDEX,0,0,0,0,0,EXT4_HEAT_MANAGER
#ifdef TEMP_PID
,0,EXT4_PID_INTEGRAL_DRIVE_MAX,EXT4_PID_INTEGRAL_DRIVE_MIN,EXT4_PID_P,EXT4_PID_I,EXT4_PID_D,EXT4_PID_MAX,0,0,0,{0,0,0,0}
#endif
}
,ext4_select_cmd,ext4_deselect_cmd,EXT4_EXTRUDER_COOLER_SPEED,0
}
#endif
#if NUM_EXTRUDER>5
,{5,EXT5_X_OFFSET,EXT5_Y_OFFSET,EXT5_STEPS_PER_MM,EXT5_ENABLE_PIN,EXT5_ENABLE_ON,
EXT5_MAX_FEEDRATE,EXT5_MAX_ACCELERATION,EXT5_MAX_START_FEEDRATE,0,EXT5_WATCHPERIOD
,EXT5_WAIT_RETRACT_TEMP,EXT5_WAIT_RETRACT_UNITS
#ifdef USE_ADVANCE
#ifdef ENABLE_QUADRATIC_ADVANCE
,EXT5_ADVANCE_K
#endif
,EXT5_ADVANCE_L
#endif
,{5,EXT5_TEMPSENSOR_TYPE,EXT5_SENSOR_INDEX,0,0,0,0,0,EXT5_HEAT_MANAGER
#ifdef TEMP_PID
,0,EXT5_PID_INTEGRAL_DRIVE_MAX,EXT5_PID_INTEGRAL_DRIVE_MIN,EXT5_PID_P,EXT5_PID_I,EXT5_PID_D,EXT5_PID_MAX,0,0,0,{0,0,0,0}
#endif
}
,ext5_select_cmd,ext5_deselect_cmd,EXT5_EXTRUDER_COOLER_SPEED,0
}
#endif
};
#if HAVE_HEATED_BED
#define NUM_TEMPERATURE_LOOPS NUM_EXTRUDER+1
TemperatureController heatedBedController = {NUM_EXTRUDER,HEATED_BED_SENSOR_TYPE,BED_SENSOR_INDEX,0,0,0,0,0,HEATED_BED_HEAT_MANAGER
#ifdef TEMP_PID
,0,HEATED_BED_PID_INTEGRAL_DRIVE_MAX,HEATED_BED_PID_INTEGRAL_DRIVE_MIN,HEATED_BED_PID_PGAIN,HEATED_BED_PID_IGAIN,HEATED_BED_PID_DGAIN,HEATED_BED_PID_MAX,0,0,0,{0,0,0,0}
#endif
};
#else
#define NUM_TEMPERATURE_LOOPS NUM_EXTRUDER
#endif
TemperatureController *tempController[NUM_TEMPERATURE_LOOPS] = {
#if NUM_EXTRUDER>0
&extruder[0].tempControl
#endif
#if NUM_EXTRUDER>1
,&extruder[1].tempControl
#endif
#if NUM_EXTRUDER>2
,&extruder[2].tempControl
#endif
#if NUM_EXTRUDER>3
,&extruder[3].tempControl
#endif
#if NUM_EXTRUDER>4
,&extruder[4].tempControl
#endif
#if NUM_EXTRUDER>5
,&extruder[5].tempControl
#endif
#if HAVE_HEATED_BED
,&heatedBedController
#endif
};
#ifdef USE_GENERIC_THERMISTORTABLE_1
short temptable_generic1[GENERIC_THERM_NUM_ENTRIES][2];
#endif
#ifdef USE_GENERIC_THERMISTORTABLE_2
short temptable_generic2[GENERIC_THERM_NUM_ENTRIES][2];
#endif
#ifdef USE_GENERIC_THERMISTORTABLE_3
short temptable_generic3[GENERIC_THERM_NUM_ENTRIES][2];
#endif
byte manage_monitor = 255; ///< Temp. we want to monitor with our host. 1+NUM_EXTRUDER is heated bed
unsigned int counter_periodical=0;
volatile byte execute_periodical=0;
byte counter_250ms=25;
#ifdef SUPPORT_MAX6675
extern int read_max6675(byte ss_pin);
#endif
#if ANALOG_INPUTS>0
const uint8 osAnalogInputChannels[] PROGMEM = ANALOG_INPUT_CHANNELS;
uint8 osAnalogInputCounter[ANALOG_INPUTS];
uint osAnalogInputBuildup[ANALOG_INPUTS];
uint8 osAnalogInputPos=0; // Current sampling position
volatile uint osAnalogInputValues[ANALOG_INPUTS];
#endif
void initHeatedBed() {
#if HAVE_HEATED_BED
#ifdef TEMP_PID
if(heatedBedController.pidIGain) { // prevent division by zero
heatedBedController.tempIStateLimitMax = (float)heatedBedController.pidDriveMax*10.0f/heatedBedController.pidIGain;
heatedBedController.tempIStateLimitMin = (float)heatedBedController.pidDriveMin*10.0f/heatedBedController.pidIGain;
}
#endif
#endif
}
// ------------------------------------------------------------------------------------------------------------------
// ------------------------------------------- createGenericTable ---------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
#if defined(USE_GENERIC_THERMISTORTABLE_1) || defined(USE_GENERIC_THERMISTORTABLE_2) || defined(USE_GENERIC_THERMISTORTABLE_3)
void createGenericTable(short table[GENERIC_THERM_NUM_ENTRIES][2],short minTemp,short maxTemp,float beta,float r0,float t0,float r1,float r2) {
t0+=273.15f;
float rs,vs;
if(r1==0) {
rs = r2;
vs = GENERIC_THERM_VREF;
} else {
vs =(float)(GENERIC_THERM_VREF*r1)/(r1+r2);
rs = (r2*r1)/(r1+r2);
}
float k = r0*exp(-beta/t0);
float delta = (maxTemp-minTemp)/(GENERIC_THERM_NUM_ENTRIES-1.0f);
for(byte i=0;i<GENERIC_THERM_NUM_ENTRIES;i++) {
float t = maxTemp-i*delta;
float r = exp(beta/(t+272.65))*k;
float v = 4092*r*vs/((rs+r)*GENERIC_THERM_VREF);
int adc = (int)(v);
t *= 8;
if(adc>4092) adc=4092;
table[i][0] = (adc>>(ANALOG_REDUCE_BITS));
table[i][1] = (int)t;
#ifdef DEBUG_GENERIC
OUT_P_I("GenTemp: ",table[i][0]);
OUT_P_I_LN(",",table[i][1]);
#endif
}
}
#endif
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- initExtruder ------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
/** \brief Initalizes all extruder.
Updates the pin configuration needed for the extruder and activates extruder 0.
Starts a interrupt based analog input reader, which is used by simple thermistors
for temperature reading.
*/
void initExtruder() {
byte i;
current_extruder = &extruder[0];
#ifdef USE_GENERIC_THERMISTORTABLE_1
createGenericTable(temptable_generic1,GENERIC_THERM1_MIN_TEMP,GENERIC_THERM1_MAX_TEMP,GENERIC_THERM1_BETA,GENERIC_THERM1_R0,GENERIC_THERM1_T0,GENERIC_THERM1_R1,GENERIC_THERM1_R2);
#endif
#ifdef USE_GENERIC_THERMISTORTABLE_2
createGenericTable(temptable_generic2,GENERIC_THERM2_MIN_TEMP,GENERIC_THERM2_MAX_TEMP,GENERIC_THERM2_BETA,GENERIC_THERM2_R0,GENERIC_THERM2_T0,GENERIC_THERM2_R1,GENERIC_THERM2_R2);
#endif
#ifdef USE_GENERIC_THERMISTORTABLE_3
createGenericTable(temptable_generic3,GENERIC_THERM3_MIN_TEMP,GENERIC_THERM3_MAX_TEMP,GENERIC_THERM3_BETA,GENERIC_THERM3_R0,GENERIC_THERM3_T0,GENERIC_THERM3_R1,GENERIC_THERM3_R2);
#endif
#if defined(EXT0_STEP_PIN) && EXT0_STEP_PIN>-1
SET_OUTPUT(EXT0_DIR_PIN);
SET_OUTPUT(EXT0_STEP_PIN);
#endif
#if defined(EXT1_STEP_PIN) && EXT1_STEP_PIN>-1 && NUM_EXTRUDER>1
SET_OUTPUT(EXT1_DIR_PIN);
SET_OUTPUT(EXT1_STEP_PIN);
#endif
#if defined(EXT2_STEP_PIN) && EXT2_STEP_PIN>-1 && NUM_EXTRUDER>2
SET_OUTPUT(EXT2_DIR_PIN);
SET_OUTPUT(EXT2_STEP_PIN);
#endif
#if defined(EXT3_STEP_PIN) && EXT3_STEP_PIN>-1 && NUM_EXTRUDER>3
SET_OUTPUT(EXT3_DIR_PIN);
SET_OUTPUT(EXT3_STEP_PIN);
#endif
#if defined(EXT4_STEP_PIN) && EXT4_STEP_PIN>-1 && NUM_EXTRUDER>4
SET_OUTPUT(EXT4_DIR_PIN);
SET_OUTPUT(EXT4_STEP_PIN);
#endif
#if defined(EXT5_STEP_PIN) && EXT5_STEP_PIN>-1 && NUM_EXTRUDER>5
SET_OUTPUT(EXT5_DIR_PIN);
SET_OUTPUT(EXT5_STEP_PIN);
#endif
for(i=0;i<NUM_EXTRUDER;++i) {
Extruder *act = &extruder[i];
if(act->enablePin > -1) {
pinMode(act->enablePin,OUTPUT);
if(!act->enableOn) digitalWrite(act->enablePin,HIGH);
}
act->tempControl.lastTemperatureUpdate = millis();
#ifdef SUPPORT_MAX6675
if(act->sensorType==101) {
WRITE(SCK_PIN,0);
SET_OUTPUT(SCK_PIN);
WRITE(MOSI_PIN,1);
SET_OUTPUT(MOSI_PIN);
WRITE(MISO_PIN,1);
SET_INPUT(MISO_PIN);
digitalWrite(act->tempControl.sensorPin,1);
pinMode(act->tempControl.sensorPin,OUTPUT);
}
#endif
}
#if HEATED_BED_HEATER_PIN>-1
SET_OUTPUT(HEATED_BED_HEATER_PIN);
initHeatedBed();
#endif
extruder_select(0);
#if ANALOG_INPUTS>0
ADMUX = ANALOG_REF; // refernce voltage
for(i=0;i<ANALOG_INPUTS;i++) {
osAnalogInputCounter[i] = 0;
osAnalogInputBuildup[i] = 0;
osAnalogInputValues[i] = 0;
}
ADCSRA = _BV(ADEN)|_BV(ADSC)|ANALOG_PRESCALER;
//ADCSRA |= _BV(ADSC); // start ADC-conversion
while (ADCSRA & _BV(ADSC) ) {} // wait for conversion
/* ADCW must be read once, otherwise the next result is wrong. */
uint dummyADCResult;
dummyADCResult = ADCW;
// Enable interrupt driven conversion loop
byte channel = pgm_read_byte(&osAnalogInputChannels[osAnalogInputPos]);
#if defined(ADCSRB) && defined(MUX5)
if(channel & 8) // Reading channel 0-7 or 8-15?
ADCSRB |= _BV(MUX5);
else
ADCSRB &= ~_BV(MUX5);
#endif
ADMUX = (ADMUX & ~(0x1F)) | (channel & 7);
ADCSRA |= _BV(ADSC); // start conversion without interrupt!
#endif
}
void updateTempControlVars(TemperatureController *tc) {
#ifdef TEMP_PID
if(tc->pidIGain) { // prevent division by zero
tc->tempIStateLimitMax = (float)tc->pidDriveMax*10.0f/tc->pidIGain;
tc->tempIStateLimitMin = (float)tc->pidDriveMin*10.0f/tc->pidIGain;
}
#endif
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- extruder_select ---------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
/** \brief Select extruder ext_num.
This function changes and initalizes a new extruder. This is also called, after the eeprom values are changed.
*/
void extruder_select(byte ext_num) {
if(ext_num>=NUM_EXTRUDER)
ext_num = 0;
#if NUM_EXTRUDER>1
bool executeSelect = false;
if(ext_num!=current_extruder->id) {
gcode_execute_PString(current_extruder->deselectCommands);
executeSelect = true;
}
#endif
current_extruder->extrudePosition = printer_state.currentPositionSteps[3];
long dx = current_extruder->xOffset;
long dy = current_extruder->yOffset;
current_extruder = &extruder[ext_num];
dx -= current_extruder->xOffset;
dy -= current_extruder->yOffset;
#ifdef SEPERATE_EXTRUDER_POSITIONS
// Use seperate extruder positions only if beeing told. Slic3r e.g. creates a continuous extruder position increment
printer_state.currentPositionSteps[3] = current_extruder->extrudePosition;
#endif
printer_state.destinationSteps[3] = printer_state.currentPositionSteps[3];
axis_steps_per_unit[3] = current_extruder->stepsPerMM;
inv_axis_steps_per_unit[3] = 1.0f/axis_steps_per_unit[3];
max_feedrate[3] = current_extruder->maxFeedrate;
// max_start_speed_units_per_second[3] = current_extruder->maxStartFeedrate;
max_acceleration_units_per_sq_second[3] = max_travel_acceleration_units_per_sq_second[3] = current_extruder->maxAcceleration;
axis_travel_steps_per_sqr_second[3] = axis_steps_per_sqr_second[3] = max_acceleration_units_per_sq_second[3] * axis_steps_per_unit[3];
#if USE_OPS==1 || defined(USE_ADVANCE)
printer_state.minExtruderSpeed = (byte)floor(F_CPU/(TIMER0_PRESCALE*current_extruder->maxStartFeedrate*current_extruder->stepsPerMM));
printer_state.maxExtruderSpeed = (byte)floor(F_CPU/(TIMER0_PRESCALE*current_extruder->maxFeedrate*current_extruder->stepsPerMM));
if(printer_state.maxExtruderSpeed>15) printer_state.maxExtruderSpeed = 15;
if(printer_state.maxExtruderSpeed>=printer_state.minExtruderSpeed) {
printer_state.maxExtruderSpeed = printer_state.minExtruderSpeed;
} else {
float maxdist = current_extruder->maxFeedrate*current_extruder->maxFeedrate*0.00013888/current_extruder->maxAcceleration;
maxdist-= current_extruder->maxStartFeedrate*current_extruder->maxStartFeedrate*0.5/current_extruder->maxAcceleration;
printer_state.extruderAccelerateDelay = (byte)constrain(ceil(maxdist*current_extruder->stepsPerMM/(printer_state.minExtruderSpeed-printer_state.maxExtruderSpeed)),1,255);
}
float fmax=((float)F_CPU/((float)printer_state.maxExtruderSpeed*TIMER0_PRESCALE*axis_steps_per_unit[3]))*60.0; // Limit feedrate to interrupt speed
if(fmax<max_feedrate[3]) max_feedrate[3] = fmax;
#endif
updateTempControlVars(&current_extruder->tempControl);
#if USE_OPS==1
printer_state.opsRetractSteps = printer_state.opsRetractDistance*current_extruder->stepsPerMM;
printer_state.opsPushbackSteps = (printer_state.opsRetractDistance+printer_state.opsRetractBacklash)*current_extruder->stepsPerMM;
if(printer_state.opsMode<=1)
printer_state.opsMoveAfterSteps = 0;
else
printer_state.opsMoveAfterSteps = (int)(-(float)printer_state.opsRetractSteps*(100.0-printer_state.opsMoveAfter)*0.01);
#endif
if(dx || dy) {
float oldfeedrate = printer_state.feedrate;
move_steps(dx,dy,0,0,homing_feedrate[0],true,ALWAYS_CHECK_ENDSTOPS);
printer_state.offsetX += dx;
printer_state.offsetY += dy;
printer_state.feedrate = oldfeedrate;
}
#if NUM_EXTRUDER>1
if(executeSelect) // Run only when changing
gcode_execute_PString(current_extruder->selectCommands);
#endif
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- extruder_set_temperature ------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
void extruder_set_temperature(float temp_celsius,byte extr) {
bool alloffs = true;
for(byte i=0;i<NUM_EXTRUDER;i++)
if(tempController[i]->targetTemperatureC>15) alloffs = false;
#ifdef MAXTEMP
if(temp_celsius>MAXTEMP) temp_celsius = MAXTEMP;
#endif
if(temp_celsius<0) temp_celsius=0;
TemperatureController *tc = tempController[extr];
if(temp_celsius==tc->targetTemperatureC) return;
tc->targetTemperature = conv_temp_raw(tc->sensorType,temp_celsius);
tc->targetTemperatureC = temp_celsius;
if(temp_celsius<50) extruder[extr].coolerPWM = 0;
else extruder[extr].coolerPWM = extruder[extr].coolerSpeed;
OUT_P_FX("TargetExtr",extr,0);
OUT_P_FX_LN(":",temp_celsius,0);
#if USE_OPS==1
if(extr==current_extruder->id && temp_celsius<(MIN_EXTRUDER_TEMP)) { // Protect for cold filament
printer_state.filamentRetracted = false;
printmoveSeen = 0;
}
#endif
bool alloff = true;
for(byte i=0;i<NUM_EXTRUDER;i++)
if(tempController[i]->targetTemperatureC>15) alloff = false;
#if EEPROM_MODE != 0
if(alloff && !alloffs) // All heaters are now switched off?
epr_update_usage();
#endif
if(alloffs && !alloff) // heaters are turned on, start measuring printing time
printer_state.msecondsPrinting = millis();
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- heated_bed_set_temperature ----------------------------------------
// ------------------------------------------------------------------------------------------------------------------
void heated_bed_set_temperature(float temp_celsius) {
#if HAVE_HEATED_BED
if(temp_celsius>HEATED_BED_MAX_TEMP) temp_celsius = HEATED_BED_MAX_TEMP;
if(temp_celsius<0) temp_celsius = 0;
if(heatedBedController.targetTemperatureC==temp_celsius) return; // don't flood log with messages if killed
heatedBedController.targetTemperatureC=temp_celsius;
heatedBedController.targetTemperature = conv_temp_raw(heatedBedController.sensorType,temp_celsius);
OUT_P_FX_LN("TargetBed:",heatedBedController.targetTemperatureC,0);
#endif
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- heated_bed_get_temperature ----------------------------------------
// ------------------------------------------------------------------------------------------------------------------
float heated_bed_get_temperature() {
#if HAVE_HEATED_BED
TemperatureController *c = tempController[NUM_TEMPERATURE_LOOPS-1];
return c->currentTemperatureC;
//return conv_raw_temp(c->sensorType,c->currentTemperature);
#else
return -1;
#endif
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- extruder_disable --------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
/** \brief Disable stepper motor of current extruder. */
void extruder_disable() {
if(current_extruder->enablePin > -1)
digitalWrite(current_extruder->enablePin,!current_extruder->enableOn);
}
#define NUMTEMPS_1 28
// Epcos B57560G0107F000
const short temptable_1[NUMTEMPS_1][2] PROGMEM = {
{0,4000},{92,2400},{105,2320},{121,2240},{140,2160},{162,2080},{189,2000},{222,1920},{261,1840},{308,1760},
{365,1680},{434,1600},{519,1520},{621,1440},{744,1360},{891,1280},{1067,1200},{1272,1120},
{1771,960},{2357,800},{2943,640},{3429,480},{3760,320},{3869,240},{3912,200},{3948,160},{4077,-160},{4094,-440}
};
#define NUMTEMPS_2 21
const short temptable_2[NUMTEMPS_2][2] PROGMEM = {
{1*4, 848*8},{54*4, 275*8}, {107*4, 228*8}, {160*4, 202*8},{213*4, 185*8}, {266*4, 171*8}, {319*4, 160*8}, {372*4, 150*8},
{425*4, 141*8}, {478*4, 133*8},{531*4, 125*8},{584*4, 118*8},{637*4, 110*8},{690*4, 103*8},{743*4, 95*8},{796*4, 86*8},
{849*4, 77*8},{902*4, 65*8},{955*4, 49*8},{1008*4, 17*8},{1020*4, 0*8} //safety
};
#define NUMTEMPS_3 28
const short temptable_3[NUMTEMPS_3][2] PROGMEM = {
{1*4,864*8},{21*4,300*8},{25*4,290*8},{29*4,280*8},{33*4,270*8},{39*4,260*8},{46*4,250*8},{54*4,240*8},{64*4,230*8},{75*4,220*8},
{90*4,210*8},{107*4,200*8},{128*4,190*8},{154*4,180*8},{184*4,170*8},{221*4,160*8},{265*4,150*8},{316*4,140*8},{375*4,130*8},
{441*4,120*8},{513*4,110*8},{588*4,100*8},{734*4,80*8},{856*4,60*8},{938*4,40*8},{986*4,20*8},{1008*4,0*8},{1018*4,-20*8} };
#define NUMTEMPS_4 20
const short temptable_4[NUMTEMPS_4][2] PROGMEM = {
{1*4, 430*8},{54*4, 137*8},{107*4, 107*8},{160*4, 91*8},{213*4, 80*8},{266*4, 71*8},{319*4, 64*8},{372*4, 57*8},{425*4, 51*8},
{478*4, 46*8},{531*4, 41*8},{584*4, 35*8},{637*4, 30*8},{690*4, 25*8},{743*4, 20*8},{796*4, 14*8},{849*4, 7*8},{902*4, 0*8},
{955*4, -11*8},{1008*4, -35*8}};
#if NUM_TEMPS_USERTHERMISTOR0>0
const short temptable_5[NUM_TEMPS_USERTHERMISTOR0][2] PROGMEM = USER_THERMISTORTABLE0 ;
#endif
#if NUM_TEMPS_USERTHERMISTOR1>0
const short temptable_6[NUM_TEMPS_USERTHERMISTOR1][2] PROGMEM = USER_THERMISTORTABLE1 ;
#endif
#if NUM_TEMPS_USERTHERMISTOR2>0
const short temptable_7[NUM_TEMPS_USERTHERMISTOR2][2] PROGMEM = USER_THERMISTORTABLE2 ;
#endif
const short * const temptables[7] PROGMEM = {(short int *)&temptable_1[0][0],(short int *)&temptable_2[0][0],(short int *)&temptable_3[0][0],(short int *)&temptable_4[0][0]
#if NUM_TEMPS_USERTHERMISTOR0>0
,(short int *)&temptable_5[0][0]
#else
,0
#endif
#if NUM_TEMPS_USERTHERMISTOR1>0
,(short int *)&temptable_6[0][0]
#else
,0
#endif
#if NUM_TEMPS_USERTHERMISTOR2>0
,(short int *)&temptable_7[0][0]
#else
,0
#endif
};
const byte temptables_num[7] PROGMEM = {NUMTEMPS_1,NUMTEMPS_2,NUMTEMPS_3,NUMTEMPS_4,NUM_TEMPS_USERTHERMISTOR0,NUM_TEMPS_USERTHERMISTOR1,NUM_TEMPS_USERTHERMISTOR2};
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- read_raw_temperature ----------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
int read_raw_temperature(byte type,byte pin) {
switch(type) {
#if ANALOG_INPUTS>0
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 97:
case 98:
case 99:
return (1023<<(2-ANALOG_REDUCE_BITS))-(osAnalogInputValues[pin]>>(ANALOG_REDUCE_BITS)); // Convert to 10 bit result
case 50: // User defined PTC table
case 51:
case 52:
return (osAnalogInputValues[pin]>>(ANALOG_REDUCE_BITS)); // Convert to 10 bit result
case 100: // AD595
return (osAnalogInputValues[pin]>>(ANALOG_REDUCE_BITS));
#endif
#ifdef SUPPORT_MAX6675
case 101: // MAX6675
return read_max6675(pin);
#endif
}
return 4095; // unknown method, return high value to switch heater off for safety
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- conv_raw_temp -----------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
float conv_raw_temp(byte type,int raw_temp) {
//OUT_P_I_LN("OC for raw ",raw_temp);
switch(type) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
{
type--;
byte num = pgm_read_byte(&temptables_num[type])<<1;
byte i=2;
const short *temptable = (const short *)pgm_read_word(&temptables[type]); //pgm_read_word_near(&temptables[type]);
short oldraw = pgm_read_word(&temptable[0]);
short oldtemp = pgm_read_word(&temptable[1]);
short newraw,newtemp;
raw_temp = (1023<<(2-ANALOG_REDUCE_BITS))-raw_temp;
while(i<num) {
newraw = pgm_read_word(&temptable[i++]);
newtemp = pgm_read_word(&temptable[i++]);
if (newraw > raw_temp) {
//OUT_P_I("RC O:",oldtemp);OUT_P_I_LN(" OR:",oldraw);
//OUT_P_I("RC N:",newtemp);OUT_P_I_LN(" NR:",newraw);
return TEMP_INT_TO_FLOAT(oldtemp + (float)(raw_temp-oldraw)*(float)(newtemp-oldtemp)/(newraw-oldraw));
}
oldtemp = newtemp;
oldraw = newraw;
}
// Overflow: Set to last value in the table
return TEMP_INT_TO_FLOAT(newtemp);}
case 50: // User defined PTC thermistor
case 51:
case 52:
{
type-=46;
byte num = pgm_read_byte(&temptables_num[type])<<1;
byte i=2;
const short *temptable = (const short *)pgm_read_word(&temptables[type]); //pgm_read_word_near(&temptables[type]);
short oldraw = pgm_read_word(&temptable[0]);
short oldtemp = pgm_read_word(&temptable[1]);
short newraw,newtemp;
while(i<num) {
newraw = pgm_read_word(&temptable[i++]);
newtemp = pgm_read_word(&temptable[i++]);
if (newraw > raw_temp)
return TEMP_INT_TO_FLOAT(oldtemp + (float)(raw_temp-oldraw)*(float)(newtemp-oldtemp)/(newraw-oldraw));
oldtemp = newtemp;
oldraw = newraw;
}
// Overflow: Set to last value in the table
return TEMP_INT_TO_FLOAT(newtemp);
}
case 100: // AD595
return (int)((long)raw_temp * 500/(1024<<(2-ANALOG_REDUCE_BITS)));
#ifdef SUPPORT_MAX6675
case 101: // MAX6675
return raw_temp /4;
#endif
#if defined(USE_GENERIC_THERMISTORTABLE_1) || defined(USE_GENERIC_THERMISTORTABLE_2) || defined(USE_GENERIC_THERMISTORTABLE_3)
case 97:
case 98:
case 99: {
byte i=2;
const short *temptable;
#ifdef USE_GENERIC_THERMISTORTABLE_1
if(type == 97)
temptable = (const short *)temptable_generic1;
#endif
#ifdef USE_GENERIC_THERMISTORTABLE_2
if(type == 98)
temptable = (const short *)temptable_generic2;
#endif
#ifdef USE_GENERIC_THERMISTORTABLE_3
if(type == 99)
temptable = (const short *)temptable_generic3;
#endif
short oldraw = temptable[0];
short oldtemp = temptable[1];
short newraw,newtemp;
raw_temp = (1023<<(2-ANALOG_REDUCE_BITS))-raw_temp;
//OUT_P_I("Raw ",raw_temp);
while(i<GENERIC_THERM_NUM_ENTRIES*2) {
newraw = temptable[i++];
newtemp = temptable[i++];
if (newraw > raw_temp) {
//OUT_P_I("RC O:",oldtemp);OUT_P_I_LN(" OR:",oldraw);
//OUT_P_I("RC N:",newtemp);OUT_P_I_LN(" NR:",newraw);
return TEMP_INT_TO_FLOAT(oldtemp + (float)(raw_temp-oldraw)*(float)(newtemp-oldtemp)/(newraw-oldraw));
}
oldtemp = newtemp;
oldraw = newraw;
}
// Overflow: Set to last value in the table
return TEMP_INT_TO_FLOAT(newtemp);
}
#endif
}
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- conv_temp_raw -----------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
int conv_temp_raw(byte type,float tempf) {
int temp = TEMP_FLOAT_TO_INT(tempf);
switch(type) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
{
type--;
byte num = pgm_read_byte(&temptables_num[type])<<1;
byte i=2;
const short *temptable = (const short *)pgm_read_word(&temptables[type]); //pgm_read_word(&temptables[type]);
short oldraw = pgm_read_word(&temptable[0]);
short oldtemp = pgm_read_word(&temptable[1]);
short newraw,newtemp;
while(i<num) {
newraw = pgm_read_word(&temptable[i++]);
newtemp = pgm_read_word(&temptable[i++]);
if (newtemp < temp)
return (1023<<(2-ANALOG_REDUCE_BITS))- oldraw + (long)(oldtemp-temp)*(long)(oldraw-newraw)/(oldtemp-newtemp);
oldtemp = newtemp;
oldraw = newraw;
}
// Overflow: Set to last value in the table
return (1023<<(2-ANALOG_REDUCE_BITS))-newraw;
}
case 50: // user defined PTC thermistor
case 51:
case 52:
{
type-=46;
byte num = pgm_read_byte(&temptables_num[type])<<1;
byte i=2;
const short *temptable = (const short *)pgm_read_word(&temptables[type]); //pgm_read_word(&temptables[type]);
short oldraw = pgm_read_word(&temptable[0]);
short oldtemp = pgm_read_word(&temptable[1]);
short newraw,newtemp;
while(i<num) {
newraw = pgm_read_word(&temptable[i++]);
newtemp = pgm_read_word(&temptable[i++]);
if (newtemp > temp)
return oldraw + (long)(oldtemp-temp)*(long)(oldraw-newraw)/(oldtemp-newtemp);
oldtemp = newtemp;
oldraw = newraw;
}
// Overflow: Set to last value in the table
return newraw;
}
case 100: // HEATER_USES_AD595
return (int)((long)temp * (1024<<(2-ANALOG_REDUCE_BITS))/ 500);
#ifdef SUPPORT_MAX6675
case 101: // defined HEATER_USES_MAX6675
return temp * 4;
#endif
#if defined(USE_GENERIC_THERMISTORTABLE_1) || defined(USE_GENERIC_THERMISTORTABLE_2) || defined(USE_GENERIC_THERMISTORTABLE_3)
case 97:
case 98:
case 99: {
byte i=2;
const short *temptable;
#ifdef USE_GENERIC_THERMISTORTABLE_1
if(type == 97)
temptable = (const short *)temptable_generic1;
#endif
#ifdef USE_GENERIC_THERMISTORTABLE_2
if(type == 98)
temptable = (const short *)temptable_generic2;
#endif
#ifdef USE_GENERIC_THERMISTORTABLE_3
if(type == 99)
temptable = (const short *)temptable_generic3;
#endif
short oldraw = temptable[0];
short oldtemp = temptable[1];
short newraw,newtemp;
while(i<GENERIC_THERM_NUM_ENTRIES*2) {
newraw = temptable[i++];
newtemp = temptable[i++];
if (newtemp < temp)
return (1023<<(2-ANALOG_REDUCE_BITS))- oldraw + (long)(oldtemp-temp)*(long)(oldraw-newraw)/(oldtemp-newtemp);
oldtemp = newtemp;
oldraw = newraw;
}
// Overflow: Set to last value in the table
return (1023<<(2-ANALOG_REDUCE_BITS))-newraw;
}
#endif
}
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- disableAllHeater --------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
byte autotuneIndex = 255;
void disableAllHeater() {
for(byte i=0;i<NUM_TEMPERATURE_LOOPS;i++) {
TemperatureController *c = tempController[i];
c->targetTemperature = 0;
c->targetTemperatureC = 0;
pwm_pos[c->pwmIndex] = 0;
}
autotuneIndex = 255;
}
// ------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------ autotunePID -----------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
#ifdef TEMP_PID
void autotunePID(float temp,int controllerId)
{
TemperatureController *c = tempController[controllerId];
float currentTemp;
int cycles=0;
bool heating = true;
unsigned long temp_millis = millis();
unsigned long t1=temp_millis;
unsigned long t2=temp_millis;
long t_high;
long t_low;
long bias=c->pidMax>>1;
long d = c->pidMax>>1;
float Ku, Tu;
float Kp, Ki, Kd;
float maxTemp=20, minTemp=20;
OUT_P_LN("PID Autotune start");
disableAllHeater(); // switch off all heaters.
autotuneIndex = controllerId;
pwm_pos[c->pwmIndex] = c->pidMax;
for(;;) {
c->currentTemperature = read_raw_temperature(c->sensorType,c->sensorPin);
currentTemp = c->currentTemperatureC = conv_raw_temp(c->sensorType,c->currentTemperature);
unsigned long time = millis();
maxTemp=max(maxTemp,currentTemp);
minTemp=min(minTemp,currentTemp);
if(heating == true && currentTemp > temp) { // switch heating -> off
if(time - t2 > (controllerId<NUM_EXTRUDER ? 2500 : 1500)) {
heating=false;
pwm_pos[c->pwmIndex] = (bias - d);
t1=time;
t_high=t1 - t2;
maxTemp=temp;
}
}
if(heating == false && currentTemp < temp) {
if(time - t1 > (controllerId<NUM_EXTRUDER ? 5000 : 3000)) {
heating=true;
t2=time;
t_low=t2 - t1; // half wave length
if(cycles > 0) {
bias += (d*(t_high - t_low))/(t_low + t_high);
bias = constrain(bias, 20 ,c->pidMax-20);
if(bias > c->pidMax/2) d = c->pidMax - 1 - bias;
else d = bias;
OUT_P_I(" bias: ",bias);
OUT_P_I(" d: ",d);
OUT_P_F(" min: ",minTemp);
OUT_P_F_LN(" max: ",maxTemp);
if(cycles > 2) {
// Parameter according ZieglerNichols method: http://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
Ku = (4.0*d)/(3.14159*(maxTemp-minTemp));
Tu = ((float)(t_low + t_high)/1000.0);
OUT_P_F(" Ku: ",Ku);
OUT_P_F_LN(" Tu: ",Tu);
Kp = 0.6*Ku;
Ki = 2*Kp/Tu;
Kd = Kp*Tu*0.125;
OUT_P_LN(" Classic PID");
OUT_P_F_LN(" Kp: ",Kp);
OUT_P_F_LN(" Ki: ",Ki);
OUT_P_F_LN(" Kd: ",Kd);
/*
Kp = 0.33*Ku;
Ki = Kp/Tu;
Kd = Kp*Tu/3;
OUT_P_LN(" Some overshoot");
OUT_P_F_LN(" Kp: ",Kp);
OUT_P_F_LN(" Ki: ",Ki);
OUT_P_F_LN(" Kd: ",Kd);
Kp = 0.2*Ku;
Ki = 2*Kp/Tu;
Kd = Kp*Tu/3;
OUT_P_LN(" No overshoot");
OUT_P_F_LN(" Kp: ",Kp);
OUT_P_F_LN(" Ki: ",Ki);
OUT_P_F_LN(" Kd: ",Kd);
*/
}
}
pwm_pos[c->pwmIndex] = (bias + d);
cycles++;
minTemp=temp;
}
}
if(currentTemp > (temp + 20)) {
OUT_P_LN("PID Autotune failed! Temperature to high");
disableAllHeater();
return;
}
if(time - temp_millis > 1000) {
temp_millis = time;
print_temperatures();
}
if(((time - t1) + (time - t2)) > (10L*60L*1000L*2L)) { // 20 Minutes
OUT_P_LN("PID Autotune failed! timeout");
disableAllHeater();
return;
}
if(cycles > 5) {
OUT_P_LN("PID Autotune finished ! Place the Kp, Ki and Kd constants in the configuration.h");
disableAllHeater();
return;
}
UI_MEDIUM;
UI_SLOW;
}
}
#endif
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- write_monitor -----------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
/** \brief Writes monitored temperatures.
This function is called every 250ms to write the monitored temperature. If monitoring is
disabled, the function is not called.
*/
void write_monitor() {
out.print_long_P(PSTR("MTEMP:"),millis());
TemperatureController *act = tempController[manage_monitor];
OUT_P_F(" ",act->currentTemperatureC);
OUT_P_FX(" ",act->targetTemperatureC,0);
OUT_P_I_LN(" ",pwm_pos[act->pwmIndex]);
}
// ------------------------------------------------------------------------------------------------------------------
// --------------------------------------------- reportTempsensorError ----------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
bool reportTempsensorError() {
if(!(printer_state.flag0 & PRINTER_FLAG0_TEMPSENSOR_DEFECT)) return false;
for(byte i=0;i<NUM_TEMPERATURE_LOOPS;i++) {
int temp = tempController[i]->currentTemperatureC;
if(i==NUM_EXTRUDER) OUT_P("heated bed");
else OUT_P_I("extruder ",i);
if(temp<-10 || temp>400) {
OUT_P_LN(": temp sensor defect");
} else OUT_P_LN(": working");
}
OUT_P_LN("Printer set into dry run mode until restart!");
return true;
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- manage temperatures -----------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
/** Makes updates to temperatures and heater state every call.
Is called every 100ms.
*/
void manage_temperatures() {
for(byte controller=0;controller<NUM_TEMPERATURE_LOOPS;controller++) {
if(controller == autotuneIndex) continue;
TemperatureController *act = tempController[controller];
// Get Temperature
//int oldTemp = act->currentTemperatureC;
act->currentTemperature = read_raw_temperature(act->sensorType,act->sensorPin);
act->currentTemperatureC = conv_raw_temp(act->sensorType,act->currentTemperature);
if(!(printer_state.flag0 & PRINTER_FLAG0_TEMPSENSOR_DEFECT) && (act->currentTemperatureC<-10 || act->currentTemperatureC>400)) { // no temp sensor or short in sensor, disable heater
printer_state.flag0 |= PRINTER_FLAG0_TEMPSENSOR_DEFECT;
reportTempsensorError();
}
if(printer_state.flag0 & PRINTER_FLAG0_TEMPSENSOR_DEFECT) continue;
byte on = act->currentTemperature>=act->targetTemperature ? LOW : HIGH;
#ifdef TEMP_PID
act->tempArray[act->tempPointer++] = act->currentTemperatureC;
act->tempPointer &= 3;
if(act->heatManager==1) {
byte output;
float error = act->targetTemperatureC - act->currentTemperatureC;
if(act->targetTemperatureC<20.0f) output = 0; // off is off, even if damping term wants a heat peak!
else if(error>PID_CONTROL_RANGE)
output = act->pidMax;
else if(error<-PID_CONTROL_RANGE)
output = 0;
else {
float pidTerm = act->pidPGain * error;
act->tempIState = constrain(act->tempIState+error,act->tempIStateLimitMin,act->tempIStateLimitMax);
pidTerm += act->pidIGain * act->tempIState*0.1;
long dgain = act->pidDGain * (act->tempArray[act->tempPointer]-act->currentTemperatureC)*3.333f;
pidTerm += dgain;
#if SCALE_PID_TO_MAX==1
pidTerm = (pidTerm*act->pidMax)*0.0039062;
#endif
output = constrain((int)pidTerm, 0, act->pidMax);
}
pwm_pos[act->pwmIndex] = output;
} else
#endif
if(act->heatManager == 2) { // Bang-bang with reduced change frequency to save relais life
unsigned long time = millis();
if (time - act->lastTemperatureUpdate > HEATED_BED_SET_INTERVAL) {
pwm_pos[act->pwmIndex] = (on ? 255 : 0);
act->lastTemperatureUpdate = time;
}
} else { // Fast Bang-Bang fallback
pwm_pos[act->pwmIndex] = (on ? 255 : 0);
}
#ifdef MAXTEMP
if(act->currentTemperatureC>MAXTEMP) // Force heater off if MAXTEMP is exceeded
pwm_pos[act->pwmIndex] = 0;
#endif
#if LED_PIN>-1
if(act == &current_extruder->tempControl)
WRITE(LED_PIN,on);
#endif
}
if(printer_state.flag0 & PRINTER_FLAG0_TEMPSENSOR_DEFECT) {
for(byte i=0;i<NUM_TEMPERATURE_LOOPS;i++) {
pwm_pos[tempController[i]->pwmIndex] = 0;
}
debug_level |= 8; // Go into dry mode
}
}
// ------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------- read_max6675 ------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------
#ifdef SUPPORT_MAX6675
int read_max6675(byte ss_pin)
{
int max6675_temp = 0;
#ifdef PRR
PRR &= ~(1<<PRSPI);
#elif defined PRR0
PRR0 &= ~(1<<PRSPI);
#endif
SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPR0);
digitalWrite(ss_pin, 0); // enable TT_MAX6675
delay(1); // ensure 100ns delay - a bit extra is fine
SPDR = 0; // read MSB
while ((SPSR & (1<<SPIF)) == 0);
max6675_temp = SPDR;
max6675_temp <<= 8;
SPDR = 0; // read LSB
while ((SPSR & (1<<SPIF)) == 0);
max6675_temp |= SPDR;
digitalWrite(ss_pin, 1); // disable TT_MAX6675
return max6675_temp & 4 ? 2000 : max6675_temp >> 3; // thermocouple open?
}
#endif