smoothie port to mbed online compiler (smoothieware.org)

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TemperatureControl.cpp Source File

TemperatureControl.cpp

00001 /*  
00002       This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
00003       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.
00004       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.
00005       You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. 
00006 */
00007 
00008 // TODO : THIS FILE IS LAME, MUST BE MADE MUCH BETTER
00009 
00010 #include "libs/Module.h"
00011 #include "libs/Kernel.h"
00012 #include <math.h>
00013 #include "TemperatureControl.h"
00014 #include "libs/Pin.h"
00015 
00016 TemperatureControl::TemperatureControl(){}
00017 
00018 TemperatureControl::TemperatureControl(uint16_t name){
00019     this->name_checksum = name;
00020     this->error_count = 0; 
00021 }
00022 
00023 void TemperatureControl::on_module_loaded(){
00024     
00025     // We start not desiring any temp
00026     this->desired_adc_value = UNDEFINED;
00027 
00028     // Settings
00029     this->on_config_reload(this);
00030 
00031     this->acceleration_factor = 10;
00032 
00033     this->kernel->slow_ticker->attach( 20, this, &TemperatureControl::thermistor_read_tick );
00034 
00035     // Register for events
00036     this->register_for_event(ON_GCODE_EXECUTE); 
00037     this->register_for_event(ON_MAIN_LOOP); 
00038 
00039 }
00040 
00041 void TemperatureControl::on_main_loop(void* argument){ }
00042 
00043 // Get configuration from the config file
00044 void TemperatureControl::on_config_reload(void* argument){
00045 
00046     this->readings_per_second = this->kernel->config->value(temperature_control_checksum, this->name_checksum, readings_per_second_checksum)->by_default(5)->as_number();
00047 
00048     // Values are here : http://reprap.org/wiki/Thermistor
00049     this->r0   = 100000;
00050     this->t0   = 25;
00051     this->beta = 4066;
00052     this->vadc = 3.3;
00053     this->vcc  = 3.3;
00054     this->r1   = 0;
00055     this->r2   = 4700;
00056 
00057     // Preset values for various common types of thermistors
00058     ConfigValue* thermistor = this->kernel->config->value(temperature_control_checksum, this->name_checksum, thermistor_checksum);    
00059     if(       thermistor->value.compare("EPCOS100K"    ) == 0 ){ // Default
00060     }else if( thermistor->value.compare("RRRF100K"     ) == 0 ){ this->beta = 3960;
00061     }else if( thermistor->value.compare("RRRF10K"      ) == 0 ){ this->beta = 3964; this->r0 = 10000; this->r1 = 680; this->r2 = 1600;
00062     }else if( thermistor->value.compare("Honeywell100K") == 0 ){ this->beta = 3974;
00063     }else if( thermistor->value.compare("Semitec"      ) == 0 ){ this->beta = 4267; }
00064 
00065     // Preset values are overriden by specified values
00066     this->r0 =                  this->kernel->config->value(temperature_control_checksum, this->name_checksum, r0_checksum  )->by_default(100000)->as_number();               // Stated resistance eg. 100K
00067     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
00068     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
00069     this->vadc =                this->kernel->config->value(temperature_control_checksum, this->name_checksum, vadc_checksum)->by_default(3.3   )->as_number();               // ADC Reference
00070     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
00071     this->r1 =                  this->kernel->config->value(temperature_control_checksum, this->name_checksum, r1_checksum  )->by_default(0     )->as_number();
00072     this->r2 =                  this->kernel->config->value(temperature_control_checksum, this->name_checksum, r2_checksum  )->by_default(4700  )->as_number();
00073     
00074     // Thermistor math 
00075     this->k = this->r0 * exp( -this->beta / this->t0 );
00076     if( r1 > 0 ){ this->vs = r1 * this->vcc / ( r1 + r2 ); this->rs = r1 * r2 / ( r1 + r2 ); }else{ this->vs = this->vcc; this->rs = r2; } 
00077 
00078     // Thermistor pin for ADC readings
00079     this->thermistor_pin = this->kernel->config->value(temperature_control_checksum, this->name_checksum, thermistor_pin_checksum )->required()->as_pin();
00080     this->kernel->adc->enable_pin(this->thermistor_pin);
00081 
00082     // Heater pin
00083     this->heater_pin     =  this->kernel->config->value(temperature_control_checksum, this->name_checksum, heater_pin_checksum)->required()->as_pin()->as_output();
00084     this->heater_pin->set(0);
00085 
00086 }
00087 
00088 void TemperatureControl::on_gcode_execute(void* argument){
00089     Gcode* gcode = static_cast<Gcode*>(argument);
00090 
00091     // Set temperature without waiting
00092     if( gcode->has_letter('M') && gcode->get_value('M') == 104 && gcode->has_letter('S') ){
00093         this->set_desired_temperature(gcode->get_value('S')); 
00094     } 
00095 
00096     // Set temperature and wait
00097     if( gcode->has_letter('M') && gcode->get_value('M') == 109 && gcode->has_letter('S') ){
00098         this->set_desired_temperature(gcode->get_value('S'));
00099         
00100         // Pause 
00101         this->kernel->pauser->take(); 
00102         this->waiting = true; 
00103     
00104     } 
00105 
00106     // Get temperature
00107     if( gcode->has_letter('M') && gcode->get_value('M') == 105 ){
00108         gcode->stream->printf("get temperature: %f current:%f target:%f \r\n", this->get_temperature(), this->new_thermistor_reading(), this->desired_adc_value );
00109     } 
00110 }
00111 
00112 void TemperatureControl::set_desired_temperature(double desired_temperature){
00113     this->desired_adc_value = this->temperature_to_adc_value(desired_temperature);
00114 }
00115 
00116 double TemperatureControl::get_temperature(){
00117     double temp = this->new_thermistor_reading() ;
00118     return this->adc_value_to_temperature( this->new_thermistor_reading() );
00119 }
00120 
00121 double TemperatureControl::adc_value_to_temperature(double adc_value){
00122     double v = adc_value * this->vadc;            // Convert from 0-1 adc value to voltage
00123     double r = this->rs * v / ( this->vs - v );   // Resistance of thermistor
00124     return ( this->beta / log( r / this->k )) - 273.15;
00125 }
00126 
00127 double TemperatureControl::temperature_to_adc_value(double temperature){
00128     double r = this->r0 * exp( this->beta * ( 1 / (temperature + 273.15) -1 / this->t0 ) ); // Resistance of the thermistor 
00129     double v = this->vs * r / ( this->rs + r );                                             // Voltage at the potential divider
00130     return v / this->vadc * 1.00000;                                               // The ADC reading
00131 }
00132 
00133 uint32_t TemperatureControl::thermistor_read_tick(uint32_t dummy){
00134     if( this->desired_adc_value != UNDEFINED ){
00135         if( this->new_thermistor_reading() > this->desired_adc_value ){
00136             this->heater_pin->set(1); 
00137         }else{
00138             this->heater_pin->set(0); 
00139             if( this->waiting ){ 
00140                 this->kernel->pauser->release();
00141                 this->waiting = false; 
00142             }
00143         }
00144     }
00145 }
00146 
00147 double TemperatureControl::new_thermistor_reading(){
00148    
00149     double new_reading = double( double(this->kernel->adc->read(this->thermistor_pin) / double(1<<12) ) );
00150 
00151     if( this->queue.size() < 15 ){
00152         this->queue.push_back( new_reading );
00153         return new_reading;
00154     }else{
00155         double current_temp = this->average_adc_reading();
00156         double error = fabs(new_reading - current_temp); 
00157         if( error < 0.1 ){
00158             this->error_count = 0;
00159             double test;
00160             this->queue.pop_front(test); 
00161             this->queue.push_back( new_reading );
00162         }else{
00163             this->error_count++;
00164             if( this->error_count > 4 ){
00165                 double test;
00166                 this->queue.pop_front(test); 
00167             }
00168         } 
00169         return current_temp;
00170     }
00171 }
00172 
00173 
00174 double TemperatureControl::average_adc_reading(){
00175     double total;
00176     int j=0;
00177     int reading_index = this->queue.head;
00178     while( reading_index != this->queue.tail ){
00179         j++;
00180         total += this->queue.buffer[reading_index];
00181         reading_index = this->queue.next_block_index( reading_index );
00182     }
00183     return total / j;
00184 }
00185 
00186 
00187