Home > Electronics > Electric Imp & SHTxx sensors

Electric Imp & SHTxx sensors

December 17th, 2012

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);

Electronics ,

  1. No comments yet.
  1. No trackbacks yet.