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

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