±0.5°C Maximum Accuracy Digital Temperature Sensor
Dependents: mbed-os5-F303-18650-Manager-tp4056
MCP9808.cpp
- Committer:
- mcm
- Date:
- 2019-04-25
- Revision:
- 3:54515d036e93
- Parent:
- 2:da266f1b2273
File content as of revision 3:54515d036e93:
/** * @brief MCP9808.cpp * @details ±0.5°C Maximum Accuracy Digital Temperature Sensor. * Function file. * * * @return N/A * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre N/A. * @warning N/A * @pre This code belongs to AqueronteBlog ( http://unbarquero.blogspot.com ). All rights reserved. */ #include "MCP9808.h" MCP9808::MCP9808 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq ) : _i2c ( sda, scl ) , _MCP9808_Addr ( addr ) { _i2c.frequency( freq ); } MCP9808::~MCP9808() { } /** * @brief MCP9808_GetCONFIG ( MCP9808_config_reg_t* ) * * @details It gets CONFIG register value. * * @param[in] N/A. * * @param[out] myCONFIG: CONFIG register value. * * * @return Status of MCP9808_GetCONFIG. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre N/A * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_GetCONFIG ( MCP9808_config_reg_t* myCONFIG ) { char cmd[2] = { 0U }; uint16_t myConfigAux = 0U; uint32_t aux; /* Read the register */ cmd[0] = MCP9808_CONFIG; aux = _i2c.write ( _MCP9808_Addr, &cmd[0], 1U, true ); aux = _i2c.read ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) ); /* Mask it and update it with the new value */ myConfigAux = cmd[0]; myConfigAux <<= 8U; myConfigAux |= cmd[1]; myCONFIG->t_hyst = (MCP9808_config_thyst_t)( myConfigAux & CONFIG_T_HYST_MASK ); myCONFIG->shdn = (MCP9808_config_shdn_t)( myConfigAux & CONFIG_SHDN_MASK ); myCONFIG->t_crit = (MCP9808_config_crit_lock_t)( myConfigAux & CONFIG_CRIT_LOCK_MASK ); myCONFIG->t_win_lock = (MCP9808_config_win_lock_t)( myConfigAux & CONFIG_WIN_LOCK_MASK ); myCONFIG->int_clear = (MCP9808_conf_int_clear_t)( myConfigAux & CONFIG_INT_CLEAR_MASK ); myCONFIG->alert_stat = (MCP9808_config_alert_stat_t)( myConfigAux & CONFIG_ALERT_STAT_MASK ); myCONFIG->alert_cnt = (MCP9808_config_alert_cnt_t)( myConfigAux & CONFIG_ALERT_CNT_MASK ); myCONFIG->alert_sel = (MCP9808_config_alert_sel_t)( myConfigAux & CONFIG_ALERT_SEL_MASK ); myCONFIG->alert_pol = (MCP9808_config_alert_pol_t)( myConfigAux & CONFIG_ALERT_POL_MASK ); myCONFIG->alert_mod = (MCP9808_config_alert_mod_t)( myConfigAux & CONFIG_ALERT_MOD_MASK ); if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } /** * @brief MCP9808_SetCONFIG ( MCP9808_config_reg_t ) * * @details It sets CONFIG register value. * * @param[in] myCONFIG: CONFIG register value. * * @param[out] N/A. * * * @return Status of MCP9808_SetCONFIG. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre MCP9808_GetCONFIG function should be called first to mask the bits. * @warning Be aware that some commands can NOT be written depending on Crit.Lock and/or Win.Lock values. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_SetCONFIG ( MCP9808_config_reg_t myCONFIG ) { char cmd[3] = { 0U }; uint16_t myConfigAux = 0U; uint32_t aux; /* Update CONFI register */ myConfigAux = ( myCONFIG.t_hyst | myCONFIG.shdn | myCONFIG.t_crit | myCONFIG.t_win_lock | myCONFIG.int_clear | myCONFIG.alert_stat | myCONFIG.alert_cnt | myCONFIG.alert_sel | myCONFIG.alert_pol | myCONFIG.alert_mod ); cmd[0] = MCP9808_CONFIG; cmd[1] = (uint8_t)( myConfigAux >> 8U ); cmd[2] = (uint8_t)( myConfigAux & 0xFF ); aux = _i2c.write ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false ); if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } /** * @brief MCP9808_GetRawTA ( MCP9808_data_t* ) * * @details It gets ambient temperature register ( raw value ). * * @param[in] N/A * * @param[out] myRawTA: Raw T_A data. * * * @return Status of MCP9808_GetRawTA. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre N/A * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_GetRawTA ( MCP9808_data_t* myRawTA ) { char cmd[2] = { 0U }; uint32_t aux; /* Read the register */ cmd[0] = MCP9808_TA; aux = _i2c.write ( _MCP9808_Addr, &cmd[0], 1U, true ); aux = _i2c.read ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) ); /* Mask it and update it with the new value */ myRawTA->t_a_raw = cmd[0]; myRawTA->t_a_raw <<= 8U; myRawTA->t_a_raw |= cmd[1]; if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } /** * @brief MCP9808_GetTA ( MCP9808_data_t* ) * * @details It gets ambient temperature register ( Celsius degrees ). * * @param[in] N/A * * @param[out] myTA: T_A value and flags. * * * @return Status of MCP9808_GetTA. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre This function also updates the comparison flags. * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_GetTA ( MCP9808_data_t* myTA ) { uint8_t myUpperByte = 0U; uint8_t myLowerByte = 0U; MCP9808::MCP9808_status_t aux; /* Read the register */ aux = MCP9808::MCP9808_GetRawTA ( &(*myTA) ); /* Mask it and update it with the new value */ /* Mask the flags */ myTA->ta_vs_tcrit = (MCP9808_t_a_ta_vs_tcrit_t)( myTA->t_a_raw & T_A_TA_VS_TCRIT_MASK ); myTA->ta_vs_tupper = (MCP9808_t_a_ta_vs_tupper_t)( myTA->t_a_raw & T_A_TA_VS_TUPPER_MASK ); myTA->t_lower = (MCP9808_t_a_ta_vs_tlower_t)( myTA->t_a_raw & T_A_TA_VS_TLOWER_MASK ); myTA->t_a_sign = (MCP9808_t_a_sign_t)( myTA->t_a_raw & T_A_TA_SIGN_MASK ); /* Mask the ambient temperature value */ myUpperByte = (uint8_t)( myTA->t_a_raw >> 8U ); myLowerByte = (uint8_t)( myTA->t_a_raw & 0xFF ); /* Clean the flags */ myUpperByte &= ~(uint8_t)( ( T_A_TA_VS_TCRIT_MASK | T_A_TA_VS_TUPPER_MASK | T_A_TA_VS_TLOWER_MASK ) >> 8U ); /* Check if T_A is negative/positive */ if ( myTA->t_a_sign == T_A_TA_SIGN_NEGATIVE ) { /* Ambient uint8_t is NEGATIVE */ myUpperByte &= ~(uint8_t)( T_A_TA_SIGN_MASK >> 8U ); // Clear the SIGN flag myTA->t_a = 256.0f - (float)( ( myUpperByte * 16.0f ) + ( myLowerByte / 16.0f ) ); // Ambient temperature value } else { /* Ambient temperature is POSITIVE */ myTA->t_a = (float)( ( myUpperByte * 16.0f ) + ( myLowerByte / 16.0f ) ); // Ambient temperature value } return aux; } /** * @brief MCP9808_GetManufacturerID ( MCP9808_data_t* ) * * @details It gets manufacturer ID. * * @param[in] N/A. * * @param[out] myManufacturerID: Manufacturer ID code * * * @return Status of MCP9808_GetManufacturerID. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre It should be 0x0054 ( hexadecimal ). * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_GetManufacturerID ( MCP9808_data_t* myManufacturerID ) { char cmd[2] = { 0U }; uint32_t aux; /* Read the register */ cmd[0] = MCP9808_MANUFACTURER_ID; aux = _i2c.write ( _MCP9808_Addr, &cmd[0], 1U, true ); aux = _i2c.read ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) ); /* Mask it and update it with the new value */ myManufacturerID->manufacturerID = cmd[0]; myManufacturerID->manufacturerID <<= 8U; myManufacturerID->manufacturerID |= cmd[1]; if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } /** * @brief MCP9808_GetDeviceID ( MCP9808_data_t* ) * * @details It gets device ID and device revision. * * @param[in] N/A * * @param[out] myDeviceID: Both device ID and device revision * * * @return Status of MCP9808_GetDeviceID. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre Device ID should be 0x04 ( hexadecimal ). * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_GetDeviceID ( MCP9808_data_t* myDeviceID ) { char cmd[2] = { 0U }; uint32_t aux; /* Read the register */ cmd[0] = MCP9808_DEVICE_ID; aux = _i2c.write ( _MCP9808_Addr, &cmd[0], 1U, true ); aux = _i2c.read ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) ); /* Mask it and update it with the new value */ myDeviceID->deviceID = cmd[0]; myDeviceID->deviceRevision = cmd[1]; if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } /** * @brief MCP9808_SetResolution ( MCP9808_data_t ) * * @details It sets the sensor resolution. * * @param[in] myResolution: Device resolution. * * @param[out] N/A * * * @return Status of MCP9808_SetResolution. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre Resolution vs timing conversion: * · Resolution: +0.5°C ( t_CONV = 30ms typical ) * · Resolution: +0.25°C ( t_CONV = 65ms typical ) * · Resolution: +0.125°C ( t_CONV = 130ms typical ) * · Resolution: +0.0625°C ( power-up default, t_CONV = 250ms typical ) * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_SetResolution ( MCP9808_data_t myResolution ) { char cmd[2] = { 0U }; uint32_t aux; /* Read the register */ cmd[0] = MCP9808_RESOLUTION; cmd[1] = myResolution.resolution; aux = _i2c.write ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false ); if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } /** * @brief MCP9808_GetResolution ( MCP9808_data_t* ) * * @details It gets the sensor resolution. * * @param[in] N/A. * * @param[out] myResolution: Device resolution. * * * @return Status of MCP9808_GetResolution. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre Resolution vs timing conversion: * · Resolution: +0.5°C ( t_CONV = 30ms typical ) * · Resolution: +0.25°C ( t_CONV = 65ms typical ) * · Resolution: +0.125°C ( t_CONV = 130ms typical ) * · Resolution: +0.0625°C ( power-up default, t_CONV = 250ms typical ) * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_GetResolution ( MCP9808_data_t* myResolution ) { char cmd = 0U; uint32_t aux; /* Read the register */ cmd = MCP9808_RESOLUTION; aux = _i2c.write ( _MCP9808_Addr, &cmd, 1U, true ); aux = _i2c.read ( _MCP9808_Addr, &cmd, 1U ); /* Mask it and update it with the new value */ myResolution->resolution = (MCP9808_resolution_t)cmd; if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } /** * @brief MCP9808_SetT_Limit ( MCP9808_registers_t, MCP9808_data_t ) * * @details It sets temperature limit for: T_UPPER, T_LOWER or T_CRIT. * * @param[in] myTLimit: Temperature limit register: T_UPPER, T_LOWER or T_CRIT. * @param[in] myTValue_Limit: Temperature limit value. * * @param[out] N/A. * * * @return Status of MCP9808_SetT_Limit. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre N/A. * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_SetT_Limit ( MCP9808_registers_t myTLimit, MCP9808_data_t myTValue_Limit ) { char cmd[2] = { 0U }; int8_t myDecimal = 0U; int8_t myIntegral = 0U; uint32_t aux; /* Only temperature limit registers can keep going */ if ( ( myTLimit != MCP9808_TUPPER ) || ( myTLimit != MCP9808_TLOWER ) || ( myTLimit != MCP9808_TCRIT ) ) { return MCP9808_FAILURE; } else { /* Parse the data */ myIntegral = (int8_t)myTValue_Limit.t_upper; myDecimal = (uint8_t)( ( myTValue_Limit.t_upper - myIntegral ) * 100.0f ); /* Check the decimal part is correct; Valid decimal values: 0.00, 0.25, 0.50 or 0.75 */ myIntegral <<= 4U; myDecimal <<= 2U; if( ( myDecimal != TEMPERATURE_LIMIT_DECIMAL_PART_0_00C ) || ( myDecimal != TEMPERATURE_LIMIT_DECIMAL_PART_0_25C ) || ( myDecimal != TEMPERATURE_LIMIT_DECIMAL_PART_0_50C ) || ( myDecimal != TEMPERATURE_LIMIT_DECIMAL_PART_0_50C ) ) { return MCP9808_FAILURE; } else { /* Update the register with the new value */ cmd[0] = myTLimit; cmd[1] = ( myIntegral | myDecimal ); aux = _i2c.write ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false ); if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } } } /** * @brief MCP9808_GetT_Limit ( MCP9808_registers_t, MCP9808_data_t* ) * * @details It gets temperature limit for: T_UPPER, T_LOWER or T_CRIT. * * @param[in] myTLimit: Temperature limit register: T_UPPER, T_LOWER or T_CRIT. * * @param[out] myTValue_Limit: Temperature limit value for the chosen register. * * * @return Status of MCP9808_GetT_Limit. * * * @author Manuel Caballero * @date 25/April/2019 * @version 25/April/2019 The ORIGIN * @pre N/A. * @warning N/A. */ MCP9808::MCP9808_status_t MCP9808::MCP9808_GetT_Limit ( MCP9808_registers_t myTLimit, MCP9808_data_t* myTValue_Limit ) { char cmd = 0U; uint8_t myDecimal = 0U; float myAuxValue = 0U; uint32_t aux; /* Only temperature limit registers can keep going */ if ( ( myTLimit != MCP9808_TUPPER ) || ( myTLimit != MCP9808_TLOWER ) || ( myTLimit != MCP9808_TCRIT ) ) { return MCP9808_FAILURE; } else { /* Read the register */ cmd = myTLimit; aux = _i2c.write ( _MCP9808_Addr, &cmd, 1U, true ); aux = _i2c.read ( _MCP9808_Addr, &cmd, 1U ); /* Process the data */ myAuxValue = (float)( ( cmd & TEMPERATURE_LIMIT_INTEGRAL_PART_MASK ) >> 4U ); myDecimal = ( ( cmd & TEMPERATURE_LIMIT_DECIMAL_PART_MASK ) >> 2U ); /* Process the decimal part */ for( cmd = ( TEMPERATURE_LIMIT_DECIMAL_PART_0_00C >> 2U ); cmd < myDecimal; cmd++ ) { myAuxValue += 0.25f; } /* Parse the data */ switch( myTLimit ) { case MCP9808_TUPPER: myTValue_Limit->t_upper = (float)myAuxValue; break; case MCP9808_TLOWER: myTValue_Limit->t_lower = (float)myAuxValue; break; case MCP9808_TCRIT: myTValue_Limit->t_crit = (float)myAuxValue; break; default: return MCP9808_FAILURE; } if ( aux == I2C_SUCCESS ) { return MCP9808_SUCCESS; } else { return MCP9808_FAILURE; } } }