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

Dependencies:   AD5270 AD7798 ADT7310

Dependents:   cn0396-helloworld

For additional information check out the mbed page of the Analog Devices wiki: https://wiki.analog.com/resources/tools-software/mbed-drivers-all

Committer:
adisuciu
Date:
Tue Nov 08 09:51:15 2016 +0000
Revision:
2:8d2d32e76157
Parent:
1:024253f170c3
Fix for mbed online compiler (array initialization not allowed within class declaration)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
adisuciu 0:ef85449aa57f 1
adisuciu 0:ef85449aa57f 2 #include "AD5270.h"
adisuciu 0:ef85449aa57f 3 #include <math.h>
adisuciu 0:ef85449aa57f 4 #include "CN0396.h"
adisuciu 0:ef85449aa57f 5
adisuciu 0:ef85449aa57f 6 #define ADC_GAIN AD7798_GAIN_1
adisuciu 0:ef85449aa57f 7 #define ADC_SPS 0x05 //50SPS
adisuciu 0:ef85449aa57f 8
adisuciu 1:024253f170c3 9 #define CO_SENS (75 * pow(10.0, -9.0)) /* Sensitivity nA/ppm in 400ppm CO 50 to 100 */
adisuciu 0:ef85449aa57f 10 #define CO_RANGE 1000 /* Range ppm CO limit of performance warranty 1,000 */
adisuciu 1:024253f170c3 11 #define H2S_SENS (700 * pow(10.0, -9.0)) /* Sensitivity nA/ppm in 20ppm H2S 450 to 900 */
adisuciu 0:ef85449aa57f 12 #define H2S_RANGE 100 /* Range ppm H2S limit of performance warranty 100 */
adisuciu 0:ef85449aa57f 13
adisuciu 1:024253f170c3 14
adisuciu 1:024253f170c3 15 //CN0396::
adisuciu 1:024253f170c3 16
adisuciu 1:024253f170c3 17
adisuciu 0:ef85449aa57f 18 /* CO side H2S side
adisuciu 0:ef85449aa57f 19 Temperature Mean Mean*/
adisuciu 0:ef85449aa57f 20
adisuciu 0:ef85449aa57f 21 extern Serial pc;
adisuciu 0:ef85449aa57f 22
adisuciu 2:8d2d32e76157 23
adisuciu 2:8d2d32e76157 24 CN0396::ppm_compensation_t ppm_compensation_init[COMPENSATION_TABLE_SIZE] = {
adisuciu 1:024253f170c3 25 { -30 , 29.9 , 82.3 },
adisuciu 1:024253f170c3 26 { -20 , 38.8 , 84.6 },
adisuciu 1:024253f170c3 27 { -10 , 53.7 , 88.6 },
adisuciu 1:024253f170c3 28 {0 , 69.6 , 92.2 },
adisuciu 1:024253f170c3 29 {10 , 84.9 , 96.2 },
adisuciu 1:024253f170c3 30 {20 , 100.0 , 100.0},
adisuciu 1:024253f170c3 31 {30 , 112.7 , 103.1},
adisuciu 1:024253f170c3 32 {40 , 123.7 , 105.6},
adisuciu 1:024253f170c3 33 {50 , 133.1 , 107.4}
adisuciu 1:024253f170c3 34 };
adisuciu 2:8d2d32e76157 35 CN0396::CN0396(PinName csad, PinName csrdac, PinName cstemp) :
adisuciu 2:8d2d32e76157 36 csad(csad), csrdac(csrdac), cstemp(cstemp), ad(csad), rdac(csrdac), temp(cstemp)
adisuciu 2:8d2d32e76157 37 {
adisuciu 2:8d2d32e76157 38 memcpy(ppm_compensation,ppm_compensation_init,COMPENSATION_TABLE_SIZE*sizeof(ppm_compensation_t));
adisuciu 0:ef85449aa57f 39 }
adisuciu 0:ef85449aa57f 40
adisuciu 0:ef85449aa57f 41 void CN0396::data_to_voltage(uint16_t adcValue, float *voltage, int gain_adc)
adisuciu 0:ef85449aa57f 42 {
adisuciu 0:ef85449aa57f 43 *voltage = (float)(adcValue * V_REF) / (float)(_2_16 * gain_adc);
adisuciu 0:ef85449aa57f 44 }
adisuciu 0:ef85449aa57f 45
adisuciu 0:ef85449aa57f 46 void CN0396::data_to_voltage_bipolar(uint16_t adcValue, float *voltage, int gain_adc)
adisuciu 0:ef85449aa57f 47 {
adisuciu 0:ef85449aa57f 48 *voltage = ((static_cast<float>(adcValue) / _2_15) - 1.0) * (V_REF / static_cast<float>(gain_adc));
adisuciu 0:ef85449aa57f 49 }
adisuciu 0:ef85449aa57f 50
adisuciu 0:ef85449aa57f 51 float CN0396::get_feedback_resistor_value(float sensitivity, float range)
adisuciu 0:ef85449aa57f 52 {
adisuciu 0:ef85449aa57f 53 return 1.2 / (sensitivity * range);
adisuciu 0:ef85449aa57f 54 }
adisuciu 0:ef85449aa57f 55
adisuciu 0:ef85449aa57f 56 void CN0396::configure_feedback_resistors(float resistance1, float resistance2)
adisuciu 0:ef85449aa57f 57 {
adisuciu 0:ef85449aa57f 58 uint16_t R1 = rdac.calc_RDAC(resistance1);
adisuciu 0:ef85449aa57f 59 uint16_t R2 = rdac.calc_RDAC(resistance2);
adisuciu 0:ef85449aa57f 60
adisuciu 0:ef85449aa57f 61 csrdac = false;
adisuciu 0:ef85449aa57f 62 rdac.write_cmd(AD5270::WRITE_CTRL_REG, AD5270::RDAC_WRITE_PROTECT, false); // RDAC register write protect - allow update of wiper position through digital interface
adisuciu 0:ef85449aa57f 63 rdac.write_cmd(AD5270::WRITE_CTRL_REG, AD5270::RDAC_WRITE_PROTECT, false); // RDAC register write protect - allow update of wiper position through digital interface
adisuciu 0:ef85449aa57f 64 csrdac = true;
adisuciu 0:ef85449aa57f 65 wait_us(2);
adisuciu 0:ef85449aa57f 66 csrdac = false;
adisuciu 0:ef85449aa57f 67 rdac.write_cmd(AD5270::WRITE_RDAC, R2, false); // write data to the RDAC register
adisuciu 0:ef85449aa57f 68 rdac.write_cmd(AD5270::WRITE_RDAC, R1, false); // write data to the RDAC register
adisuciu 0:ef85449aa57f 69 csrdac = true;
adisuciu 0:ef85449aa57f 70 wait_us(2);
adisuciu 0:ef85449aa57f 71 csrdac = false;
adisuciu 0:ef85449aa57f 72 rdac.write_cmd(AD5270::WRITE_CTRL_REG, 0, false); // RDAC register write protect - allow update of wiper position through digital interface
adisuciu 0:ef85449aa57f 73 rdac.write_cmd(AD5270::WRITE_CTRL_REG, 0, false); // RDAC register write protect - allow update of wiper position through digital interface
adisuciu 0:ef85449aa57f 74 csrdac = false;
adisuciu 0:ef85449aa57f 75 wait_us(2);
adisuciu 0:ef85449aa57f 76 csrdac = false;
adisuciu 0:ef85449aa57f 77 rdac.write_reg(AD5270::HI_Z_Cmd, false);
adisuciu 0:ef85449aa57f 78 rdac.write_reg(AD5270::HI_Z_Cmd, false);
adisuciu 0:ef85449aa57f 79 csrdac = true;
adisuciu 0:ef85449aa57f 80 wait_us(2);
adisuciu 0:ef85449aa57f 81 csrdac = false;
adisuciu 0:ef85449aa57f 82 rdac.write_reg(AD5270::NO_OP_cmd, false);
adisuciu 0:ef85449aa57f 83 rdac.write_reg(AD5270::NO_OP_cmd, false);
adisuciu 0:ef85449aa57f 84 csrdac = true;
adisuciu 0:ef85449aa57f 85 }
adisuciu 0:ef85449aa57f 86
adisuciu 0:ef85449aa57f 87 void CN0396::init()
adisuciu 0:ef85449aa57f 88 {
adisuciu 0:ef85449aa57f 89 // set rdac
adisuciu 0:ef85449aa57f 90
adisuciu 0:ef85449aa57f 91 pc.printf("Computing resistor values \r\n");
adisuciu 0:ef85449aa57f 92
adisuciu 0:ef85449aa57f 93 resistance1 = get_feedback_resistor_value(CO_SENS, CO_RANGE );
adisuciu 0:ef85449aa57f 94 resistance0 = get_feedback_resistor_value(H2S_SENS, H2S_RANGE);
adisuciu 0:ef85449aa57f 95
adisuciu 0:ef85449aa57f 96 pc.printf("R1 = %f\r\nR2=%f\r\n", resistance0, resistance1);
adisuciu 0:ef85449aa57f 97 pc.printf("Configuring feedback resistors\r\n");
adisuciu 0:ef85449aa57f 98 configure_feedback_resistors(resistance1, resistance1);
adisuciu 0:ef85449aa57f 99 pc.printf("Done\r\n");
adisuciu 0:ef85449aa57f 100 // config temp
adisuciu 0:ef85449aa57f 101 pc.printf("Configuring temperature sensor\r\n");
adisuciu 0:ef85449aa57f 102 temp.reset();
adisuciu 0:ef85449aa57f 103 temp.write_config(0x90);
adisuciu 0:ef85449aa57f 104 pc.printf("Done\r\n");
adisuciu 0:ef85449aa57f 105
adisuciu 0:ef85449aa57f 106 pc.printf("Configuring ADC\r\n");
adisuciu 0:ef85449aa57f 107 ad.reset();
adisuciu 0:ef85449aa57f 108 if(ad.init()) {
adisuciu 0:ef85449aa57f 109 ad.set_coding_mode(AD7798_UNIPOLAR);
adisuciu 0:ef85449aa57f 110 ad.set_mode(AD7798_MODE_SINGLE);
adisuciu 0:ef85449aa57f 111 ad.set_gain(ADC_GAIN);
adisuciu 0:ef85449aa57f 112 ad.set_filter(ADC_SPS);
adisuciu 0:ef85449aa57f 113 ad.set_reference(AD7798_REFDET_ENA);
adisuciu 0:ef85449aa57f 114 pc.printf("ADC Config succesful\r\n");
adisuciu 0:ef85449aa57f 115 } else {
adisuciu 0:ef85449aa57f 116 pc.printf("ADC Config failed\r\n");
adisuciu 0:ef85449aa57f 117
adisuciu 0:ef85449aa57f 118 }
adisuciu 0:ef85449aa57f 119
adisuciu 0:ef85449aa57f 120
adisuciu 0:ef85449aa57f 121 }
adisuciu 0:ef85449aa57f 122
adisuciu 0:ef85449aa57f 123 float CN0396::compensate_ppm(float result, float temp, sensor_type_t sensor)
adisuciu 0:ef85449aa57f 124 {
adisuciu 0:ef85449aa57f 125 for(uint8_t i = 1; i < COMPENSATION_TABLE_SIZE; i++) {
adisuciu 0:ef85449aa57f 126 if(temp < ppm_compensation[i].temp && temp > ppm_compensation[i - 1].temp) {
adisuciu 0:ef85449aa57f 127 float compensation_coef;
adisuciu 0:ef85449aa57f 128 if(sensor == H2S_SENSOR) {
adisuciu 0:ef85449aa57f 129 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;
adisuciu 0:ef85449aa57f 130 } else {
adisuciu 0:ef85449aa57f 131 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;
adisuciu 0:ef85449aa57f 132 }
adisuciu 0:ef85449aa57f 133
adisuciu 0:ef85449aa57f 134 return (result * compensation_coef) / 100.0;
adisuciu 0:ef85449aa57f 135 }
adisuciu 0:ef85449aa57f 136 }
adisuciu 0:ef85449aa57f 137 }
adisuciu 0:ef85449aa57f 138 void CN0396::read()
adisuciu 0:ef85449aa57f 139 {
adisuciu 0:ef85449aa57f 140 uint16_t data0, data1;
adisuciu 0:ef85449aa57f 141 // read temperature
adisuciu 0:ef85449aa57f 142 uint16_t temp_data = temp.read_temp();
adisuciu 0:ef85449aa57f 143 float temp = 0;
adisuciu 0:ef85449aa57f 144
adisuciu 0:ef85449aa57f 145 if(temp_data & 0x8000) {
adisuciu 0:ef85449aa57f 146 temp = (temp_data - 65536) / (128.0);
adisuciu 0:ef85449aa57f 147 } else {
adisuciu 0:ef85449aa57f 148 temp = temp_data / (128.0);
adisuciu 0:ef85449aa57f 149 }
adisuciu 0:ef85449aa57f 150
adisuciu 0:ef85449aa57f 151 // read channels
adisuciu 0:ef85449aa57f 152 ad.set_channel(0);
adisuciu 0:ef85449aa57f 153 ad.read_data(0, &data0);
adisuciu 0:ef85449aa57f 154 float volt0;
adisuciu 0:ef85449aa57f 155 data_to_voltage(data0, &volt0);
adisuciu 0:ef85449aa57f 156 float result0 = (volt0 / resistance0) / CO_SENS;
adisuciu 0:ef85449aa57f 157 ad.set_channel(1);
adisuciu 0:ef85449aa57f 158 ad.read_data(1, &data1);
adisuciu 0:ef85449aa57f 159 float volt1;
adisuciu 0:ef85449aa57f 160 data_to_voltage(data1, &volt1);
adisuciu 0:ef85449aa57f 161 float result1 = (volt1 / resistance1) / H2S_SENS;
adisuciu 0:ef85449aa57f 162 // compute ppm based on formula
adisuciu 0:ef85449aa57f 163 // return ppm
adisuciu 0:ef85449aa57f 164 result0 = compensate_ppm(result0, temp, CO_SENSOR);
adisuciu 0:ef85449aa57f 165 result1 = compensate_ppm(result1, temp, H2S_SENSOR);
adisuciu 0:ef85449aa57f 166
adisuciu 0:ef85449aa57f 167 pc.printf("%f %f %f \r\n", temp, result0, result1);
adisuciu 0:ef85449aa57f 168 }