2 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
3 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.
4 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.
5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
8 // TODO : THIS FILE IS LAME, MUST BE MADE MUCH BETTER
10 #include "libs/Module.h"
11 #include "libs/Kernel.h"
13 #include "TemperatureControl.h"
16 TemperatureControl::TemperatureControl(){}
18 TemperatureControl::TemperatureControl(uint16_t name
){
19 this->name_checksum
= name
;
20 this->error_count
= 0;
21 this->waiting
= false;
24 void TemperatureControl::on_module_loaded(){
26 // We start not desiring any temp
27 this->desired_adc_value
= UNDEFINED
;
30 this->on_config_reload(this);
32 this->acceleration_factor
= 10;
34 this->kernel
->slow_ticker
->attach( 20, this, &TemperatureControl::thermistor_read_tick
);
36 // Register for events
37 this->register_for_event(ON_GCODE_EXECUTE
);
38 this->register_for_event(ON_MAIN_LOOP
);
42 void TemperatureControl::on_main_loop(void* argument
){ }
44 // Get configuration from the config file
45 void TemperatureControl::on_config_reload(void* argument
){
48 this->set_m_code
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, set_m_code_checksum
)->by_default(104)->as_number();
49 this->set_and_wait_m_code
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, set_and_wait_m_code_checksum
)->by_default(109)->as_number();
50 this->get_m_code
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, get_m_code_checksum
)->by_default(105)->as_number();
51 this->readings_per_second
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, readings_per_second_checksum
)->by_default(5)->as_number();
53 // Values are here : http://reprap.org/wiki/Thermistor
62 // Preset values for various common types of thermistors
63 ConfigValue
* thermistor
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, thermistor_checksum
);
64 if( thermistor
->value
.compare("EPCOS100K" ) == 0 ){ // Default
65 }else if( thermistor
->value
.compare("RRRF100K" ) == 0 ){ this->beta
= 3960;
66 }else if( thermistor
->value
.compare("RRRF10K" ) == 0 ){ this->beta
= 3964; this->r0
= 10000; this->r1
= 680; this->r2
= 1600;
67 }else if( thermistor
->value
.compare("Honeywell100K") == 0 ){ this->beta
= 3974;
68 }else if( thermistor
->value
.compare("Semitec" ) == 0 ){ this->beta
= 4267; }
70 // Preset values are overriden by specified values
71 this->r0
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, r0_checksum
)->by_default(100000)->as_number(); // Stated resistance eg. 100K
72 this->t0
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, t0_checksum
)->by_default(25 )->as_number() + 273.15; // Temperature at stated resistance, eg. 25C
73 this->beta
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, beta_checksum
)->by_default(4066 )->as_number(); // Thermistor beta rating. See http://reprap.org/bin/view/Main/MeasuringThermistorBeta
74 this->vadc
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, vadc_checksum
)->by_default(3.3 )->as_number(); // ADC Reference
75 this->vcc
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, vcc_checksum
)->by_default(3.3 )->as_number(); // Supply voltage to potential divider
76 this->r1
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, r1_checksum
)->by_default(0 )->as_number();
77 this->r2
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, r2_checksum
)->by_default(4700 )->as_number();
80 this->k
= this->r0
* exp( -this->beta
/ this->t0
);
81 if( r1
> 0 ){ this->vs
= r1
* this->vcc
/ ( r1
+ r2
); this->rs
= r1
* r2
/ ( r1
+ r2
); }else{ this->vs
= this->vcc
; this->rs
= r2
; }
83 // Thermistor pin for ADC readings
84 this->thermistor_pin
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, thermistor_pin_checksum
)->required()->as_pin();
85 this->kernel
->adc
->enable_pin(this->thermistor_pin
);
88 this->heater_pin
= this->kernel
->config
->value(temperature_control_checksum
, this->name_checksum
, heater_pin_checksum
)->required()->as_pin()->as_output();
89 this->heater_pin
->set(0);
93 void TemperatureControl::on_gcode_execute(void* argument
){
94 Gcode
* gcode
= static_cast<Gcode
*>(argument
);
97 //gcode->stream->printf("%u %u %u \r\n",gcode->has_letter('M'), (gcode->get_value('M') == 104), gcode->has_letter('S') );
99 // Set temperature without waiting
100 if( gcode
->has_letter('M') && gcode
->get_value('M') == this->set_m_code
&& gcode
->has_letter('S') ){
101 //gcode->stream->printf("setting to %f meaning %u \r\n", gcode->get_value('S'), this->temperature_to_adc_value( gcode->get_value('S') ) );
102 this->set_desired_temperature(gcode
->get_value('S'));
105 // Set temperature and wait
106 if( gcode
->has_letter('M') && gcode
->get_value('M') == this->set_and_wait_m_code
&& gcode
->has_letter('S') ){
107 this->set_desired_temperature(gcode
->get_value('S'));
110 this->kernel
->pauser
->take();
111 this->waiting
= true;
116 if( gcode
->has_letter('M') && gcode
->get_value('M') == this->get_m_code
){
117 gcode
->stream
->printf("get temperature: %f current:%f target:%f bare_value:%u \r\n", this->get_temperature(), this->new_thermistor_reading(), this->desired_adc_value
, this->kernel
->adc
->read(this->thermistor_pin
) );
121 void TemperatureControl::set_desired_temperature(double desired_temperature
){
122 this->desired_adc_value
= this->temperature_to_adc_value(desired_temperature
);
125 double TemperatureControl::get_temperature(){
126 double temp
= this->new_thermistor_reading() ;
127 return this->adc_value_to_temperature( this->new_thermistor_reading() );
130 double TemperatureControl::adc_value_to_temperature(double adc_value
){
131 double v
= adc_value
* this->vadc
; // Convert from 0-1 adc value to voltage
132 double r
= this->rs
* v
/ ( this->vs
- v
); // Resistance of thermistor
133 return ( this->beta
/ log( r
/ this->k
)) - 273.15;
136 double TemperatureControl::temperature_to_adc_value(double temperature
){
137 double r
= this->r0
* exp( this->beta
* ( 1 / (temperature
+ 273.15) -1 / this->t0
) ); // Resistance of the thermistor
138 double v
= this->vs
* r
/ ( this->rs
+ r
); // Voltage at the potential divider
139 return v
/ this->vadc
* 1.00000; // The ADC reading
142 uint32_t TemperatureControl::thermistor_read_tick(uint32_t dummy
){
143 if( this->desired_adc_value
!= UNDEFINED
){
144 if( this->new_thermistor_reading() > this->desired_adc_value
){
145 this->heater_pin
->set(1);
147 this->heater_pin
->set(0);
149 this->kernel
->pauser
->release();
150 this->waiting
= false;
156 double TemperatureControl::new_thermistor_reading(){
158 double new_reading
= double( double(this->kernel
->adc
->read(this->thermistor_pin
) / double(1<<12) ) );
160 if( this->queue
.size() < 15 ){
161 this->queue
.push_back( new_reading
);
164 double current_temp
= this->average_adc_reading();
165 double error
= fabs(new_reading
- current_temp
);
167 this->error_count
= 0;
169 this->queue
.pop_front(test
);
170 this->queue
.push_back( new_reading
);
173 if( this->error_count
> 4 ){
175 this->queue
.pop_front(test
);
183 double TemperatureControl::average_adc_reading(){
186 int reading_index
= this->queue
.head
;
187 while( reading_index
!= this->queue
.tail
){
189 total
+= this->queue
.buffer
[reading_index
];
190 reading_index
= this->queue
.next_block_index( reading_index
);