// Copyright (C)2018-2023, Philip Munts dba Munts Technologies. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. namespace IO.Devices.TH02 { /// /// Encapsulates the TH02 temperature and humidity sensor. /// public class Device : IO.Interfaces.Temperature.Sensor, IO.Interfaces.Humidity.Sensor { private readonly IO.Interfaces.I2C.Device dev; private byte[] cmd = { 0, 0, 0 }; private byte[] resp = { 0, 0 }; // TH02 register addresses private const byte regStatus = 0x00; private const byte regDataH = 0x01; private const byte regDataL = 0x02; private const byte regConfig = 0x03; private const byte regID = 0x11; // TH02 commands private const byte cmdInit = 0x00; // Turn heater off private const byte cmdTemp = 0x11; private const byte cmdHumid = 0x01; // TH02 status masks private const byte mskBusy = 0x01; // Nonzero during conversion // TH02 humidity correction coefficients (from the TH02 datasheet) private const double A0 = -4.7844; private const double A1 = 0.4008; private const double A2 = -0.00393; private const double Q0 = 0.1973; private const double Q1 = 0.00237; /// /// Constructor for an TH02 temperature and humidity sensor object. /// /// I2C bus controller. public Device(IO.Interfaces.I2C.Bus bus) { dev = new IO.Interfaces.I2C.Device(bus, 0x40); Write(regConfig, cmdInit); } // Read from an TH02 device register. private byte Read(byte reg) { // Validate parameters if (reg > regID) throw new System.Exception("Invalid register address"); if ((reg > regConfig) && (reg < regID)) throw new System.Exception("Invalid register address"); // Issue I2C transaction cmd[0] = reg; dev.Transaction(cmd, 1, resp, 1); return resp[0]; } // Write to an TH02 device register. private void Write(byte reg, byte data) { // Validate parameters if (reg > regID) throw new System.Exception("Invalid register address"); if ((reg > regConfig) && (reg < regID)) throw new System.Exception("Invalid register address"); // Issue I2C transaction cmd[0] = reg; cmd[1] = data; dev.Write(cmd, 2); } // Get raw sample data private ushort Sample(byte what) { // Start conversion Write(regConfig, what); // Wait for completion while ((Read(regStatus) & mskBusy) != 0); // Fetch result cmd[0] = regDataH; dev.Transaction(cmd, 1, resp, 2); // Return result return (ushort)(resp[0]*256 + resp[1]); } /// /// Read-only property returning the temperature in degrees Celsius. /// public double Celsius { get { return (Sample(cmdTemp) >> 2) / 32.0 - 50.0; } } /// /// Read-only property returning the temperature in Kelvins. /// public double Kelvins { get { return IO.Interfaces.Temperature.Conversions.CelsiusToKelvins(Celsius); } } /// /// Read-only property returning the temperature in degrees Fahrenheit. /// public double Fahrenheit { get { return IO.Interfaces.Temperature.Conversions.CelsiusToFahrenheit(Celsius); } } /// /// Read-only property returning the percentage relative humidity. /// public double Humidity { get { // Get humidity sample double RHvalue = (Sample(cmdHumid) >> 4)/16.0 - 24.0; // Perform linearization double RHlinear = RHvalue - (RHvalue*RHvalue*A2 + RHvalue*A1 + A0); // Perform temperature compensation return RHlinear + (Celsius - 30.0)*(RHlinear*Q1 + Q0); } } /// /// Read-only property returning the device ID. /// public byte DeviceID { get { return Read(regID); } } } }