|
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 /* @} */