Skip to content

Commit

Permalink
Add support for HTU21D/SHT21 temperature and humidity sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
pawel-sw committed Feb 13, 2018
1 parent f87d68f commit f41f8b3
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/include/user_modules.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
101 changes: 101 additions & 0 deletions app/modules/htu21.c
Original file line number Diff line number Diff line change
@@ -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);
25 changes: 25 additions & 0 deletions docs/en/modules/htu21.md
Original file line number Diff line number Diff line change
@@ -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 .. '%')
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down

0 comments on commit f41f8b3

Please sign in to comment.