Soil Measurements for pH and moisture

Dependencies:   AD7124

Dependents:   cn0398-helloworld

Fork of CN0398 by Analog Devices

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CN0398.cpp Source File

CN0398.cpp

00001 #include "CN0398.h"
00002 #include "AD7124.h"
00003 #include <mbed.h>
00004 
00005 #define RREF (5000.0)
00006 #define TEMP_GAIN (16.0)
00007 #define PT100_RESISTANCE_TO_TEMP(x) ((x-100.0)/(0.385))
00008 #define _2_23 (1<<23)
00009 
00010 #define CALIBRATION_NR_OF_SAMPLES (5)
00011 
00012 extern Serial pc;
00013 
00014 #define ms_delay (1)
00015 
00016 CN0398::CN0398(PinName cs, PinName adp7118enable) : ad7124(cs), ADP7118Enable(adp7118enable), offset_voltage(default_offset_voltage)
00017 {
00018     use_nernst = false;
00019     calibration_ph[0][0] = 4;//default_calibration_ph[0][0];
00020     calibration_ph[0][1] = 0.169534;//default_calibration_ph[0][1];
00021     calibration_ph[1][0] = 10;//default_calibration_ph[1][0];
00022     calibration_ph[1][1] = -0.134135;//default_calibration_ph[1][1];
00023     solution0 = 0;
00024     solution1 = 0;
00025 }
00026 
00027 void CN0398::calibrate_ph_pt0(float temperature)
00028 {
00029     float volt = 0;
00030     for(int i = 0; i < CALIBRATION_NR_OF_SAMPLES; i++) {
00031         set_digital_output(P2, true);
00032         int32_t data = read_channel(0);
00033         set_digital_output(P2, false);
00034         volt += data_to_voltage_bipolar(data >> 8, 1, 3.3);
00035     }
00036     volt = volt / CALIBRATION_NR_OF_SAMPLES;
00037     if(temperature < 0) {
00038         calibration_ph[0][0] = ph_temp_lut[solution0][0];
00039     } else {
00040         for(uint8_t i = 1; i < NUMBER_OF_TEMPERATURE_ENTRIES; i++) {
00041             if(temperature > ph_temperatures[i - 1] && temperature <= ph_temperatures[i]) {
00042                 calibration_ph[0][0] = ph_temp_lut[solution0][i];
00043                 break;
00044             }
00045         }
00046     }
00047     calibration_ph[0][1] = volt;
00048     pc.printf("Calibration solution 1 ph: %f with sensor voltage of %f\r\n", calibration_ph[0][0], volt);
00049 }
00050 void CN0398::calibrate_ph_pt1(float temperature)
00051 {
00052     float volt = 0;
00053     for(int i = 0; i < CALIBRATION_NR_OF_SAMPLES; i++) {
00054         set_digital_output(P2, true);
00055         int32_t data = read_channel(0);
00056         set_digital_output(P2, false);
00057         volt += data_to_voltage_bipolar(data >> 8, 1, 3.3);
00058     }
00059 
00060     volt = volt / CALIBRATION_NR_OF_SAMPLES;
00061     if(temperature < 0) {
00062         calibration_ph[1][0] = ph_temp_lut[solution1][0];
00063     } else {
00064         for(uint8_t i = 1; i < NUMBER_OF_TEMPERATURE_ENTRIES; i++) {
00065             if(temperature > ph_temperatures[i - 1] && temperature <= ph_temperatures[i]) {
00066                 calibration_ph[1][0] = ph_temp_lut[solution1][i];
00067                 break;
00068             }
00069         }
00070     }
00071     calibration_ph[1][1] = volt;
00072     pc.printf("Calibration solution 2 ph: %f with sensor voltage of %f\r\n", calibration_ph[1][0], volt);
00073 }
00074 
00075 void CN0398::calibrate_ph_offset()
00076 {
00077     float volt = 0;
00078     for(int i = 0; i < CALIBRATION_NR_OF_SAMPLES; i++) {
00079         set_digital_output(P2, true);
00080         int32_t data = read_channel(0);
00081         set_digital_output(P2, false);
00082         volt += data_to_voltage_bipolar(data >> 8, 1, 3.3);
00083     }
00084     offset_voltage = volt / CALIBRATION_NR_OF_SAMPLES;
00085     pc.printf("Offset voltage is: %f \r\n", volt);
00086 }
00087 
00088 
00089 float CN0398::read_rtd()
00090 {
00091     float temperature = 25.0;
00092 #ifdef TEMPERATURE_SENSOR_PRESENT
00093     int32_t data = read_channel(2);
00094     data = (data >> 8) & 0x00ffffff;
00095     float resistance = ((static_cast<float>(data) - _2_23) * RREF) / (TEMP_GAIN * _2_23);
00096 #ifdef USE_LINEAR_TEMP_EQ
00097     temperature = PT100_RESISTANCE_TO_TEMP(resistance);
00098 #else
00099 
00100 #define A (3.9083*pow(10.0,-3.0))
00101 #define B (-5.775*pow(10.0,-7.0))
00102     /*if(resistance < 100.0)
00103         temperature = -242.02 + 2.228 * resistance + (2.5859 * pow(10, -3)) * pow(resistance, 2) - (48260 * pow(10, -6)) * pow(resistance, 3) - (2.8183 * pow(10, -3)) * pow(resistance, 4) + (1.5243 * pow(10, -10)) * pow(resistance, 5);
00104     else*/
00105     temperature = ((-A + sqrt(double(pow(A, 2.0) - 4 * B * (1 - resistance / 100.0))) ) / (2 * B));
00106 #endif
00107 #endif
00108     return temperature;
00109 
00110 }
00111 
00112 int32_t CN0398::read_channel(uint8_t ch)
00113 {
00114     int32_t data;
00115     enable_channel(ch);
00116     start_single_conversion();
00117 
00118     if (ad7124.WaitForConvReady(10000) == -3) {
00119         pc.printf("TIMEOUT");
00120         return -1;
00121     }
00122     ad7124.ReadData(&data);
00123     disable_channel(ch);
00124     return data;
00125 
00126 }
00127 float CN0398::read_ph(float temperature)
00128 {
00129     float ph = 0;
00130 #ifdef PH_SENSOR_PRESENT
00131     set_digital_output(P2, true);
00132     int32_t data = read_channel(0);
00133     set_digital_output(P2, false);
00134     float volt = data_to_voltage_bipolar(data >> 8, 1, 3.3);
00135 #ifdef DEBUG_MODE
00136     pc.printf("pH sensor voltage - %f\n", volt);
00137 #endif
00138 
00139     if(use_nernst) {
00140         ph  = -((volt - ZERO_POINT_TOLERANCE) / ((2.303 * AVOGADRO * (temperature + KELVIN_OFFSET)) / FARADAY_CONSTANT) ) + PH_ISO;
00141     } else {
00142         float m =  (calibration_ph[1][0] - calibration_ph[0][0]) / (calibration_ph[1][1] - calibration_ph[0][1]);
00143         ph = m * (volt - calibration_ph[1][1] + offset_voltage) + calibration_ph[1][0];
00144     }
00145 #endif
00146     return ph;
00147 }
00148 float CN0398::read_moist()
00149 {
00150     float moisture = 0;
00151 #ifdef MOISTURE_SENSOR_PRESENT
00152     ADP7118Enable = true;
00153     set_digital_output(P3, true);
00154     wait_ms(SENSOR_SETTLING_TIME);
00155     int32_t data = read_channel(1);
00156     ADP7118Enable = false;
00157     set_digital_output(P3, false);
00158 
00159     data = (data >> 8) & 0x00ffffff;
00160     float volt = data_to_voltage(data, 1, 3.3);
00161 #ifdef USE_MANUFACTURER_MOISTURE_EQ
00162     if(volt <= 1.1) {
00163         moisture = 10 * volt - 1;
00164     } else if(volt > 1.1 && volt <= 1.3) {
00165         moisture = 25 * volt - 17.5;
00166     } else if(volt > 1.3 && volt <= 1.82) {
00167         moisture = 48.08 * volt - 47.5;
00168     } else if(volt > 1.82) {
00169         moisture = 26.32 * volt - 7.89;
00170     }
00171 #else
00172     moisture = -1.18467 + 21.5371 * volt - 110.996 * (pow(volt, 2)) + 397.025 * (pow(volt, 3)) - 666.986 * (pow(volt, 4)) + 569.236 * (pow(volt, 5)) - 246.005 * (pow(volt, 6)) + 49.4867 * (pow(volt, 7)) - 3.37077 * (pow(volt, 8));
00173 #endif
00174     if(moisture > 100) moisture = 100;
00175     if(moisture < 0 ) moisture = 0;
00176 #endif
00177     return moisture;
00178 }
00179 
00180 float CN0398::data_to_voltage_bipolar(uint32_t data, uint8_t gain, float VREF)
00181 {
00182     data = data & 0xFFFFFF;
00183     return ((data / static_cast<float>(0xFFFFFF / 2)) - 1) * (VREF / gain);
00184 }
00185 
00186 float CN0398::data_to_voltage(uint32_t data, uint8_t gain, float VREF)
00187 {
00188     data = data & 0xFFFFFF;
00189     return (data / static_cast<float>(0xFFFFFF)) * (VREF / gain);
00190 }
00191 
00192 void CN0398::enable_channel(int channel)
00193 {
00194     AD7124::ad7124_registers regNr = static_cast<AD7124::ad7124_registers> (AD7124::AD7124_Channel_0 + channel); //Select ADC_Control register
00195     uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
00196     setValue |= (uint32_t) AD7124_CH_MAP_REG_CH_ENABLE;  //Enable channel0
00197     setValue &= 0xFFFF;
00198     ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
00199     wait_ms(ms_delay);
00200 }
00201 
00202 void CN0398::disable_channel(int channel)
00203 {
00204     AD7124::ad7124_registers regNr = static_cast<AD7124::ad7124_registers> (AD7124::AD7124_Channel_0 + channel); //Select ADC_Control register
00205     uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
00206     setValue &= (~(uint32_t) AD7124_CH_MAP_REG_CH_ENABLE);  //Enable channel0
00207     setValue &= 0xFFFF;
00208     ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
00209     wait_ms(ms_delay);
00210 }
00211 
00212 /*
00213 void CN0398::enable_current_source0(int current_source_channel)
00214 {
00215     AD7124::ad7124_registers regNr = AD7124::AD7124_IOCon1; //Select ADC_Control register
00216     uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
00217     setValue &= ~(AD7124_IO_CTRL1_REG_IOUT_CH0(0xF));
00218     setValue |= AD7124_IO_CTRL1_REG_IOUT_CH0(current_source_channel);// set IOUT0 current to 500uA
00219     setValue &= 0xFFFFFF;
00220     ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
00221     wait_ms(ms_delay);
00222 }
00223 
00224 void CN0398::enable_current_source1(int current_source_channel)
00225 {
00226     AD7124::ad7124_registers regNr = AD7124::AD7124_IOCon1; //Select ADC_Control register
00227     uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
00228     setValue &= ~(AD7124_IO_CTRL1_REG_IOUT_CH1(0xF));
00229     setValue |= AD7124_IO_CTRL1_REG_IOUT_CH1(current_source_channel);// set IOUT0 current to 500uA
00230     setValue &= 0xFFFFFF;
00231     ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
00232     wait_ms(ms_delay);
00233 }*/
00234 
00235 void CN0398::set_digital_output(ad_digital_output_t p, bool state)
00236 {
00237     AD7124::ad7124_registers regNr = AD7124::AD7124_IOCon1; //Select ADC_Control register
00238     uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
00239     if(state)
00240         setValue |= ((AD7124_8_IO_CTRL1_REG_GPIO_DAT1) << p);
00241     else
00242         setValue &= (~((AD7124_8_IO_CTRL1_REG_GPIO_DAT1) << p));
00243     ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
00244     wait_ms(ms_delay);
00245 }
00246 
00247 
00248 void CN0398::start_single_conversion()
00249 {
00250     AD7124::ad7124_registers regNr = AD7124::AD7124_ADC_Control; //Select ADC_Control register
00251     uint32_t setValue = ad7124.ReadDeviceRegister(regNr);
00252     setValue &= 0xFFC3;
00253     setValue |= 0x04;               //single conversion;
00254     setValue |= AD7124_ADC_CTRL_REG_DATA_STATUS;
00255     setValue &= 0xFFFF;
00256     ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC*/
00257     wait_ms(ms_delay * 10);
00258 }
00259 
00260 void CN0398::reset()
00261 {
00262     ad7124.frequency(500000);
00263     ad7124.Reset();
00264     pc.printf("Reseted AD7124\r\n");
00265     wait_ms(1000);
00266 }
00267 
00268 void CN0398::setup()
00269 {
00270     ad7124.Setup();
00271 }
00272 
00273 void CN0398::init()
00274 {
00275     uint32_t setValue;
00276     enum AD7124::ad7124_registers regNr;
00277 
00278     /* Set Config_0 0x19*/
00279     regNr = AD7124::AD7124_Config_0;               //Select Config_0 register - pH
00280     setValue = 0;//ad7124.ReadDeviceRegister(regNr);
00281     setValue |= AD7124_CFG_REG_BIPOLAR;     //Select bipolar operation
00282     setValue |= AD7124_CFG_REG_BURNOUT(0);  //Burnout current source off
00283     setValue |= AD7124_CFG_REG_REF_BUFP;
00284     setValue |= AD7124_CFG_REG_REF_BUFM;
00285     setValue |= AD7124_CFG_REG_AIN_BUFP;    //Buffer AIN5
00286     setValue |= AD7124_CFG_REG_AINN_BUFM;   //Buffer AIN4
00287     setValue |= AD7124_CFG_REG_REF_SEL(0); //REFIN1(+)/REFIN1(−).
00288     setValue |= AD7124_CFG_REG_PGA(0);
00289     setValue &= 0xFFFF;
00290     ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC
00291 
00292     /* Set Config_0 0x1A*/
00293     regNr = AD7124::AD7124_Config_1;               //Select Config_1 register - Moisture
00294     setValue = 0;//ad7124.ReadDeviceRegister(regNr);
00295     setValue &= ~AD7124_CFG_REG_BIPOLAR;     //Select bipolar operation
00296     setValue |= AD7124_CFG_REG_BURNOUT(0);  //Burnout current source off
00297     setValue |= AD7124_CFG_REG_REF_BUFP;
00298     setValue |= AD7124_CFG_REG_REF_BUFM;
00299     setValue |= AD7124_CFG_REG_AIN_BUFP;    //Buffer AIN5
00300     setValue |= AD7124_CFG_REG_AINN_BUFM;   //Buffer AIN4*/
00301     setValue |= AD7124_CFG_REG_REF_SEL(0); // REFIN1(+)/REFIN1(−).
00302     setValue |= AD7124_CFG_REG_PGA(0);
00303     setValue &= 0xFFFF;
00304     ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC
00305 
00306     /* Set Config_0 0x1B*/
00307     regNr = AD7124::AD7124_Config_2;               //Select Config_2 register - temp
00308     setValue = 0;//ad7124.ReadDeviceRegister(regNr);
00309     setValue |= AD7124_CFG_REG_BIPOLAR;     //Select bipolar operation
00310     setValue |= AD7124_CFG_REG_BURNOUT(0);  //Burnout current source off
00311     setValue |= AD7124_CFG_REG_REF_BUFP;
00312     setValue |= AD7124_CFG_REG_REF_BUFM;
00313     setValue |= AD7124_CFG_REG_AIN_BUFP;    //Buffer AIN5
00314     setValue |= AD7124_CFG_REG_AINN_BUFM;   //Buffer AIN4
00315     setValue |= AD7124_CFG_REG_REF_SEL(1); //REFIN2(+)/REFIN2(-).
00316     setValue |= AD7124_CFG_REG_PGA(4); // gain 16
00317     setValue &= 0xFFFF;
00318     ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC
00319 
00320     /* Set Channel_0 register 0x09*/
00321     regNr = AD7124::AD7124_Channel_0;  // pH reading
00322     setValue = 0;
00323     setValue |= AD7124_CH_MAP_REG_SETUP(0);             // Select setup0
00324     setValue |= AD7124_CH_MAP_REG_AINP(6);         // Set AIN4 as positive input
00325     setValue |= AD7124_CH_MAP_REG_AINM(7);         // Set AIN5 as negative input
00326     setValue &= 0xFFFF;
00327     ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC
00328 
00329     regNr = AD7124::AD7124_Channel_1; // Moisture
00330     setValue = 0;
00331     setValue |= AD7124_CH_MAP_REG_SETUP(1);             // Select setup0
00332     setValue |= AD7124_CH_MAP_REG_AINP(8);         // Set AIN4 as positive input
00333     setValue |= AD7124_CH_MAP_REG_AINM(19);         // Set AIN5 as negative input
00334     setValue &= 0xFFFF;
00335     ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC
00336 
00337     regNr = AD7124::AD7124_Channel_2; // RTD - gain 16
00338     setValue = 0;
00339     setValue |= AD7124_CH_MAP_REG_SETUP(2);             // Select setup0
00340     setValue |= AD7124_CH_MAP_REG_AINP(9);         // Set AIN4 as positive input
00341     setValue |= AD7124_CH_MAP_REG_AINM(10);         // Set AIN5 as negative input
00342     setValue &= 0xFFFF;
00343     ad7124.WriteDeviceRegister(regNr, setValue);   // Write data to ADC
00344 
00345     /* Set IO_Control_1 0x03 */
00346     regNr = AD7124::AD7124_IOCon1;               //Select IO_Control_1 register
00347     //setValue = ad7124.ReadDeviceRegister(regNr);
00348     setValue = 0;
00349     setValue |= AD7124_8_IO_CTRL1_REG_GPIO_CTRL2; // enable AIN3 as digital output
00350     setValue |= AD7124_8_IO_CTRL1_REG_GPIO_CTRL3; // enable AIN4 as digital output
00351     setValue |= AD7124_IO_CTRL1_REG_IOUT_CH0(11); // source ain11
00352     setValue |= AD7124_IO_CTRL1_REG_IOUT_CH1(12); // source ain12
00353     setValue |= AD7124_IO_CTRL1_REG_IOUT0(0x4);// set IOUT0 current to 500uA
00354     setValue |= AD7124_IO_CTRL1_REG_IOUT1(0x4);// set IOUT0 current to 500uA*/
00355     setValue &= 0xFFFFFF;
00356     ad7124.WriteDeviceRegister(regNr, setValue);// Write data to ADC
00357 
00358     // Set IO_Control_2
00359     regNr = AD7124::AD7124_IOCon2;               //Select IO_Control_2 register
00360     setValue = 0;
00361     setValue |= AD7124_8_IO_CTRL2_REG_GPIO_VBIAS7; // enable AIN3 as digital output
00362     setValue &= 0xFFFFFF;
00363     ad7124.WriteDeviceRegister(regNr, setValue);// Write data to ADC
00364 
00365 
00366     /* Set ADC_Control 0x01 */
00367     regNr = AD7124::AD7124_ADC_Control;            //Select ADC_Control register
00368     setValue = ad7124.ReadDeviceRegister(regNr);
00369     setValue |= AD7124_ADC_CTRL_REG_DATA_STATUS; // set data status bit in order to check on which channel the conversion is
00370     setValue &= 0xFFC3; // remove prev mode bits
00371     setValue |= AD7124_ADC_CTRL_REG_MODE(2);
00372     setValue &= 0xFFFF;
00373     ad7124.WriteDeviceRegister(regNr, setValue);    // Write data to ADC
00374     wait_ms(ms_delay);
00375 }
00376 
00377 
00378 
00379 
00380