Commit | Line | Data |
---|---|---|
ded56b35 AW |
1 | #include "mbed.h" |
2 | #include "libs/Module.h" | |
3 | #include "libs/Kernel.h" | |
4 | #include <math.h> | |
5 | #include "TemperatureControl.h" | |
6 | ||
7 | TemperatureControl::TemperatureControl(){ | |
8 | this->error_count = 0; | |
9 | } | |
10 | ||
11 | void TemperatureControl::on_module_loaded(){ | |
12 | ||
13 | // We start now desiring any temp | |
14 | this->desired_adc_value = UNDEFINED; | |
15 | ||
16 | // Settings | |
7dd8133c | 17 | this->on_config_reload(this); |
ded56b35 AW |
18 | |
19 | this->acceleration_factor = 10; | |
20 | ||
21 | // Setup pins and timer | |
22 | this->thermistor_pin = new AnalogIn(p20); | |
d9ebc974 | 23 | this->kernel->slow_ticker->attach( 20, this, &TemperatureControl::thermistor_read_tick ); |
ded56b35 AW |
24 | this->heater_pwm = new PwmOut(p22); |
25 | this->heater_pwm->write(0); | |
26 | this->pwm_value = 0; | |
27 | ||
28 | // Register for events | |
29 | this->register_for_event(ON_GCODE_EXECUTE); | |
b6c86164 | 30 | this->register_for_event(ON_MAIN_LOOP); |
ded56b35 AW |
31 | |
32 | } | |
33 | ||
b6c86164 AW |
34 | void TemperatureControl::on_main_loop(void* argument){ |
35 | } | |
7dd8133c AW |
36 | |
37 | // Get configuration from the config file | |
38 | void TemperatureControl::on_config_reload(void* argument){ | |
39 | ||
40 | this->readings_per_second = this->kernel->config->value(readings_per_second_ckeckusm )->by_default(5 )->as_number(); | |
41 | ||
42 | // Values are here : http://reprap.org/wiki/Thermistor | |
43 | // TODO: WARNING : THIS WILL CHANGE and backward compatibility will be broken for config files that use this | |
a98f72da AW |
44 | this->r0 = 100000; |
45 | this->t0 = 25; | |
46 | this->beta = 4066; | |
47 | this->vadc = 3.3; | |
48 | this->vcc = 3.3; | |
49 | this->r1 = 0; | |
50 | this->r2 = 4700; | |
51 | ||
52 | ConfigValue* thermistor = this->kernel->config->value(temperature_control_thermistor_checksum); | |
53 | ||
54 | if( thermistor->value.compare("EPCOS100K") == 0 ){ | |
55 | // Already the default | |
56 | }else if( thermistor->value.compare("RRRF100K") == 0 ){ | |
57 | this->beta = 3960; | |
58 | }else if( thermistor->value.compare("RRRF10K") == 0 ){ | |
59 | this->beta = 3964; | |
60 | this->r0 = 10000; | |
61 | this->r1 = 680; | |
62 | this->r2 = 1600; | |
63 | }else if( thermistor->value.compare("Honeywell100K") == 0 ){ | |
64 | this->beta = 3974; | |
65 | }else if( thermistor->value.compare("Semitec") == 0 ){ | |
66 | this->beta = 4267; | |
67 | } | |
68 | ||
7dd8133c AW |
69 | this->r0 = this->kernel->config->value(temperature_control_r0_ckeckusm )->by_default(100000)->as_number(); // Stated resistance eg. 100K |
70 | this->t0 = this->kernel->config->value(temperature_control_t0_ckeckusm )->by_default(25 )->as_number() + 273.15; // Temperature at stated resistance, eg. 25C | |
71 | this->beta = this->kernel->config->value(temperature_control_beta_ckeckusm)->by_default(4066 )->as_number(); // Thermistor beta rating. See http://reprap.org/bin/view/Main/MeasuringThermistorBeta | |
72 | this->vadc = this->kernel->config->value(temperature_control_vadc_ckeckusm)->by_default(3.3 )->as_number(); // ADC Reference | |
73 | this->vcc = this->kernel->config->value(temperature_control_vcc_ckeckusm )->by_default(3.3 )->as_number(); // Supply voltage to potential divider | |
74 | this->r1 = this->kernel->config->value(temperature_control_r1_ckeckusm )->by_default(0 )->as_number(); | |
75 | this->r2 = this->kernel->config->value(temperature_control_r2_ckeckusm )->by_default(4700 )->as_number(); | |
76 | ||
77 | this->k = this->r0 * exp( -this->beta / this->t0 ); | |
78 | ||
79 | if( r1 > 0 ){ | |
80 | this->vs = r1 * this->vcc / ( r1 + r2 ); | |
81 | this->rs = r1 * r2 / ( r1 + r2 ); | |
82 | }else{ | |
83 | this->vs = this->vcc; | |
84 | this->rs = r2; | |
85 | } | |
86 | ||
87 | } | |
88 | ||
ded56b35 AW |
89 | void TemperatureControl::on_gcode_execute(void* argument){ |
90 | Gcode* gcode = static_cast<Gcode*>(argument); | |
91 | ||
92 | // Set temperature | |
93 | if( gcode->has_letter('M') && gcode->get_value('M') == 104 && gcode->has_letter('S') ){ | |
94 | this->set_desired_temperature(gcode->get_value('S')); | |
95 | } | |
96 | ||
97 | // Get temperature | |
98 | if( gcode->has_letter('M') && gcode->get_value('M') == 105 ){ | |
b6c86164 | 99 | this->kernel->serial->printf("get temperature: %f current:%f target:%f \r\n", this->get_temperature(), this->new_thermistor_reading(), this->desired_adc_value ); |
ded56b35 AW |
100 | } |
101 | } | |
102 | ||
103 | void TemperatureControl::set_desired_temperature(double desired_temperature){ | |
104 | this->desired_adc_value = this->temperature_to_adc_value(desired_temperature); | |
ded56b35 AW |
105 | } |
106 | ||
107 | double TemperatureControl::get_temperature(){ | |
108 | double temp = this->new_thermistor_reading() ; | |
109 | return this->adc_value_to_temperature( this->new_thermistor_reading() ); | |
110 | } | |
111 | ||
112 | double TemperatureControl::adc_value_to_temperature(double adc_value){ | |
113 | double v = adc_value * this->vadc; // Convert from 0-1 adc value to voltage | |
114 | double r = this->rs * v / ( this->vs - v ); // Resistance of thermistor | |
115 | return ( this->beta / log( r / this->k )) - 273.15; | |
116 | } | |
117 | ||
118 | double TemperatureControl::temperature_to_adc_value(double temperature){ | |
119 | double r = this->r0 * exp( this->beta * ( 1 / (temperature + 273.15) -1 / this->t0 ) ); // Resistance of the thermistor | |
120 | double v = this->vs * r / ( this->rs + r ); // Voltage at the potential divider | |
121 | return v / this->vadc * 1.00000; // The ADC reading | |
122 | } | |
123 | ||
124 | void TemperatureControl::thermistor_read_tick(){ | |
ded56b35 | 125 | if( this->desired_adc_value != UNDEFINED ){ |
b6c86164 AW |
126 | if( this->new_thermistor_reading() > this->desired_adc_value ){ |
127 | this->heater_pwm->write( 1 ); | |
ded56b35 | 128 | }else{ |
b6c86164 | 129 | this->heater_pwm->write( 0 ); |
ded56b35 AW |
130 | } |
131 | } | |
ded56b35 AW |
132 | } |
133 | ||
134 | double TemperatureControl::new_thermistor_reading(){ | |
135 | double new_reading = this->thermistor_pin->read(); | |
136 | ||
137 | if( this->queue.size() < 15 ){ | |
138 | this->queue.push_back( new_reading ); | |
139 | //this->kernel->serial->printf("first\r\n"); | |
140 | return new_reading; | |
141 | }else{ | |
142 | double current_temp = this->average_adc_reading(); | |
143 | double error = fabs(new_reading - current_temp); | |
144 | if( error < 0.1 ){ | |
145 | this->error_count = 0; | |
146 | double test; | |
147 | this->queue.pop_front(test); | |
148 | this->queue.push_back( new_reading ); | |
149 | }else{ | |
150 | this->error_count++; | |
151 | if( this->error_count > 4 ){ | |
152 | double test; | |
153 | this->queue.pop_front(test); | |
154 | } | |
155 | } | |
156 | return current_temp; | |
157 | } | |
158 | } | |
159 | ||
160 | ||
161 | double TemperatureControl::average_adc_reading(){ | |
162 | double total; | |
163 | int j=0; | |
164 | int reading_index = this->queue.head; | |
165 | while( reading_index != this->queue.tail ){ | |
166 | j++; | |
167 | total += this->queue.buffer[reading_index]; | |
168 | reading_index = this->queue.next_block_index( reading_index ); | |
169 | } | |
170 | return total / j; | |
171 | } | |
172 | ||
173 | ||
174 |