Electric Imp & SHTxx sensors
There have been a couple people requesting the code to drive an SHT temp/humidity sensor from an electric imp, so I’ll post it below. No warrantee implied.. Also, it’s ugly as someone else wrote it for some other microprocessor and I just tweaked it; I would never write such aesthetically displeasing code. Obviously, I’m big banging pins 8 and 9; adjust to suite your needs. Don’t forget the pullup resistor on one of those lines. This is also written for the SHT71, tweak for whichever unit you are using.
class SHT {
function delay_us(x) {imp.sleep(0.000001 * x);}noACK =0;
ACK=1;
//adr command r/w
STATUS_REG_W =0x06; //000 0011 0
STATUS_REG_R =0x07; //000 0011 1
MEASURE_TEMP =0x03; //000 0001 1
MEASURE_HUMI =0x05; //000 0010 1
RESET =0x1e; //000 1111 0
data_output = true;
function constructor() {
hardware.pin8.configure(DIGITAL_OUT);
hardware.pin9.configure(DIGITAL_OUT);
s_softreset( );
}
function sck_set(x) {
hardware.pin8.write(x);
}
function data_set(x) {
if (!data_output) {
hardware.pin9.configure(DIGITAL_OUT);
data_output = true;
}
hardware.pin9.write(x);
}
function data_get() {
if (data_output) {
hardware.pin9.configure(DIGITAL_IN);
data_output = false;
}
return hardware.pin9.read();
}
function SCK( val) {
if (val) {
sck_set(1);
} else {
sck_set(0);
}
}
function DATA( val) {
if (val) {
//input w/ pullup resistor
data_get();
} else {
//output – gnd
data_set(0);
}
}
function sht_init() {
s_write_statusreg(0, 0x00); //8/12 bit resolution
}
//———————————————————————————-
function s_write_byte( value) {
//———————————————————————————-
// writes a byte on the Sensibus and checks the acknowledge
local error=0;
for (local i=0x80; i>0; i=i/2) //shift bit for masking
{
if (i & value) DATA( 1); //masking value with i , write to SENSI-BUS
else DATA(0);
delay_us(5);
SCK( 1); //clk for SENSI-BUS
delay_us(5); //pulswith approx. 5 us
SCK( 0);
}
delay_us(5);
DATA( 1); //release DATA-line
SCK( 1); //clk #9 for ack
error=data_get(); //check ack (DATA will be pulled down by SHT11)
SCK( 0);
return error; //error=1 in case of no acknowledge
}
//———————————————————————————-
function s_read_byte( ack)
//———————————————————————————-
// reads a byte form the Sensibus and gives an acknowledge in case of "ack=1"
{
local val=0;
DATA( 1); //release DATA-line
for (local i=0x80; i>0 ; i = i>>1) { //shift bit for masking
SCK( 1); //clk for SENSI-BUS
if (data_get()) val=(val | i); //read bit
SCK( 0);
}
if (ack) {
DATA(0);
} else {
DATA(1);
}
SCK( 1); //clk #9 for ack
delay_us(5); //pulswith approx. 5 us
SCK( 0);
DATA( 1); //release DATA-line
return val;
}
//———————————————————————————-
function s_transstart( )
//———————————————————————————-
// generates a transmission start
// _____ ________
// DATA: |_______|
// ___ ___
// SCK : ___| |___| |______
{
DATA( 1);
SCK( 0);//Initial state
delay_us(2);
SCK( 1);
delay_us(2);
DATA( 0);
delay_us(2);
SCK( 0);
delay_us(6);
SCK( 1);
delay_us(2);
DATA( 1);
delay_us(2);
SCK( 0);
}
//———————————————————————————-
function s_connectionreset( )
//———————————————————————————-
// communication reset: DATA-line=1 and at least 9 SCK cycles followed by transstart
// _____________________________________________________ ________
// DATA: |_______|
// _ _ _ _ _ _ _ _ _ ___ ___
// SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |______
{
server.log("connectionreset()");
DATA( 1);
SCK( 0); //Initial state
for(local i=0;i<9;i++) //9 SCK cycle
{
SCK( 1); delay_us(1);
SCK( 0); delay_us(1);
}
s_transstart(); //transmission start
}
//———————————————————————————-
function s_softreset( )
//———————————————————————————-
// resets the sensor by a softreset
{
local error=0;
s_connectionreset(); //reset communication
error = s_write_byte( RESET); //send RESET-command to sensor
return error; //error=1 in case of no response form the sensor
}
//———————————————————————————-
function s_read_statusreg() {
//———————————————————————————-
// reads the status register with checksum (8-bit)
local error=0;
local ret = {};
s_transstart(); //transmission start
error=s_write_byte(STATUS_REG_R); //send command to sensor
ret.value <- s_read_byte(ACK);
ret.checksum <- s_read_byte(noACK);
ret.error <- error;
return ret; //error=1 in case of no response form the sensor
}
//———————————————————————————-
function s_write_statusreg( p_value)
//———————————————————————————-
// writes the status register with checksum (8-bit)
{
local error=0;
s_transstart(); //transmission start
error= error+s_write_byte( STATUS_REG_W);//send command to sensor
error= error+s_write_byte( p_value); //send value of status register
return error; //error>=1 in case of no response form the sensor
}
function s_getHumidity( ) {
local timer=0.0;
local data=0.0;
local a;
local b;
local crc;
local result=0;
local errorString="";
s_transstart();
if (s_write_byte( MEASURE_HUMI)) {
server.log("s_getHumidity:writing data error");
return 0;
}
// wait up until 2 seconds for DATA to go low
while (timer < 2 && data_get()) {
imp.sleep(0.01);
timer = timer + 0.01;
}
// see if an error occured (data_get is still high)
if (data_get()) {
server.log("s_getHumidity:no response");
return 0;
}
a = s_read_byte( ACK); //MSB
b = s_read_byte( ACK); //LSB
crc = s_read_byte( noACK); //checksum
result = a<<8 | b;
// data = -4.0 + (result * 0.0405) – (0.0000028 *result * result);
return result;
// return data;
}
function s_getTemperature( ) {
local timer=0.0;
local data=0.0;
local a;
local b;
local crc;
local result=0;
local errorString="";
s_transstart();
if (s_write_byte( MEASURE_TEMP)) {
server.log("s_getTemperature:writing data error");
return 0;
}
// wait up until 2 seconds for DATA to go low
while (timer < 2) {
if (data_get() == 0) break;
imp.sleep(0.01);
timer = timer + 0.01;
}
// see if an error occured (data_get is still high)
if (data_get()) {
server.log("s_getTemperature:no response");
return 0;
}
a = s_read_byte( ACK); //MSB
b = s_read_byte( ACK); //LSB
crc = s_read_byte( noACK); //checksum
result = a<<8 | b;
// data = -40.2 + ( .018 * result );
// return data;
return result;
}
//—————————————————————————————-
function get()
//—————————————————————————————-
// calculates temperature [°C] and humidity [%RH]
// input : humi [Ticks] (12 bit)
// temp [Ticks] (14 bit)
// output: humi [%RH]
// temp [°C]
{ local C1=-4.0; // for 12 Bit
local C2=0.0405; // for 12 Bit
local C3=-0.0000028; // for 12 Bit
local T1=0.01; // for 14 Bit @ 5V
local T2=0.00008; // for 14 Bit @ 5V
local rh_lin; // rh_lin: Humidity linear
local rh_true; // rh_true: Temperature compensated humidity
local t_C; // t_C : Temperature [°C]
// s_connectionreset();
// imp.sleep(1);
local hum_data=s_getHumidity(); // rh: Humidity [Ticks] 12 Bit
local temp_data=s_getTemperature(); // t: Temperature [Ticks] 14 Bit
t_C=temp_data*0.01 – 40; //calc. temperature from ticks to [°C]
rh_lin=C3*hum_data*hum_data + C2*hum_data + C1; //calc. humidity from ticks to [%RH]
rh_true=(t_C-25)*(T1+T2*hum_data)+rh_lin; //calc. temperature compensated humidity [%RH]
if(rh_true>100)rh_true=100; //cut if the value is outside of
if(rh_true<0.1)rh_true=0.1; //the physical possible range
local t_F = t_C * 9 / 5 + 32;
local ret = {};
ret.temp <- t_F;
ret.humidity <- rh_true;
return ret;
}
}
sht <- SHT(); //instantiate class only once
local tempHum = sht.get(); //call as often as you want
server.log("temp="+tempHum.temp+" hum="+tempHum.humidity);