Part Two: The Temperature and Water Level Sensors

The next part of the project is to add the thermistor and water level sensor. First, start with the thermistor since it is more difficult to implement than the water level sensor.

As previously mentioned, the thermistor is part of a voltage divider system as shown in Figure 1. The output of the divider circuit is connected to an ADC input. Once the ADC reads and performs the ADC conversion, the conversion result is then used as part of the Simplified β (beta) Parameter equation (see Figure 1), which is a derivative of the Steinhart-Hart equation. The Simplified β Parameter equation uses terms that are easily attainable, such as the thermistor resistance value at 25°C, and reduces the complexity of the calculations that software must perform. To further simplify the software calculations, several of the more math-intensive variables have been pre-calculated by hand and listed as software constants.

Figure 1. Simplified β Parameter Equation
1T=1T0+1Bln(RR0)

where:

T = Temperature in Kelvin (K)

T0 = 298.15 K (room temperature (25°C))

B = Thermistor coefficient (in this case 3950)

R = measured thermistor resistance (ADC value (in voltage) must be converted to resistance)

R0 = Thermistor’s rated resistance at 25°C (in this case 10k Ω)

These calculations require floating-point math, similar to the pH sensor. When the project is created for this part of the system, the same steps to change from the C99 standard to the C90 standard must be followed. This will allow the use of 24-bit floats, which can then be broken down into three individual bytes for I2C transmission (see Part One: The pH Sensor for details).

Converting the Thermistor Input into Temperature shows the code used to calculate the temperature value and convert the 24-bit floating-point variable into three individual bytes. The snippet includes variables that have been precalculated in an effort to save additional memory space.

Converting the Thermistor Input into Temperature

uint16_t adc_result = 0;
float temperature = 0.00000;
float T0 = 0.00335;                                 // 1 / 298.15
float B = 0.00025;                                  // 1 / 3950 (beta value)
#define MAXADC          1023.000                    // 10-Bit ADCC
#define K               273.1500                    // Kelvin constant
#define LN              0.4343                      // Log(e)

while (1)
{
    adc_result = ADC_GetConversion(channel_ANA2);

    temperature = (MAXADC / (float)adc_result) - 1.00000;// R equiv of voltage
    temperature = log10(temperature);  // Take Log of the temperature
    temperature = temperature / LN;    // Divide log(temp) by Log(e) value
    temperature = B * temperature;     // Multiply by B constant
    temperature += T0;                 // Add T0 constant
    temperature = 1 / temperature;     // Invert to get degrees in Kelvin (K)
    temperature -= K;                  // Subtract K constant
    //printf("%1.2fC \r\n", temperature);       // Display temp

    (uint24_t)thermCopy = (float)temperature * 100;

    // Break down the float variable into 3 bytes to transmit
    thermLowByte = thermCopy & 0xFF;                   // Get low byte
    thermHighByte = (thermCopy >> 8) & 0xFF;           // Get high byte
    thermUpperByte = (thermCopy >> 16) & 0xFF;         // Get upper byte
    (uint8_t)i2cArray[0] = (uint8_t)thermLowByte;
    (uint8_t)i2cArray[1] = (uint16_t)thermHighByte;
    (uint8_t)i2cArray[2] = (uint24_t)thermUpperByte;
}

Once the temperature has been calculated, the water level sensor can be added. The water level sensor is very easy to implement. Since the ADC is already in use, another ADC input can be enabled to read the sensor output. The water level sensor is a “normally open” circuit, meaning that no current can flow. When the water level is low, magnetic forces from the floating part of the sensor are close enough to force the two metals contacts located in the shaft of the sensor to make contact. This allows current to flow through the sensor, which results in a voltage that can be read by the ADC.

Two wires protrude from the shaft of the water level sensor. One wire is connected to a power source; in this case, it is connected to VDD. The other end is connected to an ADC input pin. To prevent any transients from damaging the ADC input, a 100 Ω resistor is added in series to the ADC input. When the sensor is connected and the water level is good, the ADC pin will be floating and the ADC readings will be random. However, when the circuit closes, VDD appears on the ADC pin. Software can read the input, and if the ADC value is anything below VDD, the water level can be determined as good. If the ADC value is equal to VDD, the water level is too low.

Water Level Sensor Calculation shows the routine used to determine the water level. Since the sensor output can be converted into a 10-bit result, it is easy to convert the 10-bit reading into two bytes for I2C transmission.

Water Level Sensor Calculation

lvlSensor = ADC_GetConversion(channel_ANA4);
lvlSnsLowByte = lvlSensor & 0xFF;
lvlSnsHighByte = (lvlSensor >> 8) & 0xFF;
(uint8_t)i2cArray[3] = (uint8_t)lvlSnsLowByte;
(uint8_t)i2cArray[4] = (uint8_t)lvlSnsHighByte;
//printf("%d ADC Value \r\n", lvlSensor);

The last step is to add the I2C slave drivers. The same driver set as used in Part One can be used here as well.