Commit | Line | Data |
---|---|---|
df27a6a3 | 1 | /* |
cd011f58 AW |
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. | |
df27a6a3 | 5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. |
cd011f58 AW |
6 | */ |
7 | ||
7b49793d | 8 | // TODO : THIS FILE IS LAME, MUST BE MADE MUCH BETTER |
cd011f58 | 9 | |
ded56b35 AW |
10 | #include "libs/Module.h" |
11 | #include "libs/Kernel.h" | |
12 | #include <math.h> | |
13 | #include "TemperatureControl.h" | |
3c132bd0 | 14 | #include "libs/Pin.h" |
ded56b35 | 15 | |
3c132bd0 AW |
16 | TemperatureControl::TemperatureControl(){} |
17 | ||
18 | TemperatureControl::TemperatureControl(uint16_t name){ | |
19 | this->name_checksum = name; | |
df27a6a3 | 20 | this->error_count = 0; |
4464301d | 21 | this->waiting = false; |
ded56b35 AW |
22 | } |
23 | ||
24 | void TemperatureControl::on_module_loaded(){ | |
25 | ||
81b547a1 | 26 | // We start not desiring any temp |
ded56b35 AW |
27 | this->desired_adc_value = UNDEFINED; |
28 | ||
29 | // Settings | |
7dd8133c | 30 | this->on_config_reload(this); |
ded56b35 AW |
31 | |
32 | this->acceleration_factor = 10; | |
33 | ||
d9ebc974 | 34 | this->kernel->slow_ticker->attach( 20, this, &TemperatureControl::thermistor_read_tick ); |
ded56b35 AW |
35 | |
36 | // Register for events | |
df27a6a3 MM |
37 | this->register_for_event(ON_GCODE_EXECUTE); |
38 | this->register_for_event(ON_MAIN_LOOP); | |
ded56b35 AW |
39 | |
40 | } | |
41 | ||
3c132bd0 | 42 | void TemperatureControl::on_main_loop(void* argument){ } |
7dd8133c AW |
43 | |
44 | // Get configuration from the config file | |
45 | void TemperatureControl::on_config_reload(void* argument){ | |
46 | ||
1306ba99 AW |
47 | // General config |
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(); | |
8c309ca9 | 51 | this->readings_per_second = this->kernel->config->value(temperature_control_checksum, this->name_checksum, readings_per_second_checksum)->by_default(5)->as_number(); |
7dd8133c AW |
52 | |
53 | // Values are here : http://reprap.org/wiki/Thermistor | |
423df6df AW |
54 | this->r0 = 100000; |
55 | this->t0 = 25; | |
a98f72da AW |
56 | this->beta = 4066; |
57 | this->vadc = 3.3; | |
423df6df AW |
58 | this->vcc = 3.3; |
59 | this->r1 = 0; | |
60 | this->r2 = 4700; | |
a98f72da | 61 | |
3c132bd0 | 62 | // Preset values for various common types of thermistors |
df27a6a3 | 63 | ConfigValue* thermistor = this->kernel->config->value(temperature_control_checksum, this->name_checksum, thermistor_checksum); |
423df6df AW |
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; } | |
a98f72da | 69 | |
3c132bd0 | 70 | // Preset values are overriden by specified values |
8c309ca9 L |
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(); | |
7dd8133c | 78 | |
df27a6a3 | 79 | // Thermistor math |
3c132bd0 | 80 | this->k = this->r0 * exp( -this->beta / this->t0 ); |
df27a6a3 | 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; } |
3c132bd0 AW |
82 | |
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); | |
86 | ||
87 | // Heater 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); | |
7dd8133c AW |
90 | |
91 | } | |
92 | ||
b2b0b56d AW |
93 | //#pragma GCC push_options |
94 | //#pragma GCC optimize ("O0") | |
db453125 AW |
95 | |
96 | ||
ded56b35 AW |
97 | void TemperatureControl::on_gcode_execute(void* argument){ |
98 | Gcode* gcode = static_cast<Gcode*>(argument); | |
e6b5ae25 AW |
99 | if( gcode->has_m){ |
100 | // Set temperature without waiting | |
101 | if( gcode->m == this->set_m_code && gcode->has_letter('S') ){ | |
102 | //gcode->stream->printf("setting to %f meaning %u \r\n", gcode->get_value('S'), this->temperature_to_adc_value( gcode->get_value('S') ) ); | |
df27a6a3 MM |
103 | this->set_desired_temperature(gcode->get_value('S')); |
104 | } | |
e6b5ae25 AW |
105 | // Set temperature and wait |
106 | if( gcode->m == this->set_and_wait_m_code && gcode->has_letter('S') ){ | |
107 | this->set_desired_temperature(gcode->get_value('S')); | |
df27a6a3 MM |
108 | // Pause |
109 | this->kernel->pauser->take(); | |
110 | this->waiting = true; | |
111 | } | |
e6b5ae25 AW |
112 | // Get temperature |
113 | if( gcode->m == this->get_m_code ){ | |
114 | 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) ); | |
115 | } | |
df27a6a3 | 116 | } |
ded56b35 AW |
117 | } |
118 | ||
b2b0b56d | 119 | //#pragma GCC pop_options |
db453125 AW |
120 | |
121 | ||
ded56b35 AW |
122 | void TemperatureControl::set_desired_temperature(double desired_temperature){ |
123 | this->desired_adc_value = this->temperature_to_adc_value(desired_temperature); | |
ded56b35 AW |
124 | } |
125 | ||
126 | double TemperatureControl::get_temperature(){ | |
ded56b35 AW |
127 | return this->adc_value_to_temperature( this->new_thermistor_reading() ); |
128 | } | |
129 | ||
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; | |
134 | } | |
135 | ||
136 | double TemperatureControl::temperature_to_adc_value(double temperature){ | |
df27a6a3 | 137 | double r = this->r0 * exp( this->beta * ( 1 / (temperature + 273.15) -1 / this->t0 ) ); // Resistance of the thermistor |
ded56b35 AW |
138 | double v = this->vs * r / ( this->rs + r ); // Voltage at the potential divider |
139 | return v / this->vadc * 1.00000; // The ADC reading | |
140 | } | |
141 | ||
8b8b3339 | 142 | uint32_t TemperatureControl::thermistor_read_tick(uint32_t dummy){ |
ded56b35 | 143 | if( this->desired_adc_value != UNDEFINED ){ |
b6c86164 | 144 | if( this->new_thermistor_reading() > this->desired_adc_value ){ |
df27a6a3 | 145 | this->heater_pin->set(1); |
ded56b35 | 146 | }else{ |
df27a6a3 MM |
147 | this->heater_pin->set(0); |
148 | if( this->waiting ){ | |
81b547a1 | 149 | this->kernel->pauser->release(); |
df27a6a3 | 150 | this->waiting = false; |
81b547a1 | 151 | } |
ded56b35 AW |
152 | } |
153 | } | |
281967e4 | 154 | return 0; |
ded56b35 AW |
155 | } |
156 | ||
157 | double TemperatureControl::new_thermistor_reading(){ | |
3c132bd0 AW |
158 | |
159 | double new_reading = double( double(this->kernel->adc->read(this->thermistor_pin) / double(1<<12) ) ); | |
ded56b35 AW |
160 | |
161 | if( this->queue.size() < 15 ){ | |
162 | this->queue.push_back( new_reading ); | |
ded56b35 AW |
163 | return new_reading; |
164 | }else{ | |
165 | double current_temp = this->average_adc_reading(); | |
df27a6a3 | 166 | double error = fabs(new_reading - current_temp); |
ded56b35 AW |
167 | if( error < 0.1 ){ |
168 | this->error_count = 0; | |
169 | double test; | |
df27a6a3 | 170 | this->queue.pop_front(test); |
ded56b35 AW |
171 | this->queue.push_back( new_reading ); |
172 | }else{ | |
173 | this->error_count++; | |
174 | if( this->error_count > 4 ){ | |
175 | double test; | |
df27a6a3 | 176 | this->queue.pop_front(test); |
ded56b35 | 177 | } |
df27a6a3 | 178 | } |
ded56b35 AW |
179 | return current_temp; |
180 | } | |
181 | } | |
182 | ||
183 | ||
184 | double TemperatureControl::average_adc_reading(){ | |
76bb4c37 BG |
185 | double total = 0; |
186 | int j = 0; | |
ded56b35 AW |
187 | int reading_index = this->queue.head; |
188 | while( reading_index != this->queue.tail ){ | |
189 | j++; | |
190 | total += this->queue.buffer[reading_index]; | |
191 | reading_index = this->queue.next_block_index( reading_index ); | |
192 | } | |
193 | return total / j; | |
194 | } | |
195 | ||
196 | ||
197 |