CN0396 (4-Wire Electrochemical Dual Toxic Gas Sensing System)

Dependencies:   AD5270 AD7798 ADT7310

Dependents:   cn0396-helloworld

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CN0396.cpp Source File

CN0396.cpp

00001 
00002 #include "AD5270.h"
00003 #include <math.h>
00004 #include "CN0396.h"
00005 
00006 #define ADC_GAIN      AD7798_GAIN_1
00007 #define ADC_SPS        0x05  //50SPS
00008 
00009 #define CO_SENS    (75 * pow(10.0, -9.0))    /* Sensitivity nA/ppm in 400ppm CO 50 to 100 */
00010 #define CO_RANGE   1000 /* Range ppm CO limit of performance warranty 1,000 */
00011 #define H2S_SENS   (700 * pow(10.0, -9.0)) /* Sensitivity nA/ppm in 20ppm H2S 450 to 900 */
00012 #define H2S_RANGE  100  /* Range ppm H2S limit of performance warranty 100 */
00013 
00014 
00015 //CN0396::
00016 
00017 
00018 /*  CO side H2S side
00019 Temperature Mean    Mean*/
00020 
00021 extern Serial pc;
00022 
00023 
00024 CN0396::ppm_compensation_t ppm_compensation_init[COMPENSATION_TABLE_SIZE]  = {
00025         { -30   , 29.9  , 82.3 },
00026         { -20   , 38.8  , 84.6 },
00027         { -10   , 53.7  , 88.6 },
00028         {0      , 69.6  , 92.2 },
00029         {10     , 84.9  , 96.2 },
00030         {20     , 100.0 , 100.0},
00031         {30     , 112.7 , 103.1},
00032         {40     , 123.7 , 105.6},
00033         {50     , 133.1 , 107.4}
00034     };
00035 CN0396::CN0396(PinName csad, PinName csrdac, PinName cstemp) :
00036     csad(csad), csrdac(csrdac), cstemp(cstemp), ad(csad), rdac(csrdac), temp(cstemp)
00037 {
00038 memcpy(ppm_compensation,ppm_compensation_init,COMPENSATION_TABLE_SIZE*sizeof(ppm_compensation_t));
00039 }
00040 
00041 void CN0396::data_to_voltage(uint16_t adcValue, float *voltage, int gain_adc)
00042 {
00043     *voltage = (float)(adcValue * V_REF) / (float)(_2_16 * gain_adc);
00044 }
00045 
00046 void CN0396::data_to_voltage_bipolar(uint16_t adcValue, float *voltage, int gain_adc)
00047 {
00048     *voltage = ((static_cast<float>(adcValue) / _2_15) - 1.0) * (V_REF / static_cast<float>(gain_adc));
00049 }
00050 
00051 float CN0396::get_feedback_resistor_value(float sensitivity, float range)
00052 {
00053     return 1.2 / (sensitivity * range);
00054 }
00055 
00056 void CN0396::configure_feedback_resistors(float resistance1, float resistance2)
00057 {
00058     uint16_t R1 = rdac.calc_RDAC(resistance1);
00059     uint16_t R2 = rdac.calc_RDAC(resistance2);
00060 
00061     csrdac = false;
00062     rdac.write_cmd(AD5270::WRITE_CTRL_REG,  AD5270::RDAC_WRITE_PROTECT, false); // RDAC register write protect -  allow update of wiper position through digital interface
00063     rdac.write_cmd(AD5270::WRITE_CTRL_REG,  AD5270::RDAC_WRITE_PROTECT, false); // RDAC register write protect -  allow update of wiper position through digital interface
00064     csrdac = true;
00065     wait_us(2);
00066     csrdac = false;
00067     rdac.write_cmd(AD5270::WRITE_RDAC, R2, false); // write data to the RDAC register
00068     rdac.write_cmd(AD5270::WRITE_RDAC, R1, false); // write data to the RDAC register
00069     csrdac = true;
00070     wait_us(2);
00071     csrdac = false;
00072     rdac.write_cmd(AD5270::WRITE_CTRL_REG, 0, false); // RDAC register write protect -  allow update of wiper position through digital interface
00073     rdac.write_cmd(AD5270::WRITE_CTRL_REG, 0, false); // RDAC register write protect -  allow update of wiper position through digital interface
00074     csrdac = false;
00075     wait_us(2);
00076     csrdac = false;
00077     rdac.write_reg(AD5270::HI_Z_Cmd, false);
00078     rdac.write_reg(AD5270::HI_Z_Cmd, false);
00079     csrdac = true;
00080     wait_us(2);
00081     csrdac = false;
00082     rdac.write_reg(AD5270::NO_OP_cmd, false);
00083     rdac.write_reg(AD5270::NO_OP_cmd, false);
00084     csrdac = true;
00085 }
00086 
00087 void CN0396::init()
00088 {
00089     // set rdac
00090 
00091     pc.printf("Computing resistor values \r\n");
00092 
00093     resistance1 = get_feedback_resistor_value(CO_SENS,  CO_RANGE );
00094     resistance0 = get_feedback_resistor_value(H2S_SENS, H2S_RANGE);
00095 
00096     pc.printf("R1 = %f\r\nR2=%f\r\n", resistance0, resistance1);
00097     pc.printf("Configuring feedback resistors\r\n");
00098     configure_feedback_resistors(resistance1, resistance1);
00099     pc.printf("Done\r\n");
00100     // config temp
00101     pc.printf("Configuring temperature sensor\r\n");
00102     temp.reset();
00103     temp.write_config(0x90);
00104     pc.printf("Done\r\n");
00105 
00106     pc.printf("Configuring ADC\r\n");
00107     ad.reset();
00108     if(ad.init()) {
00109         ad.set_coding_mode(AD7798_UNIPOLAR);
00110         ad.set_mode(AD7798_MODE_SINGLE);
00111         ad.set_gain(ADC_GAIN);
00112         ad.set_filter(ADC_SPS);
00113         ad.set_reference(AD7798_REFDET_ENA);
00114         pc.printf("ADC Config succesful\r\n");
00115     } else {
00116         pc.printf("ADC Config failed\r\n");
00117 
00118     }
00119 
00120 
00121 }
00122 
00123 float CN0396::compensate_ppm(float result, float temp, sensor_type_t sensor)
00124 {
00125     for(uint8_t i = 1; i < COMPENSATION_TABLE_SIZE; i++) {
00126         if(temp < ppm_compensation[i].temp && temp > ppm_compensation[i - 1].temp) {
00127             float compensation_coef;
00128             if(sensor == H2S_SENSOR) {
00129                 compensation_coef = (((temp - (ppm_compensation[i - 1].temp )) * (ppm_compensation[i].H2S_percent - ppm_compensation[i - 1].H2S_percent)) / (ppm_compensation[i].temp  - ppm_compensation[i - 1].temp)) + ppm_compensation[i - 1].H2S_percent;
00130             } else {
00131                 compensation_coef = (((temp - (ppm_compensation[i - 1].temp )) * (ppm_compensation[i].CO_percent - ppm_compensation[i - 1].CO_percent)) / (ppm_compensation[i].temp  - ppm_compensation[i - 1].temp)) + ppm_compensation[i - 1].CO_percent;
00132             }
00133 
00134             return (result * compensation_coef) / 100.0;
00135         }
00136     }
00137 }
00138 void CN0396::read()
00139 {
00140     uint16_t data0, data1;
00141     // read temperature
00142     uint16_t temp_data = temp.read_temp();
00143     float temp = 0;
00144 
00145     if(temp_data & 0x8000) {
00146         temp = (temp_data - 65536) / (128.0);
00147     } else {
00148         temp = temp_data / (128.0);
00149     }
00150 
00151     // read channels
00152     ad.set_channel(0);
00153     ad.read_data(0, &data0);
00154     float volt0;
00155     data_to_voltage(data0, &volt0);
00156     float result0 = (volt0 / resistance0) / CO_SENS;
00157     ad.set_channel(1);
00158     ad.read_data(1, &data1);
00159     float volt1;
00160     data_to_voltage(data1, &volt1);
00161     float result1 = (volt1 / resistance1) / H2S_SENS;
00162     // compute ppm based on formula
00163     // return ppm
00164     result0 = compensate_ppm(result0, temp, CO_SENSOR);
00165     result1 = compensate_ppm(result1, temp, H2S_SENSOR);
00166 
00167     pc.printf("%f %f %f \r\n", temp, result0, result1);
00168 }