--- /dev/null
+/*
+ this file is part of smoothie (http://smoothieware.org/). the motion control part is heavily based on grbl (https://github.com/simen/grbl).
+ smoothie 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.
+ smoothie 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 smoothie. if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef tempsensor_h
+#define tempsensor_h
+
+class TempSensor
+{
+public:
+ // Load config parameters using provided "base" names.
+ virtual void UpdateConfig(uint16_t module_checksum, uint16_t name_checksum) = 0;
+
+ // Return temperature in degrees Celsius.
+ virtual float get_temperature() = 0;
+
+ // Make sure the interface provides a destructor.
+ virtual ~TempSensor() {}
+};
+
+#endif
#include "TemperatureControl.h"
#include "TemperatureControlPool.h"
#include "libs/Pin.h"
-#include "libs/Median.h"
#include "modules/robot/Conveyor.h"
#include "PublicDataRequest.h"
#include "TemperatureControlPublicAccess.h"
#include "Config.h"
#include "checksumm.h"
#include "Gcode.h"
-#include "Adc.h"
#include "SlowTicker.h"
#include "Pauser.h"
#include "ConfigValue.h"
#include "TemperatureControl.h"
#include "PID_Autotuner.h"
+// Temp sensor implementations:
+#include "Thermistor.h"
+#include "max31855.h"
+
#include "MRI_Hooks.h"
#define UNDEFINED -1
-#define thermistor_checksum CHECKSUM("thermistor")
-#define r0_checksum CHECKSUM("r0")
+#define sensor_checksum CHECKSUM("sensor")
+
#define readings_per_second_checksum CHECKSUM("readings_per_second")
#define max_pwm_checksum CHECKSUM("max_pwm")
#define pwm_frequency_checksum CHECKSUM("pwm_frequency")
#define bang_bang_checksum CHECKSUM("bang_bang")
#define hysteresis_checksum CHECKSUM("hysteresis")
-#define t0_checksum CHECKSUM("t0")
-#define beta_checksum CHECKSUM("beta")
-#define vadc_checksum CHECKSUM("vadc")
-#define vcc_checksum CHECKSUM("vcc")
-#define r1_checksum CHECKSUM("r1")
-#define r2_checksum CHECKSUM("r2")
-#define thermistor_pin_checksum CHECKSUM("thermistor_pin")
#define heater_pin_checksum CHECKSUM("heater_pin")
#define get_m_code_checksum CHECKSUM("get_m_code")
void TemperatureControl::on_main_loop(void* argument){
if (this->min_temp_violated) {
- THEKERNEL->streams->printf("Error: MINTEMP triggered on P%d.%d! check your thermistors!\n", this->thermistor_pin.port_number, this->thermistor_pin.pin);
+ THEKERNEL->streams->printf("Error: MINTEMP triggered. Check your temperature sensors!\n");
this->min_temp_violated = false;
}
}
this->designator = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, designator_checksum)->by_default(string("T"))->as_string();
- // Values are here : http://reprap.org/wiki/Thermistor
- this->r0 = 100000;
- this->t0 = 25;
- this->beta = 4066;
- this->r1 = 0;
- this->r2 = 4700;
-
- // Preset values for various common types of thermistors
- ConfigValue* thermistor = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, thermistor_checksum);
- if( thermistor->as_string().compare("EPCOS100K" ) == 0 ){ // Default
- }else if( thermistor->as_string().compare("RRRF100K" ) == 0 ){ this->beta = 3960;
- }else if( thermistor->as_string().compare("RRRF10K" ) == 0 ){ this->beta = 3964; this->r0 = 10000; this->r1 = 680; this->r2 = 1600;
- }else if( thermistor->as_string().compare("Honeywell100K") == 0 ){ this->beta = 3974;
- }else if( thermistor->as_string().compare("Semitec" ) == 0 ){ this->beta = 4267;
- }else if( thermistor->as_string().compare("HT100K" ) == 0 ){ this->beta = 3990; }
-
- // Preset values are overriden by specified values
- this->r0 = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, r0_checksum )->by_default(this->r0 )->as_number(); // Stated resistance eg. 100K
- this->t0 = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, t0_checksum )->by_default(this->t0 )->as_number(); // Temperature at stated resistance, eg. 25C
- this->beta = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, beta_checksum)->by_default(this->beta)->as_number(); // Thermistor beta rating. See http://reprap.org/bin/view/Main/MeasuringThermistorBeta
- this->r1 = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, r1_checksum )->by_default(this->r1 )->as_number();
- this->r2 = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, r2_checksum )->by_default(this->r2 )->as_number();
-
+ // For backward compatibility, default to a thermistor sensor.
+ std::string sensor_type = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, sensor_checksum)->by_default("thermistor")->as_string();
+
+ // Instantiate correct sensor (TBD: TempSensor factory?)
+ if(sensor_type.compare("thermistor") == 0)
+ {
+ sensor.reset(new Thermistor());
+ }
+ else if(sensor_type.compare("max31855") == 0)
+ {
+ sensor.reset(new Max31855());
+ }
+
+ sensor->UpdateConfig(temperature_control_checksum, this->name_checksum);
+
this->preset1 = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, preset1_checksum)->by_default(0)->as_number();
this->preset2 = THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, preset2_checksum)->by_default(0)->as_number();
- // Thermistor math
- j = (1.0 / beta);
- k = (1.0 / (t0 + 273.15));
-
// sigma-delta output modulation
this->o = 0;
- // Thermistor pin for ADC readings
- this->thermistor_pin.from_string(THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, thermistor_pin_checksum )->required()->as_string());
- THEKERNEL->adc->enable_pin(&thermistor_pin);
-
// Heater pin
this->heater_pin.from_string( THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, heater_pin_checksum)->required()->as_string())->as_output();
this->heater_pin.max_pwm( THEKERNEL->config->value(temperature_control_checksum, this->name_checksum, max_pwm_checksum)->by_default(255)->as_number() );
return last_reading;
}
-float TemperatureControl::adc_value_to_temperature(int adc_value)
-{
- if ((adc_value == 4095) || (adc_value == 0))
- return INFINITY;
- float r = r2 / ((4095.0 / adc_value) - 1.0);
- if (r1 > 0)
- r = (r1 * r) / (r1 - r);
- return (1.0 / (k + (j * log(r / r0)))) - 273.15;
-}
-
uint32_t TemperatureControl::thermistor_read_tick(uint32_t dummy){
- int r = new_thermistor_reading();
-
- float temperature = adc_value_to_temperature(r);
+ float temperature = sensor->get_temperature();
if (target_temperature > 0)
{
- if ((r <= 1) || (r >= 4094))
+ if ((temperature <= 1) || (temperature >= 500))
{
this->min_temp_violated = true;
target_temperature = UNDEFINED;
this->lastInput= temperature;
}
-int TemperatureControl::new_thermistor_reading()
-{
- int last_raw = THEKERNEL->adc->read(&thermistor_pin);
- if (queue.size() >= queue.capacity()) {
- uint16_t l;
- queue.pop_front(l);
- }
- uint16_t r = last_raw;
- queue.push_back(r);
- for (int i=0; i<queue.size(); i++)
- median_buffer[i] = *queue.get_ref(i);
- uint16_t m = median_buffer[quick_median(median_buffer, queue.size())];
- return m;
-}
-
void TemperatureControl::on_second_tick(void* argument)
{
if (waiting)
#include "Module.h"
#include "Pwm.h"
-#include <math.h>
-
-#include "RingBuffer.h"
-
-#define QUEUE_LEN 8
+#include "TempSensor.h"
+#include <memory> // for auto_ptr
class TemperatureControlPool;
void on_set_public_data(void* argument);
void set_desired_temperature(float desired_temperature);
- float get_temperature();
- float adc_value_to_temperature(int adc_value);
- uint32_t thermistor_read_tick(uint32_t dummy);
- int new_thermistor_reading();
-
int pool_index;
TemperatureControlPool *pool;
friend class PID_Autotuner;
+ float get_temperature();
private:
+ uint32_t thermistor_read_tick(uint32_t dummy);
void pid_process(float);
float target_temperature;
float preset1;
float preset2;
- // Thermistor computation settings
- float r0;
- float t0;
- int r1;
- int r2;
- float beta;
- float j;
- float k;
-
-
+ std::auto_ptr<TempSensor> sensor;
+
// PID runtime
float i_max;
float acceleration_factor;
float readings_per_second;
- RingBuffer<uint16_t,QUEUE_LEN> queue; // Queue of readings
- uint16_t median_buffer[QUEUE_LEN];
- int running_total;
-
uint16_t name_checksum;
- Pin thermistor_pin;
Pwm heater_pin;
bool use_bangbang;
string designator;
-
void setPIDp(float p);
void setPIDi(float i);
void setPIDd(float d);
--- /dev/null
+/*
+ This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+ Smoothie 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.
+ Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libs/Kernel.h"
+#include <math.h>
+#include "libs/Pin.h"
+#include "Config.h"
+#include "checksumm.h"
+#include "Adc.h"
+#include "ConfigValue.h"
+#include "libs/Median.h"
+#include "Thermistor.h"
+
+#include "MRI_Hooks.h"
+
+#define UNDEFINED -1
+
+#define thermistor_checksum CHECKSUM("thermistor")
+#define r0_checksum CHECKSUM("r0")
+#define t0_checksum CHECKSUM("t0")
+#define beta_checksum CHECKSUM("beta")
+#define vadc_checksum CHECKSUM("vadc")
+#define vcc_checksum CHECKSUM("vcc")
+#define r1_checksum CHECKSUM("r1")
+#define r2_checksum CHECKSUM("r2")
+#define thermistor_pin_checksum CHECKSUM("thermistor_pin")
+
+Thermistor::Thermistor()
+{
+}
+
+Thermistor::~Thermistor()
+{
+}
+
+// Get configuration from the config file
+void Thermistor::UpdateConfig(uint16_t module_checksum, uint16_t name_checksum)
+{
+ // Values are here : http://reprap.org/wiki/Thermistor
+ this->r0 = 100000;
+ this->t0 = 25;
+ this->beta = 4066;
+ this->r1 = 0;
+ this->r2 = 4700;
+
+ // Preset values for various common types of thermistors
+ ConfigValue* thermistor = THEKERNEL->config->value(module_checksum, name_checksum, thermistor_checksum);
+ if( thermistor->as_string().compare("EPCOS100K" ) == 0 ){ // Default
+ }else if( thermistor->as_string().compare("RRRF100K" ) == 0 ){ this->beta = 3960;
+ }else if( thermistor->as_string().compare("RRRF10K" ) == 0 ){ this->beta = 3964; this->r0 = 10000; this->r1 = 680; this->r2 = 1600;
+ }else if( thermistor->as_string().compare("Honeywell100K") == 0 ){ this->beta = 3974;
+ }else if( thermistor->as_string().compare("Semitec" ) == 0 ){ this->beta = 4267;
+ }else if( thermistor->as_string().compare("HT100K" ) == 0 ){ this->beta = 3990; }
+
+ // Preset values are overriden by specified values
+ this->r0 = THEKERNEL->config->value(module_checksum, name_checksum, r0_checksum )->by_default(this->r0 )->as_number(); // Stated resistance eg. 100K
+ this->t0 = THEKERNEL->config->value(module_checksum, name_checksum, t0_checksum )->by_default(this->t0 )->as_number(); // Temperature at stated resistance, eg. 25C
+ this->beta = THEKERNEL->config->value(module_checksum, name_checksum, beta_checksum)->by_default(this->beta)->as_number(); // Thermistor beta rating. See http://reprap.org/bin/view/Main/MeasuringThermistorBeta
+ this->r1 = THEKERNEL->config->value(module_checksum, name_checksum, r1_checksum )->by_default(this->r1 )->as_number();
+ this->r2 = THEKERNEL->config->value(module_checksum, name_checksum, r2_checksum )->by_default(this->r2 )->as_number();
+
+ // Thermistor math
+ j = (1.0 / beta);
+ k = (1.0 / (t0 + 273.15));
+
+ // Thermistor pin for ADC readings
+ this->thermistor_pin.from_string(THEKERNEL->config->value(module_checksum, name_checksum, thermistor_pin_checksum )->required()->as_string());
+ THEKERNEL->adc->enable_pin(&thermistor_pin);
+}
+
+float Thermistor::get_temperature()
+{
+ return adc_value_to_temperature(new_thermistor_reading());
+}
+
+float Thermistor::adc_value_to_temperature(int adc_value)
+{
+ if ((adc_value == 4095) || (adc_value == 0))
+ return INFINITY;
+ float r = r2 / ((4095.0 / adc_value) - 1.0);
+ if (r1 > 0)
+ r = (r1 * r) / (r1 - r);
+ return (1.0 / (k + (j * log(r / r0)))) - 273.15;
+}
+
+int Thermistor::new_thermistor_reading()
+{
+ int last_raw = THEKERNEL->adc->read(&thermistor_pin);
+ if (queue.size() >= queue.capacity()) {
+ uint16_t l;
+ queue.pop_front(l);
+ }
+ uint16_t r = last_raw;
+ queue.push_back(r);
+ for (int i=0; i<queue.size(); i++)
+ median_buffer[i] = *queue.get_ref(i);
+ uint16_t m = median_buffer[quick_median(median_buffer, queue.size())];
+ return m;
+}
--- /dev/null
+/*
+ this file is part of smoothie (http://smoothieware.org/). the motion control part is heavily based on grbl (https://github.com/simen/grbl).
+ smoothie 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.
+ smoothie 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 smoothie. if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef thermistor_h
+#define thermistor_h
+
+#include "TempSensor.h"
+#include "RingBuffer.h"
+
+#define QUEUE_LEN 8
+
+
+class Thermistor : public TempSensor
+{
+ public:
+ Thermistor();
+ ~Thermistor();
+
+ // TempSensor interface.
+ void UpdateConfig(uint16_t module_checksum, uint16_t name_checksum);
+ float get_temperature();
+
+ private:
+ int new_thermistor_reading();
+ float adc_value_to_temperature(int adc_value);
+
+ // Thermistor computation settings
+ float r0;
+ float t0;
+ int r1;
+ int r2;
+ float beta;
+ float j;
+ float k;
+
+ Pin thermistor_pin;
+
+ RingBuffer<uint16_t,QUEUE_LEN> queue; // Queue of readings
+ uint16_t median_buffer[QUEUE_LEN];
+ int running_total;
+
+};
+
+#endif
--- /dev/null
+/*
+ This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+ Smoothie 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.
+ Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "libs/Kernel.h"
+#include <math.h>
+#include "libs/Pin.h"
+#include "Config.h"
+#include "checksumm.h"
+#include "ConfigValue.h"
+
+#include "max31855.h"
+
+#include "MRI_Hooks.h"
+
+#define chip_select_checksum CHECKSUM("chip_select")
+#define spi_channel_checksum CHECKSUM("spi_channel")
+
+Max31855::Max31855()
+{
+}
+
+Max31855::~Max31855()
+{
+}
+
+// Get configuration from the config file
+void Max31855::UpdateConfig(uint16_t module_checksum, uint16_t name_checksum)
+{
+ // Chip select
+ this->spi_cs_pin.from_string(THEKERNEL->config->value(module_checksum, name_checksum, chip_select_checksum)->by_default("nc")->as_string())->as_output();
+ this->spi_cs_pin.set(true);
+
+ // select which SPI channel to use
+ int spi_channel = THEKERNEL->config->value(module_checksum, name_checksum, spi_channel_checksum)->by_default(0)->as_number();
+ PinName miso;
+ PinName mosi;
+ PinName sclk;
+ if(spi_channel == 0) {
+ // Channel 0
+ mosi=P0_18; miso=P0_17; sclk=P0_15;
+ } else {
+ // Channel 1
+ mosi=P0_9; miso=P0_8; sclk=P0_7;
+ }
+
+ spi.reset(new SPI(mosi, miso, sclk));
+
+ this->spi->format(32);
+ this->spi->frequency(1000000);
+}
+
+float Max31855::get_temperature()
+{
+ this->spi_cs_pin.set(false);
+ wait_us(1); // Must wait for first bit valid
+
+ // Read 32 bits
+/* uint32_t data = spi->write(0);
+ data = data<<8;
+ data |= spi->write(0);
+ data = data<<8;
+ data |= spi->write(0);
+ data = data<<8;
+ data |= spi->write(0);
+*/
+ uint32_t data = uint32_t(spi->write(0));
+
+ this->spi_cs_pin.set(true);
+
+ float temperature;
+
+ //Process temp
+ if (data & 0x00010000)
+ temperature = 1000.f; //Some form of error.
+ else
+ {
+ data = data >> 18;
+ temperature = (data & 0x00001FFF) / 4.f;
+
+ if (data & 0x00002000)
+ {
+ data = ~data;
+ temperature = ((data & 0x00001FFF) + 1) / -4.f;
+ }
+ }
+ return temperature;
+}
\ No newline at end of file
--- /dev/null
+/*
+ this file is part of smoothie (http://smoothieware.org/). the motion control part is heavily based on grbl (https://github.com/simen/grbl).
+ smoothie 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.
+ smoothie 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 smoothie. if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef max31855_h
+#define max31855_h
+
+#include "TempSensor.h"
+#include <string>
+#include <libs/Pin.h>
+#include <mbed.h>
+#include <memory>
+
+class Max31855 : public TempSensor
+{
+public:
+ Max31855();
+ ~Max31855();
+ void UpdateConfig(uint16_t module_checksum, uint16_t name_checksum);
+ float get_temperature();
+
+private:
+ Pin spi_cs_pin;
+ std::auto_ptr<mbed::SPI> spi;
+};
+
+#endif