in-file config of the TemperatureControl, and simple adjustments to make
[clinton/Smoothieware.git] / src / modules / tools / temperaturecontrol / TemperatureControl.cpp
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
17 this->on_config_reload(this);
18
19 this->acceleration_factor = 10;
20
21 // Setup pins and timer
22 this->thermistor_pin = new AnalogIn(p20);
23 this->kernel->slow_ticker->attach( this, &TemperatureControl::thermistor_read_tick );
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);
30
31 }
32
33
34 // Get configuration from the config file
35 void TemperatureControl::on_config_reload(void* argument){
36
37 this->readings_per_second = this->kernel->config->value(readings_per_second_ckeckusm )->by_default(5 )->as_number();
38
39 // Values are here : http://reprap.org/wiki/Thermistor
40 // TODO: WARNING : THIS WILL CHANGE and backward compatibility will be broken for config files that use this
41 this->r0 = this->kernel->config->value(temperature_control_r0_ckeckusm )->by_default(100000)->as_number(); // Stated resistance eg. 100K
42 this->t0 = this->kernel->config->value(temperature_control_t0_ckeckusm )->by_default(25 )->as_number() + 273.15; // Temperature at stated resistance, eg. 25C
43 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
44 this->vadc = this->kernel->config->value(temperature_control_vadc_ckeckusm)->by_default(3.3 )->as_number(); // ADC Reference
45 this->vcc = this->kernel->config->value(temperature_control_vcc_ckeckusm )->by_default(3.3 )->as_number(); // Supply voltage to potential divider
46 this->r1 = this->kernel->config->value(temperature_control_r1_ckeckusm )->by_default(0 )->as_number();
47 this->r2 = this->kernel->config->value(temperature_control_r2_ckeckusm )->by_default(4700 )->as_number();
48
49 this->k = this->r0 * exp( -this->beta / this->t0 );
50
51 if( r1 > 0 ){
52 this->vs = r1 * this->vcc / ( r1 + r2 );
53 this->rs = r1 * r2 / ( r1 + r2 );
54 }else{
55 this->vs = this->vcc;
56 this->rs = r2;
57 }
58
59 }
60
61 void TemperatureControl::on_gcode_execute(void* argument){
62 Gcode* gcode = static_cast<Gcode*>(argument);
63
64 // Set temperature
65 if( gcode->has_letter('M') && gcode->get_value('M') == 104 && gcode->has_letter('S') ){
66 this->set_desired_temperature(gcode->get_value('S'));
67 }
68
69 // Get temperature
70 if( gcode->has_letter('M') && gcode->get_value('M') == 105 ){
71 this->kernel->serial->printf("get temperature: %f \r\n", this->get_temperature() );
72 }
73 }
74
75 void TemperatureControl::set_desired_temperature(double desired_temperature){
76 this->desired_adc_value = this->temperature_to_adc_value(desired_temperature);
77 this->tail_adc_value = this->temperature_to_adc_value(desired_temperature-20);
78 this->head_adc_value = this->temperature_to_adc_value(desired_temperature+5);
79 }
80
81 double TemperatureControl::get_temperature(){
82 double temp = this->new_thermistor_reading() ;
83 return this->adc_value_to_temperature( this->new_thermistor_reading() );
84 }
85
86 double TemperatureControl::adc_value_to_temperature(double adc_value){
87 double v = adc_value * this->vadc; // Convert from 0-1 adc value to voltage
88 double r = this->rs * v / ( this->vs - v ); // Resistance of thermistor
89 return ( this->beta / log( r / this->k )) - 273.15;
90 }
91
92 double TemperatureControl::temperature_to_adc_value(double temperature){
93 double r = this->r0 * exp( this->beta * ( 1 / (temperature + 273.15) -1 / this->t0 ) ); // Resistance of the thermistor
94 double v = this->vs * r / ( this->rs + r ); // Voltage at the potential divider
95 return v / this->vadc * 1.00000; // The ADC reading
96 }
97
98 void TemperatureControl::thermistor_read_tick(){
99
100 double reading = this->new_thermistor_reading();
101 if( this->desired_adc_value != UNDEFINED ){
102 double difference = fabs( reading - this->desired_adc_value );
103 double adjustment = difference / acceleration_factor / this->readings_per_second;
104 if( reading > this->tail_adc_value ){
105 this->heater_pwm->write( 1 );
106 }else if( reading < this->head_adc_value ){
107 this->pwm_value -= adjustment;
108 this->heater_pwm->write( 0 );
109 }else{
110 if( reading > this->desired_adc_value ){
111 this->pwm_value += adjustment; // Heat up
112 }else{
113 this->pwm_value -= adjustment; // Heat down
114 }
115 this->pwm_value = max( double(0), min( double(1), pwm_value ) );
116 this->heater_pwm->write( pwm_value );
117 }
118 }
119
120 }
121
122 double TemperatureControl::new_thermistor_reading(){
123 double new_reading = this->thermistor_pin->read();
124
125 if( this->queue.size() < 15 ){
126 this->queue.push_back( new_reading );
127 //this->kernel->serial->printf("first\r\n");
128 return new_reading;
129 }else{
130 double current_temp = this->average_adc_reading();
131 double error = fabs(new_reading - current_temp);
132 if( error < 0.1 ){
133 this->error_count = 0;
134 double test;
135 this->queue.pop_front(test);
136 this->queue.push_back( new_reading );
137 }else{
138 this->error_count++;
139 if( this->error_count > 4 ){
140 double test;
141 this->queue.pop_front(test);
142 }
143 }
144 return current_temp;
145 }
146 }
147
148
149 double TemperatureControl::average_adc_reading(){
150 double total;
151 int j=0;
152 int reading_index = this->queue.head;
153 while( reading_index != this->queue.tail ){
154 j++;
155 total += this->queue.buffer[reading_index];
156 reading_index = this->queue.next_block_index( reading_index );
157 }
158 return total / j;
159 }
160
161
162