I2C HUMIDITY AND TEMPERATURE SENSOR

Dependents:   dashboard_f1

Revision:
2:18c159179b08
Parent:
0:3d466d4c2cd2
--- a/SI7021.cpp	Mon Feb 05 12:31:34 2018 +0000
+++ b/SI7021.cpp	Mon Feb 05 12:34:35 2018 +0000
@@ -0,0 +1,689 @@
+/**
+ * @brief       SI7021.h
+ * @details     I2C HUMIDITY AND TEMPERATURE SENSOR.
+ *              Header file.
+ *
+ *
+ * @return      NA
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018    The ORIGIN
+ * @pre         N/A.
+ * @warning     N/A
+ * @pre         This code belongs to AqueronteBlog ( http://unbarquero.blogspot.com ).
+ */
+
+#include "SI7021.h"
+
+
+SI7021::SI7021 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq )
+    : _i2c          ( sda, scl )
+    , _SI7021_Addr  ( addr )
+{
+    _i2c.frequency( freq );
+}
+
+
+SI7021::~SI7021()
+{
+}
+
+
+
+/**
+ * @brief       SI7021_Conf ( SI7021_measurement_resolution_t , SI7021_heater_t )
+ *
+ * @details     It configures the device: resolution and heater.
+ *
+ * @param[in]    myResolution:      Resolution for RH and temperature.
+ * @param[in]    myHeater:          Enable/Disable heater.
+ *
+ * @param[out]   N/A.
+ *
+ *
+ * @return       Status of SI7021_Conf.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         Except where noted, reserved register bits will always read back as “1,” and are not affected by write operations. For
+ *              future compatibility, it is recommended that prior to a write operation, registers should be read. Then the values read
+ *              from the RSVD bits should be written back unchanged during the write operation
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_Conf ( SI7021_measurement_resolution_t myResolution, SI7021_heater_t myHeater )
+{
+    char      cmd[]    =    { SI7021_READ_RH_T_USER_REGISTER_1, 0 };
+    uint32_t  aux      =    0;
+
+
+
+    // Read USER REGISTER to mask it
+    aux = _i2c.write ( _SI7021_Addr, &cmd[0], 1, true );
+    aux = _i2c.read  ( _SI7021_Addr, &cmd[1], 1 );
+
+
+    // Update USER REGISTER according to user requirements
+    // Resolution
+    cmd[1]  &= ~SI7021_RESOLUTION_MASK;
+    cmd[1]  |=  myResolution;
+
+    // Hater
+    cmd[1]  &= ~SI7021_HTRE_MASK;
+    cmd[1]  |=  myHeater;
+
+
+
+    // Update USER REGISTER
+    cmd[0]   =   SI7021_WRITE_RH_T_USER_REGISTER_1;
+    aux      =   _i2c.write ( _SI7021_Addr, &cmd[0], 2, false );
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_SoftReset ( void )
+ *
+ * @details     It resets the device by software.
+ *
+ * @param[in]    N/A
+ *
+ * @param[out]   N/A.
+ *
+ *
+ * @return       Status of SI7021_SoftReset.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         N/A
+ * @warning     The user MUST keep in mind that the device will be
+ *              available after 5ms ( typically, 15ms maximum )
+ *              The user MUST take care of this delay!.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_SoftReset ( void )
+{
+    char      cmd    =    SI7021_RESET;
+    uint32_t  aux    =    0;
+
+
+    aux      =   _i2c.write ( _SI7021_Addr, &cmd, 1, false );
+
+    // The user needs to wait for certain period of time before communicating
+    // with the device again.
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_GetElectronicSerialNumber ( SI7021_vector_data_t* )
+ *
+ * @details     It gets the electronic serial number.
+ *
+ * @param[in]    N/A
+ *
+ * @param[out]   mySerialNumber:     The Electronic Serial Number.
+ *
+ *
+ * @return       Status of SI7021_GetElectronicSerialNumber.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         This function does NOT check the CRC
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_GetElectronicSerialNumber   ( SI7021_vector_data_t* mySerialNumber )
+{
+    char      cmd[]    =    { SI7021_READ_ELECTRONIC_ID_FIRST_BYTE_CMD1, SI7021_READ_ELECTRONIC_ID_FIRST_BYTE_CMD2, 0, 0, 0, 0, 0, 0 };
+    uint32_t  aux      =    0;
+
+
+    // Read Electronic Serial Number. First Access
+    aux = _i2c.write ( _SI7021_Addr, &cmd[0], 2, true );
+    aux = _i2c.read  ( _SI7021_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
+
+
+    mySerialNumber->ElectronicSerialNumber_MSB   =   ( ( cmd[0] << 24 ) | ( cmd[2] << 16 ) | ( cmd[4] << 8 ) | cmd[6] );
+
+
+    // Read Electronic Serial Number. Second Access
+    cmd[0]   =   SI7021_READ_ELECTRONIC_ID_SECOND_BYTE_CMD1;
+    cmd[1]   =   SI7021_READ_ELECTRONIC_ID_SECOND_BYTE_CMD2;
+
+    aux = _i2c.write ( _SI7021_Addr, &cmd[0], 2, true );
+    aux = _i2c.read  ( _SI7021_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
+
+
+    mySerialNumber->ElectronicSerialNumber_LSB   =   ( ( cmd[0] << 24 ) | ( cmd[2] << 16 ) | ( cmd[4] << 8 ) | cmd[6] );
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_GetFirmwareRevision ( SI7021_vector_data_t* )
+ *
+ * @details     It gets the firmware revision.
+ *
+ * @param[in]    N/A
+ *
+ * @param[out]   myFirmwareRevision: The firmware revision.
+ *
+ *
+ * @return       Status of SI7021_GetFirmwareRevision.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         N/A.
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_GetFirmwareRevision ( SI7021_vector_data_t* myFirmwareRevision )
+{
+    char      cmd[]    =    { SI7021_READ_FIRMWARE_VERSION_CMD1, SI7021_READ_FIRMWARE_VERSION_CMD2 };
+    uint32_t  aux      =    0;
+
+
+    // Read the firmware revision
+    aux = _i2c.write ( _SI7021_Addr, &cmd[0], 2, true );
+    aux = _i2c.read  ( _SI7021_Addr, &cmd[0], 1 );
+
+
+    myFirmwareRevision->FirmwareRevision   =   cmd[0];
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_SetHeaterCurrent ( char )
+ *
+ * @details     It sets the heater current.
+ *
+ * @param[in]    myHeaterCurrent:   New heater current value
+ *
+ * @param[out]   N/A.
+ *
+ *
+ * @return       Status of SI7021_SetHeaterCurrent.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         N/A.
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_SetHeaterCurrent ( char myHeaterCurrent )
+{
+    char      cmd[]    =    { SI7021_READ_HEATER_CONTROL_REGISTER, 0 };
+    uint32_t  aux      =    0;
+
+    
+    // myHeaterCurrent MUST be from 0 ( 0x00 ) to 15 ( 0x0F )
+    if ( myHeaterCurrent <= 15 ) {
+        // Read the heater control register
+        aux = _i2c.write ( _SI7021_Addr, &cmd[0], 1, true );
+        aux = _i2c.read  ( _SI7021_Addr, &cmd[1], 1 );
+
+
+        // Mask the data
+        cmd[1]  &=  0xF0;
+
+        // Update the value
+        cmd[0]  =   SI7021_WRITE_HEATER_CONTROL_REGISTER;
+        cmd[1] |=   myHeaterCurrent;
+
+
+        aux = _i2c.write ( _SI7021_Addr, &cmd[0], 2, false );
+    } else
+        return   SI7021_FAILURE;
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_TriggerTemperature ( SI7021_master_mode_t )
+ *
+ * @details     It performs a new temperature measurement.
+ *
+ * @param[in]    myMode:             HOLD/NO HOLD mode.
+ *
+ * @param[out]   N/A
+ *
+ *
+ * @return       Status of SI7021_TriggerTemperature.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         N/A.
+ * @warning     The user MUST respect the total conversion time.
+ *              14-bit temperature: 7ms   ( 10.8ms max )
+ *              13-bit temperature: 4ms   (  6.2ms max )
+ *              12-bit temperature: 2.4ms (  3.8ms max )
+ *              11-bit temperature: 1.5ms (  2.4ms max )
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_TriggerTemperature ( SI7021_master_mode_t myMode  )
+{
+    char         cmd        =    0;
+    bool         myI2C_stop =    false;
+    uint32_t     aux        =    0;
+
+
+
+    // Check the mode if it is HOLD MASTER MODE, then not generate a stop bit
+    if ( myMode == SI7021_HOLD_MASTER_MODE ) {
+        cmd         =    SI7021_MEASURE_TEMPERATURE_HOLD_MASTER_MODE;
+        myI2C_stop  =    true;
+    } else {
+        cmd         =    SI7021_MEASURE_TEMPERATURE_NO_HOLD_MASTER_MODE;
+        myI2C_stop  =    false;
+    }
+
+
+
+    aux = _i2c.write ( _SI7021_Addr, &cmd, 1, myI2C_stop );
+
+
+    // NOTE: The user has to respect the total conversion time!
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_ReadTemperature ( SI7021_vector_data_t* )
+ *
+ * @details     It reads the temperature.
+ *
+ * @param[in]    myMode:             HOLD/NO HOLD mode.
+ *
+ * @param[out]   myTemperature:      The current temperature
+ *
+ *
+ * @return       Status of SI7021_ReadTemperature.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         SI7021_TriggerTemperature MUST be called first. This function does NOT
+ *              read CRC byte.
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_ReadTemperature ( SI7021_vector_data_t* myTemperature )
+{
+    char      cmd[]      =    { 0, 0 };
+    uint32_t  aux        =    0;
+
+
+
+
+    aux = _i2c.read ( _SI7021_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
+
+
+    // Check if the is a valid data
+    if ( ( cmd[1] & 0x02 )  ==  0x00 ) {
+        // Parse the data
+        myTemperature->Temperature   =   ( ( cmd[0] << 8 ) | cmd[1] );
+        myTemperature->Temperature  *=   175.72;
+        myTemperature->Temperature  /=   65536.0;
+        myTemperature->Temperature  -=   46.85;
+    } else
+        return   SI7021_FAILURE;
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_ReadRawTemperatureFromRH ( SI7021_vector_data_t* )
+ *
+ * @details     It reads the raw temperature.
+ *
+ * @param[in]    N/A.
+ *
+ * @param[out]   myTemperature:      The current temperature
+ *
+ *
+ * @return       Status of SI7021_ReadRawTemperatureFromRH.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         SI7021_TriggerHumidity MUST be called first.
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_ReadRawTemperatureFromRH ( SI7021_vector_data_t* myTemperature )
+{
+    char      cmd[]      =    { SI7021_READ_TEMPERATURE_VALUE_FROM_PREVIOUS_RH_MEASUREMENT, 0 };
+    uint32_t  aux        =    0;
+
+
+
+    aux = _i2c.write ( _SI7021_Addr, &cmd[0], 1, true );
+    aux = _i2c.read  ( _SI7021_Addr, &cmd[0], 2 );
+
+
+    // Check if the is a valid data
+    if ( ( cmd[1] & 0x02 )  ==  0x00 ) {
+        // Parse the data
+        myTemperature->Temperature   =   ( ( cmd[0] << 8 ) | cmd[1] );
+    } else
+        return   SI7021_FAILURE;
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_ReadTemperatureFromRH ( SI7021_vector_data_t* )
+ *
+ * @details     It reads the temperature.
+ *
+ * @param[in]    N/A.
+ *
+ * @param[out]   myTemperature:      The current temperature
+ *
+ *
+ * @return       Status of SI7021_ReadTemperatureFromRH.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         SI7021_TriggerHumidity MUST be called first.
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_ReadTemperatureFromRH ( SI7021_vector_data_t* myTemperature )
+{
+    char      cmd[]      =    { SI7021_READ_TEMPERATURE_VALUE_FROM_PREVIOUS_RH_MEASUREMENT, 0 };
+    uint32_t  aux        =    0;
+
+
+
+    aux = _i2c.write ( _SI7021_Addr, &cmd[0], 1, true );
+    aux = _i2c.read  ( _SI7021_Addr, &cmd[0], 2 );
+
+
+    // Check if the is a valid data
+    if ( ( cmd[1] & 0x02 )  ==  0x00 ) {
+        // Parse the data
+        myTemperature->Temperature   =   ( ( cmd[0] << 8 ) | cmd[1] );
+        myTemperature->Temperature  *=   175.72;
+        myTemperature->Temperature  /=   65536.0;
+        myTemperature->Temperature  -=   46.85;
+    } else
+        return   SI7021_FAILURE;
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_TriggerHumidity ( SI7021_master_mode_t )
+ *
+ * @details     It performs a new relative humidity measurement.
+ *
+ * @param[in]    myMode:             HOLD/NO HOLD MASTER mode.
+ *
+ * @param[out]   N/A
+ *
+ *
+ * @return       Status of SI7021_TriggerHumidity.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         Initiating a RH measurement will also automatically initiate a temperature measurement.
+ *              The total conversion time will be tCONV(RH) + tCONV(T).
+ * @warning     The user MUST respect the total conversion time.
+ *              12-bit RH: 10ms   ( 12ms max )
+ *              11-bit RH: 5.8ms  (  7ms max )
+ *              10-bit RH: 3.7ms  (  4.5ms max )
+ *               8-bit RH: 2.6ms  (  3.1ms max )
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_TriggerHumidity ( SI7021_master_mode_t myMode )
+{
+    char         cmd        =    myMode;
+    uint32_t     aux        =    0;
+    bool         myI2C_stop =    false;
+
+
+
+    // Check the mode if it is HOLD MASTER MODE, then not generate a stop bit
+    if ( myMode == SI7021_HOLD_MASTER_MODE ) {
+        cmd         =    SI7021_MEASURE_RELATIVE_HUMIDITY_HOLD_MASTER_MODE;
+        myI2C_stop  =    true;
+    } else {
+        cmd         =    SI7021_MEASURE_RELATIVE_HUMIDITY_NO_HOLD_MASTER_MODE;
+        myI2C_stop  =    false;
+    }
+
+
+    aux = _i2c.write ( _SI7021_Addr, &cmd, 1, myI2C_stop );
+
+
+    // NOTE: The user has to respect the total conversion time!
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_ReadHumidity ( SI7021_vector_data_t* )
+ *
+ * @details     It reads the relative humidity.
+ *
+ * @param[in]    N/A.
+ *
+ * @param[out]   myHumidity:         The current HUMIDITY
+ *
+ *
+ * @return       Status of SI7021_ReadHumidity.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         SI7021_TriggerHumidity MUST be called first. This function does NOT
+ *              read CRC byte.
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_ReadHumidity ( SI7021_vector_data_t* myHumidity )
+{
+    char      cmd[]      =    { 0, 0 };
+    uint32_t  aux        =    0;
+
+
+
+    aux = _i2c.read ( _SI7021_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
+
+
+    // Check if the is a valid data
+    if ( ( cmd[1] & 0x03 )  ==  0x02 ) {
+        // Parse the data
+        myHumidity->RelativeHumidity   =   ( ( cmd[0] << 8 ) | cmd[1] );
+        myHumidity->RelativeHumidity  *=   125.0;
+        myHumidity->RelativeHumidity  /=   65536.0;
+        myHumidity->RelativeHumidity  -=   6.0;
+    } else
+        return   SI7021_FAILURE;
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_ReadRawHumidity ( SI7021_vector_data_t* )
+ *
+ * @details     It reads the raw relative humidity.
+ *
+ * @param[in]    N/A.
+ *
+ * @param[out]   myHumidity:         The current HUMIDITY
+ *
+ *
+ * @return       Status of SI7021_ReadRawHumidity.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         SI7021_TriggerHumidity MUST be called first. This function does NOT
+ *              read CRC byte.
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_ReadRawHumidity ( SI7021_vector_data_t* myHumidity )
+{
+    char      cmd[]      =    { 0, 0 };
+    uint32_t  aux        =    0;
+
+
+
+    aux = _i2c.read ( _SI7021_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
+
+
+    // Check if the is a valid data
+    if ( ( cmd[1] & 0x03 )  ==  0x02 ) {
+        // Parse the data
+        myHumidity->RelativeHumidity   =   ( ( cmd[0] << 8 ) | cmd[1] );
+    } else
+        return   SI7021_FAILURE;
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}
+
+
+
+/**
+ * @brief       SI7021_GetBatteryStatus ( SI7021_vector_data_t* )
+ *
+ * @details     It reads the raw relative humidity.
+ *
+ * @param[in]    N/A.
+ *
+ * @param[out]   myBatteryStatus:   The current battery status
+ *
+ *
+ * @return       Status of SI7021_GetBatteryStatus.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        5/February/2018
+ * @version     5/February/2018   The ORIGIN
+ * @pre         N/A.
+ * @warning     N/A.
+ */
+SI7021::SI7021_status_t  SI7021::SI7021_GetBatteryStatus ( SI7021_vector_data_t* myBatteryStatus )
+{
+    char      cmd      =    SI7021_READ_RH_T_USER_REGISTER_1;
+    uint32_t  aux        =    0;
+
+
+    aux = _i2c.write ( _SI7021_Addr, &cmd, 1, true );
+    aux = _i2c.read  ( _SI7021_Addr, &cmd, 1 );
+
+
+    myBatteryStatus->BatteryStatus   =   ( SI7021_vdds_status_t )( cmd & SI7021_VDDS_STATUS_MASK );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   SI7021_SUCCESS;
+    else
+        return   SI7021_FAILURE;
+}