Mindstorms 3rd Party ROBOTC Drivers RobotC
[Home] [Download] [Submit a bug/suggestion] [ROBOTC Forums] [Blog] [Support this project]

lego-temp.h

Go to the documentation of this file.
00001 /*!@addtogroup lego
00002  * @{
00003  * @defgroup legotmp Temperature Sensor
00004  * Temperature Sensor
00005  * @{
00006  */
00007 
00008 /*
00009  * $Id: lego-temp.h 133 2013-03-10 15:15:38Z xander $
00010  */
00011 
00012 #ifndef __LEGOTMP_DRIVER_H__
00013 #define __LEGOTMP_DRIVER_H__
00014 
00015 /** \file lego-temp.h
00016  * \brief RobotC New Temperature Sensor Driver
00017  *
00018  * lego-temp.h provides an API for the Lego Temperature Sensor.
00019  *
00020  * Changelog:
00021  * - 0.1: Initial release
00022  * - 0.2: Partial rewrite by Xander Soldaat to simplify API
00023  *
00024  * Credits :
00025  * - Based on http://focus.ti.com/lit/ds/symlink/tmp275.pdf (Thank to Xander Soldaat who found the internal design)
00026  * - Based on Xander Soldaat's RobotC driver template
00027  *
00028  * License: You may use this code as you wish, provided you give credit where its due.
00029  *
00030  * THIS CODE WILL ONLY WORK WITH ROBOTC VERSION 3.59 AND HIGHER. 
00031 
00032  * \author Sylvain CACHEUX (sylcalego@cacheux.info)
00033  * \author Xander Soldaat (mightor@gmail.com), version 0.2
00034  * \date 15 february 2010
00035  * \version 0.2
00036  * \example lego-temp-test1.c
00037  * \example lego-temp-test2.c
00038  */
00039 
00040 #pragma systemFile
00041 
00042 #ifndef __COMMON_H__
00043 #include "common.h"
00044 #endif
00045 
00046 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00047 /*
00048 <Address definitions>
00049 */
00050 #define LEGOTMP_I2C_ADDR 0x98 /*!< New LEGO Temperature Sensor I2C device address                                                */
00051 #define LEGOTMP_TEMP     0x00 /*!< Temperature value (return on 2 bytes, 1rst : most significant byte, 2nd  byte only half used) */
00052 #define LEGOTMP_CONFIG   0x01 /*!< Configuration registry (see http://focus.ti.com/lit/ds/symlink/tmp275.pdf)                    */
00053 
00054 
00055 
00056 // ---------------------------- Definitions --------------------------------------
00057 /*!< Command modes definition */
00058 typedef enum {
00059   A_MIN   = 8, // 0.5,   * 16 (typedef needs integer...)
00060   A_MEAN1 = 4, // 0.25   * 16 (so *16 here...)
00061   A_MEAN2 = 2, // 0.125  * 16 (... and /16 in functions)
00062   A_MAX   = 1  // 0.0625 * 16 (I'll have to improve that later...)
00063 } tLEGOTMPAccuracy; // The 4 available accuracy of the sensor
00064 
00065 
00066 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00067 // Function prototypes
00068 bool LEGOTMPreadTemp(tSensors link, float &temp);
00069 bool LEGOTMPreadAccuracy(tSensors link, tLEGOTMPAccuracy &accuracy);
00070 bool LEGOTMPsetAccuracy(tSensors link, tLEGOTMPAccuracy accuracy);
00071 bool LEGOTMPsetSingleShot(tSensors link);
00072 bool LEGOTMPsetContinuous(tSensors link);
00073 bool _LEGOTMPreadConfig(tSensors link, ubyte &config);
00074 tLEGOTMPAccuracy _LEGOTMPconvertAccuracy(ubyte config);
00075 
00076 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00077 // global variables
00078 tByteArray       LEGOTMP_I2CRequest;    /*!< Array to hold I2C command data */
00079 tByteArray       LEGOTMP_I2CReply;      /*!< Array to hold I2C reply data   */
00080 
00081 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00082 
00083 
00084 /**
00085  * Read the current configuration register
00086  *
00087  * Note: this is an internal function and should not be called directly.
00088  * @param link the LEGO Temp Sensor port number
00089  * @param config the contents of the register
00090  * @return true if no error occured, false if it did
00091  */
00092 bool _LEGOTMPreadConfig(tSensors link, ubyte &config) {
00093   memset(LEGOTMP_I2CRequest, 0, sizeof(tByteArray));
00094 
00095   LEGOTMP_I2CRequest[0] = 2;                // Message size
00096   LEGOTMP_I2CRequest[1] = LEGOTMP_I2C_ADDR; // I2C Address
00097   LEGOTMP_I2CRequest[2] = LEGOTMP_CONFIG;   // Value address
00098 
00099   if (!writeI2C(link, LEGOTMP_I2CRequest, LEGOTMP_I2CReply, 1))
00100     return false;
00101 
00102   config = LEGOTMP_I2CReply[0];
00103 
00104   return true;
00105 }
00106 
00107 
00108 /**
00109  * Set the configuration register
00110  *
00111  * Note: this is an internal function and should not be called directly.
00112  * @param link the LEGO Temp Sensor port number
00113  * @param config the contents of the register
00114  * @return true if no error occured, false if it did
00115  */
00116 bool _LEGOTMPsetConfig(tSensors link, ubyte &config) {
00117   memset(LEGOTMP_I2CRequest, 0, sizeof(tByteArray));
00118 
00119   LEGOTMP_I2CRequest[0] = 3;                // Message size
00120   LEGOTMP_I2CRequest[1] = LEGOTMP_I2C_ADDR; // I2C Address
00121   LEGOTMP_I2CRequest[2] = LEGOTMP_CONFIG;   // Value address
00122   LEGOTMP_I2CRequest[3] = config;           // Value to be set
00123 
00124   return writeI2C(link, LEGOTMP_I2CRequest);
00125 }
00126 
00127 
00128 /**
00129  * Retrieve the accuracy level from the config bytes
00130  *
00131  * Note: this is an internal function and should not be called directly.
00132  * @param config the contents of the register
00133  * @return true if no error occured, false if it did
00134  */
00135 tLEGOTMPAccuracy _LEGOTMPconvertAccuracy(ubyte config) {
00136   /* the accuracy is in bits 6 & 5<br>
00137    * Config registry :<br>
00138    * BYTE D7  <D6 D5> D4 D3 D2  D1 D0<br>
00139    * 1    OS  <R1 R0> F1 F0 POL TM SD<br>
00140    * so shifting bits to have the bits 6 and 5 at the right of the byte<br>
00141    * then doing a AND with 11 (3) to know the value of the accuracy.<br>
00142    */
00143 
00144   config = (config >> 5) & 3;
00145   switch (config) {
00146     case 0:
00147       // bits are 0 0, so the minimum accuracy
00148       return A_MIN;
00149       break;
00150     case 1:
00151       // bits are 0 1, so the mean1 accuracy
00152       return A_MEAN1;
00153       break;
00154     case 2:
00155       // bits are 1 0, so the mean2 accuracy
00156       return A_MEAN2;
00157       break;
00158     case 3:
00159       // bits are 1 1, so the maximum accuracy
00160       return A_MAX;
00161       break;
00162   }
00163   return A_MIN;
00164 }
00165 
00166 
00167 /**
00168  * Read the temperature.
00169  * @param link the LEGO Temp Sensor port number
00170  * @param temp the temperature value,
00171  * @return true if no error occured, false if it did
00172  */
00173 bool LEGOTMPreadTemp(tSensors link, float &temp) {
00174   memset(LEGOTMP_I2CRequest, 0, sizeof(tByteArray));
00175   int b1;
00176   float b2;
00177   ubyte config;
00178 
00179   //reading current accuracy
00180   if (!_LEGOTMPreadConfig(link, config))
00181     return false;
00182 
00183   // Check if we're in shutdown mode, if so, we're doing
00184   // one-shotted readings.
00185   if (config & 1 == 1) {
00186     config |= (1<<7); // set bit 7 for one-shot mode
00187 
00188     if (!_LEGOTMPsetConfig(link, config))
00189       return false;
00190 
00191     // Now we need to wait a specific amount of time, depending on the
00192     // accuracy level.
00193 
00194     switch (_LEGOTMPconvertAccuracy(config)) {
00195       case A_MIN:
00196         // conversion takes 27.5ms
00197         wait1Msec(28);
00198         break;
00199       case A_MEAN1:
00200         // conversion takes 55ms
00201         wait1Msec(55);
00202         break;
00203       case A_MEAN2:
00204         // conversion takes 110ms
00205         wait1Msec(110);
00206         break;
00207       case A_MAX:
00208         // conversion takes 220ms
00209         wait1Msec(220);
00210         break;
00211     }
00212   }
00213 
00214   // clear the array again
00215   memset(LEGOTMP_I2CRequest, 0, sizeof(tByteArray));
00216   LEGOTMP_I2CRequest[0] = 2;                // Message size
00217   LEGOTMP_I2CRequest[1] = LEGOTMP_I2C_ADDR; // I2C Address
00218   LEGOTMP_I2CRequest[2] = LEGOTMP_TEMP;     // Value address
00219 
00220   if (!writeI2C(link, LEGOTMP_I2CRequest, LEGOTMP_I2CReply, 2))
00221     return false;
00222 
00223   b1 = (int)LEGOTMP_I2CReply[0];
00224 
00225   switch (_LEGOTMPconvertAccuracy(config)) {
00226     case A_MIN:
00227       ///128 to have only the most significant bit (9 bits accuracy - 8 (b1) = 1 bit to keep)
00228       b2 = ((int)LEGOTMP_I2CReply[1] >> 7) * 0.5;
00229       break;
00230     case A_MEAN1:
00231       ///64 to have only the 2 most significant bits
00232       b2 = ((int)LEGOTMP_I2CReply[1] >> 6) * 0.25;
00233       break;
00234     case A_MEAN2:
00235       ///32 to have only the 3 most significant bits
00236       b2 = ((int)LEGOTMP_I2CReply[1] >> 5) * 0.125;
00237       break;
00238     case A_MAX:
00239       ///16 to have only the 4 most significant bits
00240       b2 = ((int)LEGOTMP_I2CReply[1] >> 4) * 0.0625;
00241       break;
00242   }
00243 
00244   if (b1 < 128) temp = b1 + b2;         // positive temp
00245   if (b1 > 127) temp = (b1 - 256) + b2; // negative temp
00246 
00247   return true;
00248 }
00249 
00250 
00251 /**
00252  * Read the temperature sensor's accuracy
00253  * @param link the LEGO Temp Sensor port number,
00254  * @param accuracy the accuracy value to be read
00255  * @return true if no error occured, false if it did
00256  */
00257 bool LEGOTMPreadAccuracy(tSensors link, tLEGOTMPAccuracy &accuracy) {
00258   memset(LEGOTMP_I2CRequest, 0, sizeof(tByteArray));
00259   ubyte config;
00260 
00261   if (!_LEGOTMPreadConfig(link, config))
00262     return false;
00263 
00264   accuracy = _LEGOTMPconvertAccuracy(config);
00265 
00266   return true;
00267 }
00268 
00269 
00270 /**
00271  * Set the temperature sensor's accuracy
00272  * @param link the LEGO Temp Sensor port number
00273  * @param accuracy the accuracy value to be set
00274  * @return true if no error occured, false if it did
00275  */
00276 bool LEGOTMPsetAccuracy(tSensors link, tLEGOTMPAccuracy accuracy) {
00277   memset(LEGOTMP_I2CRequest, 0, sizeof(tByteArray));
00278   ubyte config;
00279 
00280   // reading the configuration registry to know the other bits values
00281   if (!_LEGOTMPreadConfig(link, config))
00282     return false;
00283 
00284   // setting the value to be writed in the configuration registry depending on the others bits values
00285         /* the accuracy is in bits 6 & 5<br>
00286          * Config registry :<br>
00287          * BYTE D7  <D6 D5> D4 D3 D2  D1 D0<br>
00288          * 1    OS  <R1 R0> F1 F0 POL TM SD<br>
00289          *      128 <64 32> 16 8  4   2  1<br>
00290         */
00291 
00292   // Clear bits 5 and 6
00293   config &= 0x9F;
00294 
00295   switch (accuracy) {
00296     case A_MIN:
00297       // Minimum accuracy, so bits 6 5 must be 0 0, so doing an OR with 0000 0000;
00298       config |= 0x00;  //
00299       break;
00300     case A_MEAN1:
00301       // Mean accuracy 1, so bits 6 5 must be 0 1, so doing an OR with 0010 0000 (0x20)
00302       config |= 0x20;
00303       break;
00304     case A_MEAN2:
00305       // Mean accuracy 2, so bits 6 5 must be 1 0, so doing an OR with 0100 0000 (0x40
00306       config |= 0x40;
00307       break;
00308     case A_MAX:
00309       // Maximum accuracy, so bits 6 5 must be 1 1, so doing a OR with 0110 0000 (0x60
00310       config |= 0x60;
00311       break;
00312   }
00313 
00314   // Send new configuration to the sensor
00315   return _LEGOTMPsetConfig(link, config);
00316 }
00317 
00318 
00319 /**
00320  * Configure the sensor for Single Shot mode
00321  * @param link the New LEGO Sensor port number
00322  * @return true if no error occured, false if it did
00323  */
00324 bool LEGOTMPsetSingleShot(tSensors link) {
00325   memset(LEGOTMP_I2CRequest, 0, sizeof(tByteArray));
00326   ubyte config;
00327 
00328   // reading the configuration registry to know the other bits values
00329   if (!_LEGOTMPreadConfig(link, config))
00330     return false;
00331 
00332   // setting the value to be written in the configuration registry depending on the others bits values
00333   /* the shutdown mode bit it bit 0<br>
00334          * Config registry :<br>
00335          * BYTE D7  <D6 D5> D4 D3 D2  D1 D0<br>
00336          * 1    OS  <R1 R0> F1 F0 POL TM SD<br>
00337          *      128 <64 32> 16 8  4   2  1<br>
00338         */
00339 
00340   // Set bit 0 to 1
00341   config |= 1;
00342 
00343   // Send new configuration to the sensor
00344   return _LEGOTMPsetConfig(link, config);
00345 }
00346 
00347 
00348 /**
00349  * Configure the sensor for Continuous mode
00350  * @param link the New LEGO Sensor port number
00351  * @return true if no error occured, false if it did
00352  */
00353 bool LEGOTMPsetContinuous(tSensors link) {
00354   memset(LEGOTMP_I2CRequest, 0, sizeof(tByteArray));
00355   ubyte config;
00356 
00357   // reading the configuration registry to know the other bits values
00358   if (!_LEGOTMPreadConfig(link, config))
00359     return false;
00360 
00361   // setting the value to be written in the configuration registry depending on the others bits values
00362   /* the shutdown mode bit it bit 0<br>
00363    * Config registry :<br>
00364    * BYTE D7  <D6 D5> D4 D3 D2  D1 D0<br>
00365    * 1    OS  <R1 R0> F1 F0 POL TM SD<br>
00366    *      128 <64 32> 16 8  4   2  1<br>
00367    */
00368 
00369   // Set bit 0 to 0
00370   config &= 0xFE;
00371 
00372   // Send new configuration to the sensor
00373   return _LEGOTMPsetConfig(link, config);
00374 }
00375 
00376 #endif // __LEGOTMP_DRIVER_H__
00377 
00378 /*
00379  * $Id: lego-temp.h 133 2013-03-10 15:15:38Z xander $
00380  */
00381 /* @} */
00382 /* @} */