Manuel Caballero / MCP9808

Dependents:   mbed-os5-F303-18650-Manager-tp4056

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MCP9808.cpp Source File

MCP9808.cpp

00001 /**
00002  * @brief       MCP9808.cpp
00003  * @details     ±0.5°C Maximum Accuracy Digital Temperature Sensor.
00004  *              Function file.
00005  *
00006  *
00007  * @return      N/A
00008  *
00009  * @author      Manuel Caballero
00010  * @date        25/April/2019
00011  * @version     25/April/2019    The ORIGIN
00012  * @pre         N/A.
00013  * @warning     N/A
00014  * @pre         This code belongs to AqueronteBlog ( http://unbarquero.blogspot.com ). All rights reserved.
00015  */
00016 
00017 #include "MCP9808.h"
00018 
00019 
00020 MCP9808::MCP9808 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq )
00021     : _i2c           ( sda, scl )
00022     , _MCP9808_Addr ( addr )
00023 {
00024     _i2c.frequency( freq );
00025 }
00026 
00027 
00028 MCP9808::~MCP9808()
00029 {
00030 }
00031 
00032 
00033 
00034 /**
00035  * @brief       MCP9808_GetCONFIG ( MCP9808_config_reg_t* )
00036  *
00037  * @details     It gets CONFIG register value.
00038  *
00039  * @param[in]    N/A.
00040  *
00041  * @param[out]   myCONFIG: CONFIG register value.
00042  *
00043  *
00044  * @return       Status of MCP9808_GetCONFIG.
00045  *
00046  *
00047  * @author      Manuel Caballero
00048  * @date        25/April/2019
00049  * @version     25/April/2019     The ORIGIN
00050  * @pre         N/A
00051  * @warning     N/A.
00052  */
00053 MCP9808::MCP9808_status_t MCP9808::MCP9808_GetCONFIG ( MCP9808_config_reg_t* myCONFIG )
00054 {
00055   char      cmd[2]       = { 0U };
00056   uint16_t  myConfigAux  = 0U;
00057   uint32_t  aux;
00058 
00059   /* Read the register   */
00060   cmd[0]   =   MCP9808_CONFIG ;
00061   aux      =   _i2c.write ( _MCP9808_Addr, &cmd[0], 1U, true );
00062   aux      =   _i2c.read  ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
00063 
00064   /* Mask it and update it with the new value  */
00065   myConfigAux   =   cmd[0];
00066   myConfigAux <<=   8U;
00067   myConfigAux  |=   cmd[1];
00068 
00069   myCONFIG->t_hyst       =   (MCP9808_config_thyst_t)( myConfigAux & CONFIG_T_HYST_MASK  );
00070   myCONFIG->shdn         =   (MCP9808_config_shdn_t )( myConfigAux & CONFIG_SHDN_MASK  );
00071   myCONFIG->t_crit       =   (MCP9808_config_crit_lock_t )( myConfigAux & CONFIG_CRIT_LOCK_MASK  );
00072   myCONFIG->t_win_lock   =   (MCP9808_config_win_lock_t )( myConfigAux & CONFIG_WIN_LOCK_MASK  );
00073   myCONFIG->int_clear    =   (MCP9808_conf_int_clear_t )( myConfigAux & CONFIG_INT_CLEAR_MASK  );
00074   myCONFIG->alert_stat   =   (MCP9808_config_alert_stat_t )( myConfigAux & CONFIG_ALERT_STAT_MASK  );
00075   myCONFIG->alert_cnt    =   (MCP9808_config_alert_cnt_t )( myConfigAux & CONFIG_ALERT_CNT_MASK  );
00076   myCONFIG->alert_sel    =   (MCP9808_config_alert_sel_t )( myConfigAux & CONFIG_ALERT_SEL_MASK  );
00077   myCONFIG->alert_pol    =   (MCP9808_config_alert_pol_t )( myConfigAux & CONFIG_ALERT_POL_MASK  );
00078   myCONFIG->alert_mod    =   (MCP9808_config_alert_mod_t )( myConfigAux & CONFIG_ALERT_MOD_MASK  );
00079 
00080 
00081 
00082   if ( aux == I2C_SUCCESS  )
00083   {
00084     return   MCP9808_SUCCESS;
00085   }
00086   else
00087   {
00088     return   MCP9808_FAILURE;
00089   }
00090 }
00091 
00092 
00093 
00094 /**
00095  * @brief       MCP9808_SetCONFIG ( MCP9808_config_reg_t )
00096  *
00097  * @details     It sets CONFIG register value.
00098  *
00099  * @param[in]    myCONFIG: CONFIG register value.
00100  *
00101  * @param[out]   N/A.
00102  *
00103  *
00104  * @return       Status of MCP9808_SetCONFIG.
00105  *
00106  *
00107  * @author      Manuel Caballero
00108  * @date        25/April/2019
00109  * @version     25/April/2019     The ORIGIN
00110  * @pre         MCP9808_GetCONFIG function should be called first to mask the bits.
00111  * @warning     Be aware that some commands can NOT be written depending on Crit.Lock and/or Win.Lock values.
00112  */
00113 MCP9808::MCP9808_status_t MCP9808::MCP9808_SetCONFIG ( MCP9808_config_reg_t myCONFIG )
00114 {
00115   char      cmd[3]       = { 0U };
00116   uint16_t  myConfigAux  = 0U;
00117   uint32_t  aux;
00118 
00119   /* Update CONFI register  */
00120   myConfigAux   =   ( myCONFIG.t_hyst | myCONFIG.shdn | myCONFIG.t_crit | myCONFIG.t_win_lock | myCONFIG.int_clear |
00121                       myCONFIG.alert_stat | myCONFIG.alert_cnt | myCONFIG.alert_sel | myCONFIG.alert_pol | myCONFIG.alert_mod );
00122   
00123   cmd[0]   =   MCP9808_CONFIG ;
00124   cmd[1]   =   (uint8_t)( myConfigAux >> 8U );
00125   cmd[2]   =   (uint8_t)( myConfigAux & 0xFF );
00126   aux      =   _i2c.write ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
00127 
00128 
00129 
00130 
00131   if ( aux == I2C_SUCCESS  )
00132   {
00133     return   MCP9808_SUCCESS;
00134   }
00135   else
00136   {
00137     return   MCP9808_FAILURE;
00138   }
00139 }
00140 
00141 
00142 
00143 /**
00144  * @brief       MCP9808_GetRawTA ( MCP9808_data_t* )
00145  *
00146  * @details     It gets ambient temperature register ( raw value ).
00147  *
00148  * @param[in]    N/A
00149  *
00150  * @param[out]   myRawTA: Raw T_A data.
00151  *
00152  *
00153  * @return       Status of MCP9808_GetRawTA.
00154  *
00155  *
00156  * @author      Manuel Caballero
00157  * @date        25/April/2019
00158  * @version     25/April/2019     The ORIGIN
00159  * @pre         N/A
00160  * @warning     N/A.
00161  */
00162 MCP9808::MCP9808_status_t MCP9808::MCP9808_GetRawTA ( MCP9808_data_t* myRawTA )
00163 {
00164   char     cmd[2]  = { 0U };
00165   uint32_t aux;
00166 
00167   /* Read the register   */
00168   cmd[0]   =   MCP9808_TA ;
00169   aux      =   _i2c.write ( _MCP9808_Addr, &cmd[0], 1U, true );
00170   aux      =   _i2c.read  ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
00171   
00172   /* Mask it and update it with the new value  */
00173   myRawTA->t_a_raw   =   cmd[0];
00174   myRawTA->t_a_raw <<=   8U;
00175   myRawTA->t_a_raw  |=   cmd[1];
00176 
00177 
00178 
00179 
00180   if ( aux == I2C_SUCCESS  )
00181   {
00182     return   MCP9808_SUCCESS;
00183   }
00184   else
00185   {
00186     return   MCP9808_FAILURE;
00187   }
00188 }
00189 
00190 
00191 
00192 /**
00193  * @brief       MCP9808_GetTA ( MCP9808_data_t* )
00194  *
00195  * @details     It gets ambient temperature register ( Celsius degrees ).
00196  *
00197  * @param[in]    N/A
00198  *
00199  * @param[out]   myTA: T_A value and flags.
00200  *
00201  *
00202  * @return       Status of MCP9808_GetTA.
00203  *
00204  *
00205  * @author      Manuel Caballero
00206  * @date        25/April/2019
00207  * @version     25/April/2019     The ORIGIN
00208  * @pre         This function also updates the comparison flags.
00209  * @warning     N/A.
00210  */
00211 MCP9808::MCP9808_status_t MCP9808::MCP9808_GetTA ( MCP9808_data_t* myTA )
00212 {
00213   uint8_t          myUpperByte   =   0U;
00214   uint8_t          myLowerByte   =   0U;
00215   MCP9808::MCP9808_status_t aux;
00216 
00217   /* Read the register   */
00218   aux  =   MCP9808::MCP9808_GetRawTA ( &(*myTA) );
00219   
00220   /* Mask it and update it with the new value  */
00221   /* Mask the flags  */
00222   myTA->ta_vs_tcrit  =   (MCP9808_t_a_ta_vs_tcrit_t)( myTA->t_a_raw & T_A_TA_VS_TCRIT_MASK  );
00223   myTA->ta_vs_tupper =   (MCP9808_t_a_ta_vs_tupper_t )( myTA->t_a_raw & T_A_TA_VS_TUPPER_MASK  );
00224   myTA->t_lower      =   (MCP9808_t_a_ta_vs_tlower_t )( myTA->t_a_raw & T_A_TA_VS_TLOWER_MASK  );
00225   myTA->t_a_sign     =   (MCP9808_t_a_sign_t )( myTA->t_a_raw & T_A_TA_SIGN_MASK  );
00226 
00227   /* Mask the ambient temperature value  */
00228   myUpperByte  =   (uint8_t)( myTA->t_a_raw >> 8U );
00229   myLowerByte  =   (uint8_t)( myTA->t_a_raw & 0xFF );
00230 
00231   /* Clean the flags   */
00232   myUpperByte &=  ~(uint8_t)( ( T_A_TA_VS_TCRIT_MASK  | T_A_TA_VS_TUPPER_MASK  | T_A_TA_VS_TLOWER_MASK  ) >> 8U );
00233   
00234   /* Check if T_A is negative/positive   */
00235   if ( myTA->t_a_sign == T_A_TA_SIGN_NEGATIVE  )
00236   {
00237     /* Ambient uint8_t is NEGATIVE   */
00238     myUpperByte &=  ~(uint8_t)( T_A_TA_SIGN_MASK  >> 8U );                                     // Clear the SIGN flag
00239     myTA->t_a    =   256.0f - (float)( ( myUpperByte * 16.0f ) + ( myLowerByte / 16.0f ) );   // Ambient temperature value
00240   }
00241   else
00242   {
00243     /* Ambient temperature is POSITIVE   */
00244     myTA->t_a    =   (float)( ( myUpperByte * 16.0f ) + ( myLowerByte / 16.0f ) );            // Ambient temperature value
00245   }
00246 
00247 
00248   return aux;
00249 }
00250 
00251 
00252 
00253 /**
00254  * @brief       MCP9808_GetManufacturerID ( MCP9808_data_t* )
00255  *
00256  * @details     It gets manufacturer ID.
00257  *
00258  * @param[in]    N/A.
00259  *
00260  * @param[out]   myManufacturerID:  Manufacturer ID code
00261  *
00262  *
00263  * @return       Status of MCP9808_GetManufacturerID.
00264  *
00265  *
00266  * @author      Manuel Caballero
00267  * @date        25/April/2019
00268  * @version     25/April/2019     The ORIGIN
00269  * @pre         It should be 0x0054 ( hexadecimal ).
00270  * @warning     N/A.
00271  */
00272 MCP9808::MCP9808_status_t MCP9808::MCP9808_GetManufacturerID ( MCP9808_data_t* myManufacturerID )
00273 {
00274   char     cmd[2]  = { 0U };
00275   uint32_t aux;
00276 
00277   /* Read the register   */
00278   cmd[0]   =   MCP9808_MANUFACTURER_ID ;
00279   aux      =   _i2c.write ( _MCP9808_Addr, &cmd[0], 1U, true );
00280   aux      =   _i2c.read  ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
00281   
00282   /* Mask it and update it with the new value  */
00283   myManufacturerID->manufacturerID   =   cmd[0];
00284   myManufacturerID->manufacturerID <<=   8U;
00285   myManufacturerID->manufacturerID  |=   cmd[1];
00286 
00287 
00288 
00289   if ( aux == I2C_SUCCESS  )
00290   {
00291     return   MCP9808_SUCCESS;
00292   }
00293   else
00294   {
00295     return   MCP9808_FAILURE;
00296   }
00297 }
00298 
00299 
00300 
00301 /**
00302  * @brief       MCP9808_GetDeviceID ( MCP9808_data_t* )
00303  *
00304  * @details     It gets device ID and device revision.
00305  *
00306  * @param[in]    N/A
00307  *
00308  * @param[out]   myDeviceID: Both device ID and device revision 
00309  *
00310  *
00311  * @return       Status of MCP9808_GetDeviceID.
00312  *
00313  *
00314  * @author      Manuel Caballero
00315  * @date        25/April/2019
00316  * @version     25/April/2019     The ORIGIN
00317  * @pre         Device ID should be 0x04 ( hexadecimal ).
00318  * @warning     N/A.
00319  */
00320 MCP9808::MCP9808_status_t MCP9808::MCP9808_GetDeviceID ( MCP9808_data_t* myDeviceID )
00321 {
00322   char     cmd[2]  = { 0U };
00323   uint32_t aux;
00324 
00325   /* Read the register   */
00326   cmd[0]   =   MCP9808_DEVICE_ID ;
00327   aux      =   _i2c.write ( _MCP9808_Addr, &cmd[0], 1U, true );
00328   aux      =   _i2c.read  ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );
00329   
00330   /* Mask it and update it with the new value  */
00331   myDeviceID->deviceID         =   cmd[0];
00332   myDeviceID->deviceRevision   =   cmd[1];
00333 
00334 
00335 
00336   if ( aux == I2C_SUCCESS  )
00337   {
00338     return   MCP9808_SUCCESS;
00339   }
00340   else
00341   {
00342     return   MCP9808_FAILURE;
00343   }
00344 }
00345 
00346 
00347 
00348 /**
00349  * @brief       MCP9808_SetResolution ( MCP9808_data_t )
00350  *
00351  * @details     It sets the sensor resolution.
00352  *
00353  * @param[in]    myResolution: Device resolution.
00354  *
00355  * @param[out]   N/A 
00356  *
00357  *
00358  * @return       Status of MCP9808_SetResolution.
00359  *
00360  *
00361  * @author      Manuel Caballero
00362  * @date        25/April/2019
00363  * @version     25/April/2019     The ORIGIN
00364  * @pre         Resolution vs timing conversion:
00365  *                · Resolution: +0.5°C    ( t_CONV = 30ms typical )
00366  *                · Resolution: +0.25°C   ( t_CONV = 65ms typical )
00367  *                · Resolution: +0.125°C  ( t_CONV = 130ms typical )
00368  *                · Resolution: +0.0625°C ( power-up default, t_CONV = 250ms typical )
00369  * @warning     N/A.
00370  */
00371 MCP9808::MCP9808_status_t MCP9808::MCP9808_SetResolution ( MCP9808_data_t myResolution )
00372 {
00373   char     cmd[2]  = { 0U };
00374   uint32_t aux;
00375 
00376   /* Read the register   */
00377   cmd[0]   =   MCP9808_RESOLUTION ;
00378   cmd[1]   =   myResolution.resolution;
00379   aux      =   _i2c.write ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
00380 
00381 
00382 
00383   if ( aux == I2C_SUCCESS  )
00384   {
00385     return   MCP9808_SUCCESS;
00386   }
00387   else
00388   {
00389     return   MCP9808_FAILURE;
00390   }
00391 }
00392 
00393 
00394 
00395 /**
00396  * @brief       MCP9808_GetResolution ( MCP9808_data_t* )
00397  *
00398  * @details     It gets the sensor resolution.
00399  *
00400  * @param[in]    N/A.
00401  *
00402  * @param[out]   myResolution: Device resolution. 
00403  *
00404  *
00405  * @return       Status of MCP9808_GetResolution.
00406  *
00407  *
00408  * @author      Manuel Caballero
00409  * @date        25/April/2019
00410  * @version     25/April/2019     The ORIGIN
00411  * @pre         Resolution vs timing conversion:
00412  *                · Resolution: +0.5°C    ( t_CONV = 30ms typical )
00413  *                · Resolution: +0.25°C   ( t_CONV = 65ms typical )
00414  *                · Resolution: +0.125°C  ( t_CONV = 130ms typical )
00415  *                · Resolution: +0.0625°C ( power-up default, t_CONV = 250ms typical )
00416  * @warning     N/A.
00417  */
00418 MCP9808::MCP9808_status_t MCP9808::MCP9808_GetResolution ( MCP9808_data_t* myResolution )
00419 {
00420   char     cmd  = 0U;
00421   uint32_t aux;
00422 
00423   /* Read the register   */
00424   cmd  =   MCP9808_RESOLUTION ;
00425   aux  =   _i2c.write ( _MCP9808_Addr, &cmd, 1U, true );
00426   aux  =   _i2c.read  ( _MCP9808_Addr, &cmd, 1U );
00427   
00428   /* Mask it and update it with the new value  */
00429   myResolution->resolution     =   (MCP9808_resolution_t)cmd;
00430 
00431 
00432 
00433   if ( aux == I2C_SUCCESS  )
00434   {
00435     return   MCP9808_SUCCESS;
00436   }
00437   else
00438   {
00439     return   MCP9808_FAILURE;
00440   }
00441 }
00442 
00443 
00444 
00445 /**
00446  * @brief       MCP9808_SetT_Limit ( MCP9808_registers_t, MCP9808_data_t )
00447  *
00448  * @details     It sets temperature limit for: T_UPPER, T_LOWER or T_CRIT.
00449  *
00450  * @param[in]    myTLimit:        Temperature limit register: T_UPPER, T_LOWER or T_CRIT.
00451  * @param[in]    myTValue_Limit:  Temperature limit value.
00452  *
00453  * @param[out]   N/A. 
00454  *
00455  *
00456  * @return       Status of MCP9808_SetT_Limit.
00457  *
00458  *
00459  * @author      Manuel Caballero
00460  * @date        25/April/2019
00461  * @version     25/April/2019     The ORIGIN
00462  * @pre         N/A.
00463  * @warning     N/A.
00464  */
00465 MCP9808::MCP9808_status_t MCP9808::MCP9808_SetT_Limit ( MCP9808_registers_t myTLimit, MCP9808_data_t myTValue_Limit )
00466 {
00467   char     cmd[2]     = { 0U };
00468   int8_t   myDecimal  = 0U;
00469   int8_t   myIntegral = 0U;
00470   uint32_t aux;
00471   
00472   /* Only temperature limit registers can keep going   */
00473   if ( ( myTLimit != MCP9808_TUPPER  ) || ( myTLimit != MCP9808_TLOWER  ) || ( myTLimit != MCP9808_TCRIT  ) )
00474   {
00475     return  MCP9808_FAILURE;
00476   }
00477   else
00478   {
00479     /* Parse the data  */
00480     myIntegral =   (int8_t)myTValue_Limit.t_upper;
00481     myDecimal  =   (uint8_t)( ( myTValue_Limit.t_upper - myIntegral ) * 100.0f );
00482   
00483     /* Check the decimal part is correct; Valid decimal values: 0.00, 0.25, 0.50 or 0.75   */
00484     myIntegral <<=  4U;
00485     myDecimal  <<=  2U;
00486     if( ( myDecimal != TEMPERATURE_LIMIT_DECIMAL_PART_0_00C  ) || ( myDecimal != TEMPERATURE_LIMIT_DECIMAL_PART_0_25C  ) || 
00487         ( myDecimal != TEMPERATURE_LIMIT_DECIMAL_PART_0_50C  ) || ( myDecimal != TEMPERATURE_LIMIT_DECIMAL_PART_0_50C  ) )
00488     {
00489       return  MCP9808_FAILURE;
00490     }
00491     else
00492     {
00493       /* Update the register with the new value  */
00494       cmd[0]  =   myTLimit;
00495       cmd[1]  =   ( myIntegral | myDecimal );
00496       aux     =   _i2c.write ( _MCP9808_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
00497   
00498 
00499       if ( aux == I2C_SUCCESS  )
00500       {
00501         return   MCP9808_SUCCESS;
00502       }
00503       else
00504       {
00505         return   MCP9808_FAILURE;
00506       }
00507     }
00508   }
00509 }
00510 
00511 
00512 
00513 /**
00514  * @brief       MCP9808_GetT_Limit ( MCP9808_registers_t, MCP9808_data_t* )
00515  *
00516  * @details     It gets temperature limit for: T_UPPER, T_LOWER or T_CRIT.
00517  *
00518  * @param[in]    myTLimit:        Temperature limit register: T_UPPER, T_LOWER or T_CRIT.
00519  *
00520  * @param[out]   myTValue_Limit:  Temperature limit value for the chosen register. 
00521  *
00522  *
00523  * @return       Status of MCP9808_GetT_Limit.
00524  *
00525  *
00526  * @author      Manuel Caballero
00527  * @date        25/April/2019
00528  * @version     25/April/2019     The ORIGIN
00529  * @pre         N/A.
00530  * @warning     N/A.
00531  */
00532 MCP9808::MCP9808_status_t MCP9808::MCP9808_GetT_Limit ( MCP9808_registers_t myTLimit, MCP9808_data_t* myTValue_Limit )
00533 {
00534   char     cmd        = 0U;
00535   uint8_t  myDecimal  = 0U;
00536   float    myAuxValue = 0U;
00537   uint32_t aux;
00538   
00539   /* Only temperature limit registers can keep going   */
00540   if ( ( myTLimit != MCP9808_TUPPER  ) || ( myTLimit != MCP9808_TLOWER  ) || ( myTLimit != MCP9808_TCRIT  ) )
00541   {
00542     return  MCP9808_FAILURE;
00543   }
00544   else
00545   {
00546     /* Read the register   */
00547     cmd  =   myTLimit;
00548     aux  =   _i2c.write ( _MCP9808_Addr, &cmd, 1U, true );
00549     aux  =   _i2c.read  ( _MCP9808_Addr, &cmd, 1U );
00550     
00551     /* Process the data  */
00552     myAuxValue =   (float)( ( cmd & TEMPERATURE_LIMIT_INTEGRAL_PART_MASK  ) >> 4U );
00553     myDecimal  =   ( ( cmd & TEMPERATURE_LIMIT_DECIMAL_PART_MASK  ) >> 2U );
00554     
00555     /* Process the decimal part  */
00556     for( cmd = ( TEMPERATURE_LIMIT_DECIMAL_PART_0_00C  >> 2U ); cmd < myDecimal; cmd++ )
00557     {
00558       myAuxValue  +=   0.25f;
00559     }
00560 
00561     /* Parse the data   */
00562     switch( myTLimit )
00563     {
00564       case MCP9808_TUPPER :
00565         myTValue_Limit->t_upper  =   (float)myAuxValue;
00566         break;
00567       
00568       case MCP9808_TLOWER :
00569         myTValue_Limit->t_lower  =   (float)myAuxValue;
00570         break;
00571 
00572       case MCP9808_TCRIT :
00573         myTValue_Limit->t_crit  =   (float)myAuxValue;
00574         break;
00575 
00576       default:
00577         return  MCP9808_FAILURE;
00578     }
00579 
00580   
00581 
00582     if ( aux == I2C_SUCCESS  )
00583     {
00584       return   MCP9808_SUCCESS;
00585     }
00586     else
00587     {
00588       return   MCP9808_FAILURE;
00589     }
00590   }
00591 }