Driver Software
For calibrating and using the Conductivity Sensing Wildcard with various fluid conductivity probes and cells
The Conductivity Sensing Wildcard software driver makes it easy to calibrate and use different fluid conductivity probes or conductivity cells. The driver routines perform calibration at zero, mid-range and full-scale, measure the response of the Conductivity Sensing Wildcard when an attached probe is immersed in a solution, and calculate the conductivity of the solution.
All nonlinearities are accounted for in calculations highly optimized for execution speed, with a single conductivity measurement taking 8.2 ms on the Mosaic PDQ Board and 24 ms on Mosaic's Q-line controllers. EEPROM space is automatically allocated for persistent storage of calibration data for up to four conductivity probes (two Conductivity Sensing Wildcards), and additional EEPROM space may be allocated manually for any number of additional probes. The software provides an easy to use interface for calibrating conductivity probes, as well as a method to extract calibration data, making it easy to store factory calibration points or to transfer the conductivity probe to another instrument.
Overview of the driver functions
The software driver is organized as a set of functions, whose names all start with the prefix Cond_
which stands for conductivity. Functions are provide for initialization, calibration of probes, cells, and cables, and measurement. On the whole, the functions implement the calibration and computation calculations described in detail in Driver Software Equations.
Initializing the conductivity sensor functions
Cond_Init()
must be called before using any of the other functions except Cond_CheckEEData()
(and it is recommended to call Cond_CheckEEData()
first; see its glossary entry for more information). Cond_Init()
initializes an area of EEPROM to store the calibration data for four conductivity channels, numbered 0 through 3. On the first execution of Cond_Init()
on a controller, each of the four channels is initialized with default calibration data in preparation for calibration with actual conductivity probes. If stored calibration data is already present in EEPROM for a given channel, that stored calibration data is retained.
Conductivity probe calibration
The Cond_Cal_
functions are for calibrating a probe attached to one of the four channels, and the calibration data will be stored in EEPROM associated with that channel. For each of these functions, the channel number (0-3) is the first parameter, and the second parameter is an associated known floating point value. For Cond_Cal_Tare()
this known value parameter will always be 1.0, the value of the onboard reference resistor in KOhms. For Cond_Cal_MidRange()
and Cond_Cal_FullRange()
, the second parameter is the conductivity of the fluid used for those calibrations; we suggest using calibration fluids of 1.00 mS/cm (milliSiemens per centimeter) and 100. mS/cm respectively. If the conductivity of the full-range calibration fluid differs from 100 mS/cm by more than ±12 mS/cm, the sensor series impedance calibration becomes inaccurate by a factor of more than one part in one thousand.
After a probe has been calibrated on one of the four channels using the Cond_Cal_
functions, the calculated cell constant and sensor series impedance can be retrieved using the Cond_Fetch_
functions. When the probe is used with another instrument, those two values can be set directly for the associated channel using the Cond_Store_
functions, which will store the value in EEPROM.
Taking resistance and conductivity measurements
The high level measurement functions are Cond_kOhms()
and Cond_mS_cm()
. Cond_kOhms()
returns a floating point value equal to the fluid resistance in kOhms (thousands of Ohms), and Cond_mS_cm()
returns a floating point conductivity measurement in mS/cm (milliSiemens per centimeter) for the specified channel. These two high level functions work only after a probe has had the tare (offset) calibration performed, and has either had the mid-range and full-range calibration performed, or has had the cell constant and sensor series impedance entered. Cond_kOhms()
may return zero, and will saturate at the high end at a resistance value associated with a measurement just below than the open-probe tare measurement. Cond_mS_cm()
will saturate at the low end at the conductivity value associated with a measurement just below the tare measurement, and will saturate at the high end at a conductivity value associated with a total resistance measurement just above the sensor series resistance. A negative return value from either of these functions indicates some kind of error.
Installing the driver and running the demo programs
For Mosaic's PDQ line controllers, the demo is included in Mosaic IDE Plus at revision numbers later than 1300. Close any open projects in Mosaic IDE Plus to get to the start screen, then click on the box marked "Click Here to open a demo project" and select the Conductivity Sensor Wildcard Demo.
.cbp
project file.
In writing application software to use the Conducitivity Wildcard driver software in Mosaic IDE Plus, it is only necessary to add the following line to the top of your source code:
#include <wcond.h>
For Mosaic's Q-line controllers, the files wcond.c
, wcond.h
, numutil.c
, and numutil.h
must be in the same folder as the demo code for the demo code to compile successfully. The demo along with these files are available for download in this zip file. If you are using the Analog I/O Wildcard as well with a Q-line controller, you will also need a kernel extension package that includes the Analog I/O Wildcard driver, generated using Mosaic's Kernel Extension Manager.
Below is a code listing demonstrating common usage of the Conductivity Wildcard driver software.
Mosaic Conductivity Wildcard Demo
1: // 2: // Copyright 2013 Mosaic Industries, Inc. 3: // Disclaimer: THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT ANY 4: // WARRANTIES OR REPRESENTATIONS EXPRESS OR IMPLIED, INCLUDING, BUT NOT 5: // LIMITED TO, ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS 6: // FOR A PARTICULAR PURPOSE. 7: // 8: 9: // 10: // Conductivity Wildcard Demo Program 11: // 12: 13: #include <mosaic/allqed.h> 14: 15: // 16: // ******** DATA SOURCE SELECTION ******** 17: // 18: // Uncomment PROBE_ADC_CHAN below if you have a conductivity probe, and set 19: // it equal to the ADC channel the probe is connected to. If PROBE_ADC_CHAN 20: // remains commented out, then sensible random values are used instead. 21: // If you are using a ribbon cable provided by Mosaic to connect the two 22: // Wildcards, then output 1 of the Conductivity Wildcard connects to ADC 23: // channel 4 of the Analog I/O Wildcard, and conductivity output 2 24: // connects to ADC channel 5. 25: // 26: // Uncomment WAIM_MODULE_NUM if Conductivity Wildcard output is measured 27: // with the Analog I/O Wildcard, and set it equal to the Analog I/O 28: // Wildcard's module number (determined with settings of jumpers J1 and J2, 29: // and whether it is mounted on module port 1 or 2). If WAIM_MODULE_NUM 30: // remains commented out and PROBE_ADC_CHAN is uncommented, then the 31: // Conductivity Wildard's output must be connected to the controller's 32: // built-in ADC. 33: // 34: // Uncomment VREFR_ADC_CHAN if the reference voltage of the Conductivity 35: // Wildcard is being measured with an ADC channel. If VREFR_ADC_CHAN 36: // remains commented out, it is assumed the Conductivity Wildcard 37: // reference output is used as the reference voltage for the ADC 38: // (i.e. connected to the Analog I/O Wildcard's REF input). 39: // This is not the case if the controller's built-in ADC is used. 40: // 41: //#define WAIM_MODULE_NUM 4 42: //#define PROBE_ADC_CHAN AD16_CH4 43: //#define VREFR_ADC_CHAN AD16_CH3 44: 45: // Conductivity Wildcard software channel may be 0 through 3. 46: // This is not related to the physical connection of a conductivity 47: // probe. Rather, this is an index to a set of stored calibration 48: // constants in the Conductivty Wildcard driver software. 49: #define PROBE_COND_CHAN 0 50: 51: 52: 53: // Now include header files based on data 54: // source indicated in #define's above. 55: #ifdef __GNUC__ 56: 57: #include <wcond.h> 58: #ifdef WAIM_MODULE_NUM 59: #include <waim.h> 60: #endif 61: 62: #else // fABIUS 63: 64: #include "wcond.c" 65: #ifdef WAIM_MODULE_NUM 66: #include "library.h" 67: #include "library.c" 68: #endif 69: 70: #endif // __GNUC__ / fABIUS 71: 72: 73: 74: 75: // Macros for sensible simulated calibration readings. 76: #define RANDOM_TARE() ( 0xd000u + ( (unsigned)Random() & 0x1fff ) ) 77: #define RANDOM_MIDR() ( 0x7000u + ( (unsigned)Random() & 0x0fff ) ) 78: #define RANDOM_FULL() ( 0x300u + ( (unsigned)Random() % 0xd0 ) ) 79: 80: // Demo function prototypes. 81: int do_tare_calibration( void ); 82: int do_midrange_calibration( void ); 83: int do_fullrange_calibration( void ); 84: void do_adc_init( void ); 85: unsigned do_probe_read( void ); 86: 87: 88: 89: int main( void ) 90: { 91: INSTRUMENT_FLOAT( resistance ); 92: INSTRUMENT_FLOAT( conductivity ); 93: float tempf; 94: char* display_string; 95: unsigned probe_counts; 96: int result; 97: char user_key; 98: 99: printf( "\n\n--- Conductivity Wildcard Demo ---\n\n" ); 100: 101: do_adc_init(); 102: 103: result = Cond_CheckEEData(); 104: if( ! result ) 105: { 106: printf( "WARNING: No calibration data stored.\n" ); 107: printf( "EEPROM calibration area will be re-initialized.\n\n" ); 108: } 109: 110: result = Cond_Init(); 111: if( ! result ) 112: { 113: printf( "ERROR: Conductivity Wildcard software initialization failed!\n\n" ); 114: } 115: else 116: { 117: do 118: { 119: printf( "\n--------------------------------\n" ); 120: printf( "\nSelect an option:\n" ); 121: printf( "0. Exit to QED-Forth\n" ); 122: printf( "1. Probe Tare Calibration\n" ); 123: printf( "2. Probe Mid-Range Calibration\n" ); 124: printf( "3. Probe Full-Range Calibration\n" ); 125: printf( "4. Input Probe Cell Constant\n" ); 126: printf( "5. Input Probe Sensor Impedance\n" ); 127: printf( "6. Reset Probe Calibration Data to Defaults\n" ); 128: printf( "7. Display Probe Calibration Data\n" ); 129: printf( "8. Take Resistance and Conductivity Measurement\n\n" ); 130: 131: do user_key = Key(); while( user_key < '0' || user_key > '8' ); 132: 133: if( user_key == '1' ) do_tare_calibration(); 134: if( user_key == '2' ) do_midrange_calibration(); 135: if( user_key == '3' ) do_fullrange_calibration(); 136: 137: if( user_key == '4' ) 138: { 139: printf( "Enter probe cell constant (1/cm):\n" ); 140: tempf = User_Float_Input(); 141: result = Cond_Store_CellConstant( PROBE_COND_CHAN, tempf ); 142: if( ! result ) printf( "ERROR: Failed to store cell constant: %g\n\n", tempf ); 143: } 144: 145: if( user_key == '5' ) 146: { 147: printf( "Enter probe series sensor impedance (Ohms):\n" ); 148: tempf = User_Float_Input() / 1000.0f; 149: result = Cond_Store_SensorImpedance( PROBE_COND_CHAN, tempf ); 150: if( ! result ) printf( "ERROR: Failed to store sensor impedance: %g\n\n", tempf ); 151: } 152: 153: if( user_key == '6' ) 154: { 155: result = Cond_Cal_Reset( PROBE_COND_CHAN ); 156: if( ! result ) printf( "ERROR: Failed to reset probe calibration data.\n\n" ); 157: } 158: 159: // If user presses '1'-'6', calibration data displayed after 160: // it is updated. 161: // If user presses '7', calibration data displayed only. 162: // If user presses '8', calibration data displayed before a 163: // probe reading is taken. 164: if( user_key != '0' ) 165: { 166: tempf = Cond_Fetch_CellConstant( PROBE_COND_CHAN ); 167: printf( "Probe Cell Constant: %.3f (1/cm)\n", tempf ); 168: tempf = Cond_Fetch_SensorImpedance( PROBE_COND_CHAN ) * 1000.0f; 169: printf( "Probe Sensor Impedance: %.3f Ohms\n\n", tempf ); 170: } 171: 172: if( user_key == '8' ) 173: { 174: probe_counts = do_probe_read(); 175: printf( "Probe ADC reading: %5u/65536\n", probe_counts ); 176: resistance = Cond_kOhms( PROBE_COND_CHAN, probe_counts ); 177: conductivity = Cond_mS_cm( PROBE_COND_CHAN, probe_counts ); 178: display_string = INSTRUMENT_FORMAT4( resistance ); 179: printf( "Probe resistance: %.5s kOhms\n", display_string ); 180: display_string = INSTRUMENT_FORMAT4( conductivity ); 181: printf( "Probe conductivity: %.5s mS/cm\n\n", display_string ); 182: } 183: } 184: while( user_key != '0' ); 185: } 186: 187: return result; 188: } 189: 190: 191: 192: int do_tare_calibration( void ) 193: { 194: unsigned probe_counts; 195: int result; 196: 197: // Clear any character potentially in the serial port read buffer. 198: while( AskKey() ) Key(); 199: 200: printf( "Ensure the conductivity probe is connected and\n" ); 201: printf( "not immersed in solution. Press Esc to cancel,\n" ); 202: printf( "or any other key to perform tare calibration.\n\n" ); 203: result = Key(); 204: 205: if( result != '\x1b' ) 206: { 207: #ifdef PROBE_ADC_CHAN 208: probe_counts = do_probe_read(); 209: #else 210: probe_counts = RANDOM_TARE(); 211: #endif 212: 213: printf( "Tare calibration reading: %5u/65536\n", probe_counts ); 214: 215: result = Cond_Cal_Tare( PROBE_COND_CHAN, COND_ONBOARD_KOHMS, probe_counts ); 216: 217: if( ! result ) printf( "ERROR: Storing tare calibration failed.\n\n" ); 218: } 219: else printf( "Tare calibration not performed.\n\n" ); 220: 221: return result; 222: } 223: 224: 225: 226: int do_midrange_calibration( void ) 227: { 228: unsigned probe_counts; 229: int result; 230: 231: // Clear any character potentially in the serial port read buffer. 232: while( AskKey() ) Key(); 233: 234: printf( "Ensure the conductivity probe is connected and\n" ); 235: printf( "immersed in a calibration fluid of 1.00 mS/cm.\n" ); 236: printf( "Press Esc to cancel, or any other key to perform\n" ); 237: printf( "mid-range calibration.\n\n" ); 238: result = Key(); 239: 240: if( result != '\x1b' ) 241: { 242: #ifdef PROBE_ADC_CHAN 243: probe_counts = do_probe_read(); 244: #else 245: probe_counts = RANDOM_MIDR(); 246: #endif 247: 248: printf( "Mid-range calibration reading: %5u/65536\n", probe_counts ); 249: 250: result = Cond_Cal_Midrange( PROBE_COND_CHAN, COND_MIDR_MSCM, probe_counts ); 251: 252: if( ! result ) printf( "ERROR: Storing mid-range calibration failed.\n\n" ); 253: } 254: else printf( "Mid-range calibration not performed.\n\n" ); 255: 256: return result; 257: } 258: 259: 260: 261: int do_fullrange_calibration( void ) 262: { 263: unsigned probe_counts; 264: int result; 265: 266: // Clear any character potentially in the serial port read buffer. 267: while( AskKey() ) Key(); 268: 269: printf( "Ensure the conductivity probe is connected and\n" ); 270: printf( "immersed in a calibration fluid of 100. mS/cm.\n" ); 271: printf( "Press Esc to cancel, or any other key to perform\n" ); 272: printf( "full-range calibration.\n\n" ); 273: result = Key(); 274: 275: if( result != '\x1b' ) 276: { 277: #ifdef PROBE_ADC_CHAN 278: probe_counts = do_probe_read(); 279: #else 280: probe_counts = RANDOM_FULL(); 281: #endif 282: 283: printf( "Full-range calibration reading: %5u/65536\n", probe_counts ); 284: 285: result = Cond_Cal_Fullrange( PROBE_COND_CHAN, COND_FULL_MSCM, probe_counts ); 286: 287: if( ! result ) printf( "ERROR: Storing full-range calibration failed.\n\n" ); 288: } 289: else printf( "Full-range calibration not performed.\n\n" ); 290: 291: return result; 292: } 293: 294: 295: 296: void do_adc_init( void ) 297: { 298: #ifdef PROBE_ADC_CHAN // Using measurements, not simulated values. 299: 300: #ifdef WAIM_MODULE_NUM // Analog I/O Wildcard 301: 302: printf( "Initializing Analog I/O Wildcard module %u.\n\n", WAIM_MODULE_NUM ); 303: Init_Analog_IO( EXT_DAC12, WAIM_MODULE_NUM ); 304: 305: #else // WAIM_MODULE_NUM not defined 306: #ifdef __GNUC__ // PDQ line built-in ADC 307: 308: printf( "Initializing HCS12 built-in ADC channel %u", PROBE_ADC_CHAN ); 309: ATDOn( PROBE_ADC_CHAN ); 310: #ifdef VREFR_ADC_CHAN 311: printf( " and %u", VREFR_ADC_CHAN ); 312: ATDOn( VREFR_ADC_CHAN ); 313: #endif // VREFR_ADC_CHAN 314: printf( ".\n\n" ); 315: 316: #else // Q line built-in ADC 317: 318: printf( "Initializing HC11 built-in ADC." ); 319: AD8On(); 320: 321: #endif // __GNUC__ 322: #endif // WAIM_MODULE_NUM 323: 324: #else // PROBE_ADC_CHAN not defined; using simulated values. 325: 326: printf( "Initializing simulated data generation.\n\n" ); 327: RANDOM_SEED = TCNT; 328: 329: #endif // PROBE_ADC_CHAN 330: } 331: 332: 333: 334: unsigned do_probe_read( void ) 335: { 336: #ifdef VREFR_ADC_CHAN 337: unsigned vrefr_counts; 338: #endif 339: unsigned probe_counts; 340: 341: #ifdef PROBE_ADC_CHAN // Using measurements, not simulated values. 342: 343: #ifdef WAIM_MODULE_NUM // Analog I/O Wildcard 344: 345: probe_counts = AD16_Sample( PROBE_ADC_CHAN, WAIM_MODULE_NUM ); 346: #ifdef VREFR_ADC_CHAN 347: vrefr_counts = AD16_Sample( VREFR_ADC_CHAN, WAIM_MODULE_NUM ); 348: #endif 349: 350: #else // WAIM_MODULE_NUM not defined 351: #ifdef __GNUC__ // PDQ line built-in ADC 352: 353: probe_counts = ATDSingle( PROBE_ADC_CHAN ); 354: #ifdef VREFR_ADC_CHAN 355: vrefr_counts = ATDSingle( VREFR_ADC_CHAN ); 356: #endif 357: 358: #else // Q line built-in ADC; shift readings to left-justifty. 359: 360: probe_counts = AD8Sample( PROBE_ADC_CHAN ) << 8; 361: #ifdef VREFR_ADC_CHAN 362: vrefr_counts = AD8Sample( VREFR_ADC_CHAN ) << 8; 363: #endif 364: 365: #endif // __GNUC__ 366: #endif // WAIM_MODULE_NUM 367: 368: #ifdef VREFR_ADC_CHAN 369: // If the Conductivity Wildcard's reference voltage is read 370: // with an ADC channel, use it to normalize the probe reading. 371: probe_counts = Cond_Normalize_Counts( vrefr_counts, probe_counts ); 372: #endif 373: 374: #else // PROBE_ADC_CHAN not defined; using simulated values. 375: 376: probe_counts = Random(); 377: if( probe_counts & 0x8000u ) 378: { 379: // Use the upper bit of Random() value to decide whether 380: // to add an additional 0x4000. Total range is 0 to 381: // 0xbfff, with values from 0x4000 to 0x7fff twice as 382: // likely to appear as values 0-0x3fff and 0x8000-0xbfff. 383: probe_counts = ( probe_counts & 0x7fff ) + 0x4000; 384: } 385: // Offset range to 0x0800 to 0xc7ff. 386: probe_counts += 0x800; 387: 388: #endif // PROBE_ADC_CHAN 389: 390: return probe_counts; 391: }
Compiling the Conductivity Wildcard demo program
This walkthrough will assume that the Conductivity Wildcard was purchased from Mosaic along with the Analog I/O Wildcard and a ribbon cable for connecting the two Wildcards. This is the most common configuration and generates the most precise measurements.
By default the demo program uses simulated values for all conductivity probe readings. In order to use measured data from the Analog I/O Wildcard, uncomment the following two lines, and set the module number of the Analog I/O Wildcard and the ADC channel to which the Conductivity Wildcard output is connected. If you are using a ribbon cable provided by Mosaic to connect the two Wildcards, then output 1 of the Conductivity Wildcard connects to ADC channel 4 of the Analog I/O Wildcard, and conductivity output 2 connects to ADC channel 5.
#define WAIM_MODULE_NUM 4
#define PROBE_ADC_CHAN 4
Compile the demo program as described above using either Mosaic IDE Plus for the PDQ Board, or Mosaic IDE for the Q-line controllers. Use Mosaic Terminal to connect to the controller and select File→ Send File. Navigate to the project folder for the Conductivity Wildcard demo program, and select the compiled DLF file to send it to the controller. If you are using the Analog I/O Wildcard with a Q-line controller, you will also have to send the kernel extension package file install.txt
to the board; this is not necessary for the PDQ Board.
Once you have sent the compiled code to the controller, ensure the conductivity probe is connected to the Conductivity Wildcard sensor input header, and type main
at the command prompt to start the demo program.
Running the Conductivity Wildcard demo program
Initializing the Conductivity Wildcard driver software
The first action taken in the demo program's main
function is checking whether conductivity probe calibration data is already stored in EEPROM by calling Cond_CheckEEData()
:
result = Cond_CheckEEData();
and warning the user if the Conductivity Wildcard driver EEPROM area is going to be re-initialized. Then it calls Cond_Init()
to initialize the EEPROM area if needed, and then initialize run-time calibration constants in memory based on the data in EEPROM:
result = Cond_Init();
The return value of Cond_Init()
indicates whether initialization failed for some reason, such as a EEPROM write failure or invalid calibration data in EEPROM. The latter case should not occur, but if it does, Cond_ResetEEData()
could be called to clear the invalid data from EEPROM.
After initialization, a numbered menu is presented to the user with the option to enter calibration data, perform calibration using fluids of known conductivity, display probe calibration data, or take a resistance/conductivity measurement. With a new probe connected, whether or not that probe came with documented calibration points, you should select the option for "Probe Tare Calibration" while the probe is dry. This will cause the demo program to pass a probe reading to Cond_Cal_Tare()
and store a new dry-probe measurement that is a nonlinear offset factoring into every subsequent calculation, and also sets an upper limit for the resistance that can be measured.
Entering pre-determined probe calibration constants
After performing the tare calibration, if your conductivity probe came from the manufacturer with cell constant and series sensor impedance documented, these constants can be entered by selecting the option for "Input Probe Cell Constant" or "Input Probe Sensor Impedance". These will request the user type in a number, and pass the result to Cond_Store_CellConstant()
or Cond_Store_SensorImpedance()
respectively.
Mid-range calibration of a conductivity probe
If you need to determine the cell constant and series sensor impedance of a conductivity probe using calibration fluids of known conductivity, then after performing the tare calibration, select the option for "Probe Mid-Range Calibration". With the probe immersed in a calibration fluid of 1.00 mS/cm, press any key to cause the demo program to pass a probe reading to Cond_Cal_MidRange()
to calculate and store a new cell constant based on that measurement.
Full-range calibration of a conductivity probe
After performing the tare and mid-range calibrations, immerse the probe in a calibration fluid of 100 mS/cm. Select the option for "Probe Full-Range Calibration". With the probe immersed in the 100 mS/cm fluid, press any key to cause the demo program to pass a probe reading to Cond_Cal_FullRange()
. A new sensor series impedance will be calculated and displayed. Now that raw calibration data is available for both mid-range and full-range fluids, both calibration values will be recalculated until they stabilize. Thus, the cell constant may change slightly as well, but should not change by much.
Measuring resistance and conductivity with a calibrated probe
Once the probe is calibrated, using either known calibration constants or calibration in fluids of known conductivity, accurate conductivity measurements may be taken. Select the option for "Take a Resistance and Conductivity Measurement" to immediately read the probe output and calculate both resistance and conductivity using Cond_kOhms()
and Cond_mS_cm()
. Current calibration data will be displayed along with the resistance and conductivity measurements.
Function summary
The Conductivity Wildcard driver software includes many functions that are used internally and don't need to be accessed directly by a user's application. All functions are documented here for completeness, however you will likely only need to use those under "Primary API" below.
Primary API
Initialization
Probe Calibration
int Cond_Cal_Tare( unsigned channel, float resi_onboard, unsigned tare_counts ); int Cond_Cal_Midrange( unsigned channel, float midrange_conductivity, unsigned midrange_counts ); int Cond_Cal_Fullrange( unsigned channel, float fullrange_conductivity, unsigned fullrange_counts ); int Cond_Cal_Reset( unsigned channel );
Probe transfer
float Cond_Fetch_CellConstant( unsigned channel ); int Cond_Store_CellConstant( unsigned channel, float cell_constant ); float Cond_Fetch_SensorImpedance( unsigned channel ); int Cond_Store_SensorImpedance( unsigned channel, float sensor_impedance );
Measurement
unsigned Cond_Normalize_Counts( unsigned vrefr, unsigned vcurr ); float Cond_kOhms( unsigned channel, unsigned counts ); float Cond_mS_cm( unsigned channel, unsigned counts );
Internal functions
Calculation
float Cond_Voltage_Divider( unsigned tare_counts, unsigned curr_counts ); float Cond_Channel_kOhms( cond_chan_calb_t* chap, unsigned counts );
Calibration
int Cond_Channel_TareCal( cond_chan_calb_t* chap, float resi_onboard, unsigned tare_counts ); int Cond_Channel_MidrCal( cond_chan_calb_t* chap, float midr_cond, unsigned midr_counts ); int Cond_Channel_FullCal( cond_chan_calb_t* chap, float full_cond, unsigned full_counts ); int Cond_Channel_CondCal( cond_chan_calb_t* chap, float midr_conductivity, float full_conductivity, unsigned midr_counts, unsigned full_counts ); int Cond_Channel_LimitCal( cond_chan_calb_t* chap ); int Cond_Channel_DefaultCal( cond_chan_calb_t* chap );
Nonvolatile storage
int Cond_StoreEEPair( float f, unsigned c, cond_pair_t* addr ); int Cond_StoreEEFloat( float f, cond_pair_t* addr ); float Cond_FetchEEFloat( cond_pair_t* addr ); int Cond_InitEEStruct( cond_chan_nonvol_t* nvlp ); int Cond_Channel_LoadCal( cond_chan_calb_t* chap, cond_chan_nonvol_t* nvlp );
Function glossary
Cond_Cal_Fullrange
int Cond_Cal_Fullrange( const size_t channel, const float fullrange_conductivity, const unsigned fullrange_counts );
Precondition: Tare and mid-range calibration data has been populated for the channel index specified. Cond_Init()
populates these with either stored values from nonvolatile memory, or default values if no calibration data has been stored in nonvolatile memory. Full-range calibration should not be performed with a conductivity probe until tare and mid-range calibrations have been performed by calling Cond_Cal_Tare()
and then either Cond_Cal_Midrange()
to perform mid-range calibration, or Cond_Store_CellConstant()
if the cell constant of the probe is already known from mid-range calibration on another instrument or at the factory.
Based on a known full-range calibration solution conductivity fullrange_conductivity
and ADC reading fullrange_counts
taken with the probe in that solution, stores these known raw values in nonvolatile memory at index channel
, and then updates the calculated calibration values for this probe. It is recommended to use a full-range calibration solution with a conductivity of 100. milliSiemens per cm; if the conductivity of the full-range calibration fluid differs by more than ±12 mS/cm from 100 mS/cm, the sensor series impedance calibration becomes inaccurate by a factor of more than one part in one thousand.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. Returns a nonzero value on success and zero on failure.
Type: function
Cond_Cal_Midrange
int Cond_Cal_Midrange( const size_t channel, const float midrange_conductivity, const unsigned midrange_counts );
Precondition: Tare calibration data has been populated for the channel index specified. Cond_Init()
populates tare calibration data for all channels with either stored values from nonvolatile memory, or default values if no calibration data has been stored in nonvolatile memory. Mid-range calibration should not be performed with a conductivity probe until tare calibration data has been stored in nonvolatile memory by calling Cond_Cal_Tare()
.
Based on a known mid-range calibration solution conductivity midrange_conductivity
(1.00 milliSiemens per cm recommended) and ADC reading midrange_counts
taken with the probe in that solution, stores these known raw values in nonvolatile memory at index channel
, and then updates the calculated calibration values for this probe.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. Returns a nonzero value on success and zero on failure.
Type: function
Cond_Cal_Reset
int Cond_Cal_Reset( const size_t channel );
Resets the stored calibration data for the probe at channel index channel
to default values, and also resets the calculated calibration values for this probe. See Cond_Channel_DefaultCal()
for the values used.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. Returns a nonzero value on success and zero on failure.
Type: function
Cond_Cal_Tare
int Cond_Cal_Tare( const size_t channel, const float resi_onboard, const unsigned tare_counts );
This is the first step in calibrating any conductivity probe, and produces a result that is specific to the combination of probe and instrument. Therefore this step must be performed by an end-user even if other calibration data (cell constant and sensor series impedance) are provided by the manufacturer.
Based on a known on-board precision resistor value resi_onboard
in KΩ (always 1.0 for revision 3 of the Conductivity Wildcard) and ADC reading tare_counts
taken with the probe dry, stores these known raw values in nonvolatile memory at index channel
, and then updates the calculated calibration values for this probe.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. Returns a nonzero value on success and zero on failure.
Type: function
cond_chan_calb_t
typedef struct { float refr_imped; float sens_imped; float cell_const; float resi_ovrld; float cond_ovrld; unsigned tare_counts; unsigned short_counts; } cond_chan_calb_t;
Struct for storing calibration data used at runtime directly in computations for a particular conductivity probe. These values are generated from basic calibration data stored in nonvolatile memory, generally in a cond_chan_nonvol_t
struct.
Type: typedef struct
cond_chan_nonvol_t
typedef struct { cond_pair_t tare; cond_pair_t midr; cond_pair_t full; } cond_chan_nonvol_t;
Struct for storing either pairs of raw ADC counts and known values, or previously calculated calibration values for a particular probe, in nonvolatile memory (EEPROM). If a probe has been calibrated on this instrument, the raw ADC counts and known values will be stored, and if it was calibrated at the factory and delivered with the series impedance and cell constant documented, then those calculated values will be stored instead. Each cond_pair_t
may store either the pair of raw values or the single calculated value. If the single calculated value is stored, it is indicated by COND_PAIR_ISFLOAT
returning true, retrieved with Cond_Fetch_EEFloat
() and stored with Cond_Store_EEFloat()
.
Type: typedef struct
Cond_Channel_CondCal
int Cond_Channel_CondCal( cond_chan_calb_t* const chap, const float midr_conductivity, const float full_conductivity, const unsigned midr_counts, const unsigned full_counts );
Precondition: Tare calibration data has been populated in the cond_chan_calb_t
pointed to by chap
, by calling Cond_Channel_TareCal()
. Parameters are checked for sensibility as follows:
chap != NULL && chap->refr_imped > ZERO && midr_conductivity > ZERO && midr_conductivity < full_conductivity && full_counts < midr_counts && midr_counts < chap->tare_counts;
Given a known mid-range calibration fluid conductivity (1.00 milliSiemens per cm recommended) and full-range calibration fluid conductivity (100. milliSiemens per cm recommended), as well as ADC measurements of the conductivity probe in these fluids in the range of zero to 216 (with 216 representing the reference voltage of the Conductivity Wildcard), performs iterative calculation of the probe's series impedance and cell constant. Returns a nonzero value on success, and zero if the iterations fail to converge in a reasonable time or parameters are invalid. Failure to converge likely indicates incorrect input values.
Type: function
Cond_Channel_DefaultCal
int Cond_Channel_DefaultCal( cond_chan_calb_t* const chap );
Initializes the cond_chan_calb_t
pointed to by chap
based on the following default values:
- Tare Counts: 7/8 of the reference voltage, a round empirical average.
- Cell Constant: 1.0
- Sensor Series Impedance: 1/256 KΩ, also a round empirical average.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_Channel_FullCal
int Cond_Channel_FullCal( cond_chan_calb_t* const chap, const float full_cond, const unsigned full_counts );
Precondition: Tare and mid-range calibration data has been populated in the cond_chan_calb_t
pointed to by chap
, by first calling Cond_Channel_TareCal()
and then Cond_Channel_MidrCal()
.
Based on a known full-range calibration solution conductivity full_cond
and ADC reading full_counts
taken with the probe in that solution, sets the sensor series impedance for that probe in the cond_chan_calb_t
pointed to by chap
. It is recommended to use a full-range calibration solution with a conductivity of 100. milliSiemens per cm; if the conductivity of the full-range calibration fluid differs by more than ±12 mS/cm from 100 mS/cm, the sensor series impedance calibration becomes inaccurate by a factor of more than one part in one thousand.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_Channel_kOhms
float Cond_Channel_kOhms( const cond_chan_calb_t* const chap, const unsigned counts );
Based on calculated calibration data in the cond_chan_calb_t
pointed to by chap
, and 16 bit ADC reading counts
referenced to the Conductivity Wildcard's reference voltage at 216, calculates the measured resistance corresponding to counts
. Return value saturates at zero and at a reading just under the dry probe tare value. A negative return value indicates an error.
Type: function
Cond_Channel_LoadCal
int Cond_Channel_LoadCal( cond_chan_calb_t* const chap, const cond_chan_nonvol_t* const nvlp );
Populates the cond_chan_calb_t
struct pointed to by chap
with calculated calibration data based on the raw calibration data stored in the cond_chan_nonvol_t
struct in nonvolatile memory pointed to by nvlp
. Internally, this function calls Cond_Channel_TareCal()
and then one or more of Cond_Channel_MidrCal()
, Cond_Channel_FullCal()
, or Cond_Channel_CondCal()
depending on whether nvlp
contains calculated values for cell constant and sensor series impedance or raw values for mid-range calibration and full-range calibration.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_Channel_LimitCal
int Cond_Channel_LimitCal( cond_chan_calb_t* const chap );
Precondition: Tare calibration data has been populated in the cond_chan_calb_t
pointed to by chap
, by calling Cond_Channel_TareCal()
. Also, mid-range calibration data has been stored by either setting chap→ cell_const
or calling Cond_Channel_MidrCal()
, and full-range calibration data has been stored by either setting chap→ sens_imped
or calling Cond_Channel_FullCal()
.
Based on calibration data already stored in the cond_chan_calb_t
pointed to by chap
, sets the maximum measurable resistance value and minimum and maximum measurable conductivity values, and minimum and maximum ADC readings from this probe that cause those limits to be reached. Any ADC readings that exceed one of these limits passed to one of the Conductivity Wildcard measurement functions causes the result to saturate at these limit values.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_Channel_MidrCal
int Cond_Channel_MidrCal( cond_chan_calb_t* const chap, const float midr_cond, const unsigned midr_counts );
Precondition: Tare calibration data has been populated in the cond_chan_calb_t
pointed to by chap
, by calling Cond_Channel_TareCal()
.
Based on a known mid-range calibration solution conductivity midr_cond
(1.00 milliSiemens per cm recommended) and ADC reading midr_counts
taken with the probe in that solution, sets the cell constant for that probe in the cond_chan_calb_t
pointed to by chap
.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_Channel_TareCal
int Cond_Channel_TareCal( cond_chan_calb_t* const chap, const float resi_onboard, const unsigned tare_counts );
Calculates dry probe impedance based on the Conductivity Wildcard onboard resistance value resi_onboard
in KΩ (default value 1.0) and ADC reading tare_counts
taken with the probe not immersed in solution. Stores the resulting tare calibration data in the cond_chan_calb_t
pointed to by chap
.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_CheckEEData
int Cond_CheckEEData( void );
Returns a zero value if there is no calibration data stored in nonvolatile memory, and a nonzero value if calibration data has been stored. Note that default values stored in nonvolatile memory with Cond_ResetEEData()
will cause this function to return a nonzero value. Only if values in nonvolatile memory are uninitialized does this function return a zero value.
It is recommended to call this function before calling Cond_Init()
, and if it returns zero alert the user that stored calibration data will be initialized. If the EEPROM data were to be corrupted, this would provide an alert to the user rather than simply resetting calibration data to default values and producing incorrect measurements. Ideally the instrument would be run once in factory testing to initialize EEPROM, so the user would only see this message if corruption of EEPROM had occurred.
Type: function
Cond_Fetch_CellConstant
float Cond_Fetch_CellConstant( const size_t channel );
Returns the calculated probe cell constant associated with channel index channel
. This can be used with Cond_Store_CellConstant()
to move the probe to another instrument, or recorded as factory calibration data.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. A negative return value indicates an error.
Type: function
Cond_Fetch_SensorImpedance
float Cond_Fetch_SensorImpedance( const size_t channel );
Returns the calculated probe series sensor impedance associated with channel index channel
. This can be used with Cond_Store_SensorImpedance()
to move the probe to another instrument, or recorded as factory calibration data.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. A negative return value indicates an error.
Type: function
Cond_FetchEEFloat
float Cond_FetchEEFloat( const cond_pair_t* const addr );
Returns a non-negative 32-bit floating point value that had been stored in the cond_pair_t
pointed to by addr
using Cond_StoreEEFloat()
. A negative return value indicates an error.
Type: function
COND_FULL_MSCM
#define COND_FULL_MSCM 100.0f
A constant containing the recommended full-range calibration fluid conductivity of 100. milliSiemens per cm. If the conductivity of the full-range calibration fluid differs by more than ±12 mS/cm from 100 mS/cm, the sensor series impedance calibration becomes inaccurate by a factor of more than one part in one thousand.
Type: macro
Cond_InitEEStruct
int Cond_InitEEStruct( cond_chan_nonvol_t* nvlp );
Stores default values in the cond_chan_nonvol_t
at the EEPROM address nvlp
. For the values stored, see Cond_Channel_DefaultCal()
.
Returns a nonzero value on success and zero on failure.
Type: function
COND_INVALID
#define COND_INVALID -10000.0f
A constant used as a return value from a function to indicate invalid parameters or an invalid operation. Any negative return value from a Conductivity Wildcard driver function indicates an error.
Type: macro
Cond_kOhms
float Cond_kOhms( const size_t channel, const unsigned counts );
Based on calculated calibration data for probe at channel index channel
, and 16 bit ADC reading counts
referenced to the Conductivity Wildcard's reference voltage at 216, calculates the measured fluid resistance in KΩ. Return value saturates at zero and at a reading just under the dry probe tare value.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. A negative return value indicates an error.
Type: function
COND_MIDR_MSCM
#define COND_MIDR_MSCM 1.0f
A constant containing the recommended mid-range calibration fluid conductivity of 1.00 milliSiemens per cm.
Type: macro
Cond_mS_cm
float Cond_mS_cm( const size_t channel, const unsigned counts );
Based on calculated calibration data for probe at channel index channel
, and 16 bit ADC reading counts
referenced to the Conductivity Wildcard's reference voltage at 216, calculates the measured fluid conductivity corresponding to counts
in milliSiemens per centimeter. Return value saturates at a high reading corresponding with an impedance just above the sensor series impedance, and at a low reading corresponding with an impedance just under the dry probe tare value.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. A negative return value indicates an error.
Type: function
Cond_Normalize_Counts
unsigned Cond_Normalize_Counts( const unsigned vrefr, const unsigned vcurr );
This function is to be used if the Conductivity Wildcard's reference voltage is not used as the reference voltage for 16 bit analog to digital conversion.
All of the Conductivity Wildcard software driver functions assume that the Conductivity Wildcard's reference voltage corresponds to an (unobtainable) ADC reading of 216, or 65536. If the Conductivity Wildcard's reference voltage is used as the reference voltage for a 16 bit ADC, such as by connecting it to the REF pin of the Analog I/O Wildcard, then this condition is satisfied and Cond_Normalize_Counts()
is not necessary.
However, if an ADC with a different reference voltage is used to measure the Conductivity Wildcard output, it will be necessary to measure the Conductivity Wildcard's reference voltage as well to determine what fraction of that reference is represented by a conductivity probe reading. Given the measurement of the Conductivity Wildcard reference voltage in ADC counts as vrefr
and the measurement of a conductivity probe in ADC counts as vcurr
, this function returns a 16 bit unsigned value that is the same fraction of 216 as vcurr
is of vrefr
. In other words, Cond_Normalize_Counts( vrefr, vcurr )
= ( vcurr
/ vrefr
) × 216 with correct rounding.
If vcurr
≥vrefr
, the result saturates at the maximum 16 bit unsigned value of 216−1 (0xffff
or 65535).
Type: function
COND_NUM_CHANNELS
#define COND_NUM_CHANNELS 4
A constant indicating the number of channels for which space is allocated in EEPROM to store calibration data, and for which the top-level Conductivity Wildcard driver functions which take a channel number as an argument may be used. Valid channel numbers range from 0
to COND_NUM_CHANNELS-1
.
Type: macro
COND_ONBOARD_KOHMS
#define COND_ONBOARD_KOHMS 1.0f
A constant containing the resistance of the Conductivity Wildcard's precision reference resistor in KΩ, which is always 1.00 KΩ for revision 3 of the Conductivity Wildcard.
Type: macro
COND_PAIR_ISFLOAT
#define COND_PAIR_ISFLOAT(P) ( (P).p.known & 0x8000u )
A macro that returns a zero value if the most significant bit of the cond_pair_t
P
is zero, and a nonzero value if the most significant bit is set. Since this is the sign bit of both the 32-bit float (P).f
and the 16-bit float (P).p.known
, and negative values are never used, this bit may be used to indicate whether a 32-bit float or a pair of 16-bit float and 16-bit unsigned int are stored.
Type: macro
cond_pair_t
typedef union { float f; struct { unsigned known; unsigned counts; } p; } cond_pair_t;
Four-byte union for storing either two unsigned integers or one single-precision float. Intended to store either the combination of a known value in a 16-bit (half-precision) float and 16-bit calibration ADC reading, or a calculated 32-bit single-precision calibration value. See COND_PAIR_ISFLOAT()
for details on how the two are distinguished.
Type: typedef union
Cond_ResetEEData
int Cond_ResetEEData( void );
Initializes all calibration data in nonvolatile memory to default values. See Cond_Channel_DefaultCal()
for the values used.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_Store_CellConstant
int Cond_Store_CellConstant( const size_t channel, const float cell_constant );
Stores the probe cell constant cell_constant
for use in conductivity measurements with the probe at channel index channel
. On another instrument or at the factory, this value would have been determined in calibration and retrieved with Cond_Fetch_CellConstant()
.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. Returns a nonzero value on success and zero on failure.
Type: function
Cond_Store_SensorImpedance
int Cond_Store_SensorImpedance( const size_t channel, const float sensor_impedance );
Stores the probe series sensor impedance sensor_impedance
for use in conductivity measurements with the probe at channel index channel
. On another instrument or at the factory, this value would have been determined in calibration and retrieved with Cond_Fetch_SensorImpedance()
.
This function will fail if the Conductivity Wildcard driver EEPROM area has not yet been initialized by calling Cond_Init()
or Cond_ResetEEData()
. Returns a nonzero value on success and zero on failure.
Type: function
Cond_StoreEEFloat
int Cond_StoreEEFloat( float f, cond_pair_t* const addr );
Stores the positive 32-bit floating point value f
in the cond_pair_t
at the EEPROM address addr
.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_StoreEEPair
int Cond_StoreEEPair( const float f, const unsigned c, cond_pair_t* const addr );
Converts the 32-bit floating point value f
to a 16-bit floating point value, and stores it along with the 16-bit unsigned integer value c
in the cond_pair_t
at the EEPROM address addr
.
Returns a nonzero value on success and zero on failure.
Type: function
Cond_Voltage_Divider
float Cond_Voltage_Divider( const unsigned tare_counts, const unsigned curr_counts );
Given the dry probe voltage measurement tare_counts
and another probe voltage measurement curr_counts
, and assuming that 216 counts represents the Conductivity Wildcard's reference voltage, this function returns a floating point number indicating the total impedance of the probe measurement as a fraction of the precision reference resistance. It is generally not necessary to call this function directly, but it is used in resistance and conductivity calculations and probe calibration. A negative return value indicates that curr_counts
≥ tare_counts
.
Type: function