Device driver for Si7020 Digital humidity and temperature sensor.
Dependents: Si7020_example MAXWSNENV_sensors MAXWSNENV_sensors Hello-Uzuki-sensor-shield ... more
Si7020.cpp
00001 /******************************************************************************* 00002 * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 ******************************************************************************* 00032 */ 00033 00034 #include "Si7020.h" 00035 00036 /***** Definitions *****/ 00037 #define I2C_ADDR (0x80) // 1000000x 00038 #define POLYVAL (0x131) 00039 00040 /***** File Scope Data *****/ 00041 static const char cmd_meas_humid[] = { 0xE5 }; 00042 static const char cmd_meas_humid_no_hold[] = { 0xF5 }; 00043 static const char cmd_meas_temp[] = { 0xE3 }; 00044 static const char cmd_meas_temp_no_hold[] = { 0xF3 }; 00045 static const char cmd_meas_prev_temp[] = { 0xE0 }; 00046 static const char cmd_rst[] = { 0xFE }; 00047 static const char cmd_write_user1[] = { 0xE6 }; 00048 static const char cmd_read_user1[] = { 0xE7 }; 00049 static const char cmd_id_1[] = { 0xFA, 0x0F }; 00050 static const char cmd_id_2[] = { 0xFC, 0xC9 }; 00051 static const char cmd_fw_ver[] = { 0x84, 0xB8 }; 00052 00053 //****************************************************************************** 00054 Si7020::Si7020(PinName sda, PinName scl) 00055 { 00056 i2c_ = new I2C(sda, scl); 00057 i2c_owner = true; 00058 00059 // 400KHz, as specified by the datasheet. 00060 i2c_->frequency(400000); 00061 } 00062 00063 //****************************************************************************** 00064 Si7020::Si7020(I2C *i2c) : 00065 i2c_(i2c) 00066 { 00067 i2c_owner = false; 00068 } 00069 00070 //****************************************************************************** 00071 Si7020::~Si7020() 00072 { 00073 if(i2c_owner) { 00074 delete i2c_; 00075 } 00076 } 00077 00078 //****************************************************************************** 00079 int Si7020::reset(void) 00080 { 00081 if (i2c_->write(I2C_ADDR, cmd_rst, sizeof(cmd_rst)) != 0) { 00082 return -1; 00083 } 00084 00085 return 0; 00086 } 00087 00088 //****************************************************************************** 00089 int Si7020::getElectronicId(char* id) 00090 { 00091 // Send cmd with repeated start 00092 if (i2c_->write(I2C_ADDR, cmd_id_1, sizeof(cmd_id_1), true) != 0) { 00093 return -1; 00094 } 00095 00096 // Read first portion of ID 00097 char temp[8]; 00098 if (i2c_->read(I2C_ADDR, temp, 8, false) != 0) { 00099 return -1; 00100 } 00101 00102 // Check the CRC 00103 char crc = 0; 00104 int i; 00105 for(i = 0; i < 4; i++) { 00106 crc = crc8(temp[2*i], crc); 00107 if(crc != temp[2*i +1]) { 00108 return -1; 00109 } 00110 } 00111 00112 // Save top portion of ID 00113 id[7] = temp [0]; 00114 id[6] = temp [2]; 00115 id[5] = temp [4]; 00116 id[4] = temp [6]; 00117 00118 // Send cmd with repeated start 00119 if (i2c_->write(I2C_ADDR, cmd_id_2, sizeof(cmd_id_2), true) != 0) { 00120 return -1; 00121 } 00122 00123 // Read rest of ID 00124 if (i2c_->read(I2C_ADDR, temp, 6, false) != 0) { 00125 return -1; 00126 } 00127 00128 // Check the CRC 00129 crc = 0; 00130 for(i = 0; i < 2; i++) { 00131 crc = crc8(temp[3*i], crc); 00132 crc = crc8(temp[3*i + 1], crc); 00133 if(crc != temp[3*i + 2]) { 00134 return -1; 00135 } 00136 } 00137 00138 // Save bottom portion of ID 00139 id[3] = temp [0]; 00140 id[2] = temp [1]; 00141 id[1] = temp [3]; 00142 id[0] = temp [4]; 00143 00144 return 0; 00145 } 00146 00147 //****************************************************************************** 00148 int Si7020::configResolution(Si7020::resolution_t resolution) 00149 { 00150 char data[2]; 00151 00152 if (i2c_->write(I2C_ADDR, cmd_read_user1, sizeof(cmd_read_user1)) != 0) { 00153 return -1; 00154 } 00155 00156 if (i2c_->read(I2C_ADDR, &data[1], 1) != 0) { 00157 return -1; 00158 } 00159 00160 switch (resolution) { 00161 case RH_12b_TEMP_14b: 00162 data[1] &= ~0x81; 00163 break; 00164 case RH_8b_TEMP_12b: 00165 data[1] = (data[1] & ~0x80) | 0x01; 00166 break; 00167 case RH_10b_TEMP_13b: 00168 data[1] = (data[1] & ~0x01) | 0x80; 00169 break; 00170 case RH_11b_TEMP_11b: 00171 data[1] |= 0x81; 00172 break; 00173 default: 00174 return -1; 00175 } 00176 00177 data[0] = cmd_write_user1[0]; 00178 00179 if (i2c_->write(I2C_ADDR, data, 2) != 0) { 00180 return -1; 00181 } 00182 00183 return 0; 00184 } 00185 00186 //****************************************************************************** 00187 int Si7020::getTemperature(int16_t *tempCx10) 00188 { 00189 if (i2c_->write(I2C_ADDR, cmd_meas_temp, sizeof(cmd_meas_temp)) != 0) { 00190 return -1; 00191 } 00192 00193 return checkTemperature(tempCx10); 00194 } 00195 00196 //****************************************************************************** 00197 int Si7020::getTemperature(float *tempC) 00198 { 00199 if (i2c_->write(I2C_ADDR, cmd_meas_temp, sizeof(cmd_meas_temp)) != 0) { 00200 return -1; 00201 } 00202 00203 return checkTemperature(tempC); 00204 } 00205 00206 //****************************************************************************** 00207 int Si7020::startTemperature(void) 00208 { 00209 if (i2c_->write(I2C_ADDR, cmd_meas_temp_no_hold, sizeof(cmd_meas_temp_no_hold)) != 0) { 00210 return -1; 00211 } 00212 00213 return 0; 00214 } 00215 00216 //****************************************************************************** 00217 int Si7020::checkTemperature(int16_t *tempCx10) 00218 { 00219 char data[3]; 00220 uint16_t code; 00221 int temp; 00222 00223 if (i2c_->read(I2C_ADDR, data, 3) != 0) { 00224 return -1; 00225 } 00226 00227 // Get 16-bit value from bytes read 00228 code = ((uint16_t)data[0] << 8) + data[1]; 00229 00230 // Calculate the temperature using the formula from the datasheet 00231 // Scaled by 100 00232 temp = ((((int)17572 * code) + 0x8000) >> 16) - 4685; 00233 00234 // Return value is to be scaled by 10 00235 *tempCx10 = (temp + 5) / 10; 00236 00237 return 0; 00238 } 00239 00240 //****************************************************************************** 00241 int Si7020::checkTemperature(float *tempC) 00242 { 00243 char data[3]; 00244 uint16_t code; 00245 00246 if (i2c_->read(I2C_ADDR, data, 3) != 0) { 00247 return -1; 00248 } 00249 00250 // Get 16-bit value from bytes read 00251 code = ((uint16_t)data[0] << 8) + data[1]; 00252 00253 // Calculate the temperature using the formula from the datasheet 00254 // Scaled by 100 00255 *tempC = ((175.72f * (float)code) / 65536.0f) - 46.85f; 00256 00257 return 0; 00258 } 00259 00260 //****************************************************************************** 00261 int Si7020::getHumidity(int16_t *humidx10) 00262 { 00263 if (i2c_->write(I2C_ADDR, cmd_meas_humid, sizeof(cmd_meas_humid), true) != 0) { 00264 return -1; 00265 } 00266 00267 return checkHumidity(humidx10); 00268 } 00269 00270 //****************************************************************************** 00271 int Si7020::getHumidity(float *humid) 00272 { 00273 if (i2c_->write(I2C_ADDR, cmd_meas_humid, sizeof(cmd_meas_humid)) != 0) { 00274 return -1; 00275 } 00276 00277 return checkHumidity(humid); 00278 } 00279 00280 //****************************************************************************** 00281 int Si7020::startHumidity(void) 00282 { 00283 if (i2c_->write(I2C_ADDR, cmd_meas_humid_no_hold, sizeof(cmd_meas_humid_no_hold)) != 0) { 00284 return -1; 00285 } 00286 00287 return 0; 00288 } 00289 00290 //****************************************************************************** 00291 int Si7020::checkHumidity(int16_t *humidx10) 00292 { 00293 char data[3]; 00294 uint16_t code; 00295 00296 if (i2c_->read(I2C_ADDR, data, 3) != 0) { 00297 return -1; 00298 } 00299 00300 // Get 16-bit value from bytes read 00301 code = ((uint16_t)data[0] << 8) + data[1]; 00302 00303 // Calculate the humidity using the formula from the datasheet 00304 // Scaled by 10 00305 *humidx10 = ((((int)1250 * code) + 0x8000) >> 16) - 60; 00306 00307 // Check the crc 00308 char crc = crc8(data[0], 0x00); 00309 crc = crc8(data[1], crc); 00310 if(crc != data[2]) { 00311 return -1; 00312 } 00313 00314 return 0; 00315 } 00316 00317 //****************************************************************************** 00318 int Si7020::checkHumidity(float *humid) 00319 { 00320 char data[3]; 00321 uint16_t code; 00322 00323 if (i2c_->read(I2C_ADDR, data, 3) != 0) { 00324 return -1; 00325 } 00326 00327 // Get 16-bit value from bytes read 00328 code = ((uint16_t)data[0] << 8) + data[1]; 00329 00330 // Calculate the humidity using the formula from the datasheet 00331 *humid = ((125.0f * (float)code) / 65536.0f) - 6.0f; 00332 00333 return 0; 00334 } 00335 00336 //****************************************************************************** 00337 int Si7020::getPrevTemperature(float *tempC) { 00338 00339 if (i2c_->write(I2C_ADDR, cmd_meas_prev_temp, sizeof(cmd_meas_prev_temp)) != 0) { 00340 return -1; 00341 } 00342 00343 if(checkTemperature(tempC) != 0) { 00344 return -1; 00345 } 00346 00347 return 0; 00348 } 00349 00350 //****************************************************************************** 00351 int Si7020::getPrevTemperature(int16_t *tempCx10) { 00352 00353 if (i2c_->write(I2C_ADDR, cmd_meas_prev_temp, sizeof(cmd_meas_prev_temp)) != 0) { 00354 return -1; 00355 } 00356 00357 if(checkTemperature(tempCx10) != 0) { 00358 return -1; 00359 } 00360 00361 return 0; 00362 } 00363 00364 //****************************************************************************** 00365 int Si7020::getRev(char *rev) 00366 { 00367 if (i2c_->write(I2C_ADDR, cmd_fw_ver, sizeof(cmd_fw_ver)) != 0) { 00368 return -1; 00369 } 00370 00371 if (i2c_->read(I2C_ADDR, rev, 1) != 0) { 00372 return -1; 00373 } 00374 00375 return 0; 00376 } 00377 00378 //****************************************************************************** 00379 int Si7020::heater(bool enable) 00380 { 00381 char data[2]; 00382 00383 if (i2c_->write(I2C_ADDR, cmd_read_user1, sizeof(cmd_read_user1)) != 0) { 00384 return -1; 00385 } 00386 00387 if (i2c_->read(I2C_ADDR, &data[1], 1) != 0) { 00388 return -1; 00389 } 00390 00391 if (enable) { 00392 data[1] |= 0x04; 00393 } else { 00394 data[1] &= ~0x04; 00395 } 00396 00397 data[0] = cmd_write_user1[0]; 00398 00399 if (i2c_->write(I2C_ADDR, data, 2) != 0) { 00400 return -1; 00401 } 00402 00403 return 0; 00404 } 00405 00406 //****************************************************************************** 00407 char Si7020::crc8(char value, char seed) 00408 { 00409 int i; 00410 00411 for (i = 0; i < 8; i++) { 00412 00413 if ((value ^ seed) & 0x80) { 00414 seed <<= 1; 00415 seed ^= POLYVAL; 00416 } else { 00417 seed <<= 1; 00418 } 00419 00420 value <<= 1; 00421 } 00422 00423 return seed; 00424 }
Generated on Thu Jul 14 2022 03:07:16 by 1.7.2