diff --git a/app/include/user_modules.h b/app/include/user_modules.h index 1afdde13f4..8befebef41 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -42,6 +42,7 @@ //#define LUA_USE_MODULES_HDC1080 //#define LUA_USE_MODULES_HMC5883L //#define LUA_USE_MODULES_HTTP +//#define LUA_USE_MODULES_HTU21 //#define LUA_USE_MODULES_HX711 #define LUA_USE_MODULES_I2C //#define LUA_USE_MODULES_L3G4200D diff --git a/app/modules/htu21.c b/app/modules/htu21.c new file mode 100644 index 0000000000..ca68569023 --- /dev/null +++ b/app/modules/htu21.c @@ -0,0 +1,101 @@ +/* + * Driver for HTU21D/SHT21 humidity/temperature sensor. + * + */ +#include "module.h" +#include "lauxlib.h" +#include "platform.h" + +#define HTU21_ADDRESS 0x40 +/* HTU21 Commands */ +#define HTU21_T_MEASUREMENT_HM 0xE3 +#define HTU21_RH_MEASUREMENT_HM 0xE5 +#define HTU21_CRC_ERROR (uint16_t) 1 + +//Give this function the 2 byte message (measurement) and the check_value byte from the HTU21D +//If it returns 0, then the transmission was good +//If it returns something other than 0, then the communication was corrupted +//From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html +//POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks +#define SHIFTED_DIVISOR 0x988000 //This is the 0x0131 polynomial shifted to farthest left of three bytes + +static inline int32_t htu21_temp_ticks_to_millicelsius(uint32_t ticks) +{ + ticks &= ~0x0003; /* clear status bits */ + /* + * Formula T = -46.85 + 175.72 * ST / 2^16 from datasheet p14, + * optimized for integer fixed point (3 digits) arithmetic + */ + return ((21965 * ticks) >> 13) - 46850; +} + +static inline int32_t htu21_rh_ticks_to_per_cent_mille(uint32_t ticks) +{ + ticks &= ~0x0003; /* clear status bits */ + /* + * Formula RH = -6 + 125 * SRH / 2^16 from datasheet p14, + * optimized for integer fixed point (3 digits) arithmetic + */ + return ((15625 * ticks) >> 13) - 6000; +} + +static uint8_t checkCRC(uint16_t ravValue, uint8_t checksum) +{ + uint32_t remainder = (uint32_t) ravValue << 8; //Pad with 8 bits because we have to add in the check value + remainder |= checksum; //Add on the check value + + uint32_t divsor = (uint32_t) SHIFTED_DIVISOR; + + //Operate on only 16 positions of max 24. The remaining 8 are our remainder and should be zero when we're done. + for (int i = 0; i < 16; i++) + { + if (remainder & (uint32_t) 1 << (23 - i)) //Check if there is a one in the left position + remainder ^= divsor; + + divsor >>= 1; //Rotate the divsor max 16 times so that we have 8 bits left of a remainder + } + + return (uint8_t) remainder; +} + +static uint16_t read_with_crc_check(lua_State *L, uint8_t reg) +{ + uint16_t rawValue; + uint8_t checksum; + + platform_i2c_send_start(0); + platform_i2c_send_address(0, HTU21_ADDRESS, PLATFORM_I2C_DIRECTION_TRANSMITTER); + platform_i2c_send_byte(0, reg); + platform_i2c_send_start(0); + platform_i2c_send_address(0, HTU21_ADDRESS, PLATFORM_I2C_DIRECTION_RECEIVER); + + rawValue = (uint16_t) platform_i2c_recv_byte(0, 1) << 8; + rawValue |= platform_i2c_recv_byte(0, 1); + checksum = (uint8_t) platform_i2c_recv_byte(0, 0); + + platform_i2c_send_stop(0); + + return checkCRC(rawValue, checksum) != 0 ? HTU21_CRC_ERROR : rawValue; +} + +static int htu21_read(lua_State *L) +{ + uint16_t rawT = read_with_crc_check(L, HTU21_T_MEASUREMENT_HM); + uint16_t rawRH = read_with_crc_check(L, HTU21_RH_MEASUREMENT_HM); + + if (rawT == HTU21_CRC_ERROR || rawRH == HTU21_CRC_ERROR) { + luaL_error(L, "htu21 invalid CRC"); + } + + lua_pushinteger(L, htu21_temp_ticks_to_millicelsius(rawT)); + lua_pushinteger(L, htu21_rh_ticks_to_per_cent_mille(rawRH)); + + return 2; +} + +static const LUA_REG_TYPE htu21_map[] = { + {LSTRKEY("read"), LFUNCVAL(htu21_read)}, + {LNILKEY, LNILVAL} +}; + +NODEMCU_MODULE(HTU21, "htu21", htu21_map, NULL); diff --git a/docs/en/modules/htu21.md b/docs/en/modules/htu21.md new file mode 100644 index 0000000000..59193566de --- /dev/null +++ b/docs/en/modules/htu21.md @@ -0,0 +1,25 @@ +# HTU21 Module +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2017-02-03 | [Pawel Switalski](https://github.com/s-pw) | [Pawel Switalski](https://github.com/s-pw) | [htu21.c](../../../app/modules/htu21.c)| + + +This module provides access to the [HTU21D](https://www.sparkfun.com/products/13763) temperature and humidity sensor. The module also works with SHT21. + +## htu21.read() +Samples the sensor then returns temperature and humidity value. + +#### Syntax +`htu21.read()` + +#### Returns +Temperature data in millidegree Celsius and humidity data in per cent mille + +#### Example +```lua +local sda, scl = 1, 2 +i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once +local temperature, humidity = htu21.read() +print(temperature / 1000 .. '°C') +print(humidity / 1000 .. '%') +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index b9c70f288f..7a9f542134 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -59,6 +59,7 @@ pages: - 'hdc1080': 'en/modules/hdc1080.md' - 'hmc5883l': 'en/modules/hmc5883l.md' - 'http': 'en/modules/http.md' + - 'htu21': 'en/modules/htu21.md' - 'hx711' : 'en/modules/hx711.md' - 'i2c' : 'en/modules/i2c.md' - 'l3g4200d' : 'en/modules/l3g4200d.md'