Eric yuan
Published © LGPL

Temperature and Humidity Monitor

This is a project that uses SHT30 to get the current temperature and humidity. And then displays it on a no-chip embeded LCD.

BeginnerShowcase (no instructions)2 hours1,596
Temperature and Humidity Monitor

Things used in this project

Hardware components

Electron
Particle Electron
×1
Pocket Solder- 60/40 Rosin Core 0.031" diameter
Pocket Solder- 60/40 Rosin Core 0.031" diameter
×1

Story

Read more

Schematics

sch file

pcb file

Code

Adafruit_TMP007.h

C/C++
#include "application.h"
#include "Particle.h"
#include "math.h"

// uncomment for debugging!
//#define TMP007_DEBUG 1

#define TMP007_VOBJ       0x00
#define TMP007_TDIE       0x01
#define TMP007_CONFIG     0x02
#define TMP007_TOBJ       0x03
#define TMP007_STATUS     0x04
#define TMP007_STATMASK   0x05

#define TMP007_CFG_RESET    0x8000
#define TMP007_CFG_MODEON   0x1000
#define TMP007_CFG_1SAMPLE  0x0000
#define TMP007_CFG_2SAMPLE  0x0200
#define TMP007_CFG_4SAMPLE  0x0400
#define TMP007_CFG_8SAMPLE  0x0600
#define TMP007_CFG_16SAMPLE 0x0800
#define TMP007_CFG_ALERTEN  0x0100
#define TMP007_CFG_ALERTF   0x0080
#define TMP007_CFG_TRANSC   0x0040

#define TMP007_STAT_ALERTEN 0x8000
#define TMP007_STAT_CRTEN   0x4000

#define TMP007_I2CADDR 0x40
#define TMP007_DEVID 0x1F



class Adafruit_TMP007  {
 public:
  Adafruit_TMP007(uint8_t addr = TMP007_I2CADDR);
  boolean begin(uint8_t samplerate = TMP007_CFG_16SAMPLE);  // by default go highres

  int16_t readRawDieTemperature(void);
  int16_t readRawVoltage(void);
  double readObjTempC(void);
  double readDieTempC(void);

 private:
  uint8_t _addr;
  uint16_t read16(uint8_t addr);
  void write16(uint8_t addr, uint16_t data);
};

Adafruit_TMP007.cpp

C/C++
/*************************************************** 
  This is a library for the TMP007 Temp Sensor
  Designed specifically to work with the Adafruit TMP007 Breakout 
  ----> https://www.adafruit.com/products/2023
  These displays use I2C to communicate, 2 pins are required to  
  interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!
  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include "Adafruit_TMP007.h"

#define ARDUINO  200

//#define TESTDIE 0x0C78
//#define TESTVOLT 0xFEED

Adafruit_TMP007::Adafruit_TMP007(uint8_t i2caddr) {
  _addr = i2caddr;
}


boolean Adafruit_TMP007::begin(uint8_t samplerate) {
  Wire1.begin();

  write16(TMP007_CONFIG, TMP007_CFG_MODEON | TMP007_CFG_ALERTEN | 
	  TMP007_CFG_TRANSC | samplerate);
  write16(TMP007_STATMASK, TMP007_STAT_ALERTEN |TMP007_STAT_CRTEN);
  // enable conversion ready alert

  uint16_t did;
  did = read16(TMP007_DEVID);
#ifdef TMP007_DEBUG
  Serial.print("did = 0x"); Serial.println(did, HEX);
#endif
  if (did != 0x78) return false;
  return true;
}

//////////////////////////////////////////////////////

double Adafruit_TMP007::readDieTempC(void) {
   double Tdie = readRawDieTemperature();
   Tdie *= 0.03125; // convert to celsius
#ifdef TMP007_DEBUG
   Serial.print("Tdie = "); Serial.print(Tdie); Serial.println(" C");
#endif
   return Tdie;
}

double Adafruit_TMP007::readObjTempC(void) {
  int16_t raw = read16(TMP007_TOBJ);
  // invalid
  if (raw & 0x1) return NAN;
  raw >>=2;

  double Tobj = raw;
  Tobj *= 0.03125; // convert to celsius
#ifdef TMP007_DEBUG
   Serial.print("Tobj = "); Serial.print(Tobj); Serial.println(" C");
#endif
   return Tobj;
}



int16_t Adafruit_TMP007::readRawDieTemperature(void) {
  int16_t raw = read16(TMP007_TDIE);

#if TMP007_DEBUG == 1

#ifdef TESTDIE
  raw = TESTDIE;
#endif

  Serial.print("Raw Tambient: 0x"); Serial.print (raw, HEX);
  

  float v = raw/4;
  v *= 0.03125;
  Serial.print(" ("); Serial.print(v); Serial.println(" *C)");
#endif
  raw >>= 2;
  return raw;
}

int16_t Adafruit_TMP007::readRawVoltage(void) {
  int16_t raw;

  raw = read16(TMP007_VOBJ);

#if TMP007_DEBUG == 1

#ifdef TESTVOLT
  raw = TESTVOLT;
#endif

  Serial.print("Raw voltage: 0x"); Serial.print (raw, HEX);
  float v = raw;
  v *= 156.25;
  v /= 1000;
  Serial.print(" ("); Serial.print(v); Serial.println(" uV)");
#endif
  return raw; 
}


/*********************************************************************/

uint16_t Adafruit_TMP007::read16(uint8_t a) {
  uint16_t ret;

  Wire1.beginTransmission(_addr); // start transmission to device 
#if (ARDUINO >= 100)
  Wire1.write(a); // sends register address to read from
#else
  Wire1.send(a); // sends register address to read from
#endif
  Wire1.endTransmission(); // end transmission
  
  Wire1.beginTransmission(_addr); // start transmission to device 
  Wire1.requestFrom(_addr, (uint8_t)2);// send data n-bytes read
#if (ARDUINO >= 100)
  ret = Wire1.read(); // receive DATA
  ret <<= 8;
  ret |= Wire1.read(); // receive DATA
#else
  ret = Wire1.receive(); // receive DATA
  ret <<= 8;
  ret |= Wire1.receive(); // receive DATA
#endif
  Wire1.endTransmission(); // end transmission

  return ret;
}

void Adafruit_TMP007::write16(uint8_t a, uint16_t d) {
  Wire1.beginTransmission(_addr); // start transmission to device 
#if (ARDUINO >= 100)
  Wire1.write(a); // sends register address to read from
  Wire1.write(d>>8);  // write data
  Wire1.write(d);  // write data
#else
  Wire1.send(a); // sends register address to read from
  Wire1.send(d>>8);  // write data
  Wire1.send(d);  // write data
#endif
  Wire1.endTransmission(); // end transmission
}

Adafruit_SHT30.h

C/C++
#include "application.h"
#include "Particle.h"
#include "math.h"


//by compare with a more standard temperature/humidity sensor, got the belwo calibration value
#define CALIB_TEMP  4       
#define CALIB_HUM   10



#define SHT31_DEFAULT_ADDR         0x44
#define SHT31_MEAS_HIGHREP_STRETCH 0x2C06
#define SHT31_MEAS_MEDREP_STRETCH  0x2C0D
#define SHT31_MEAS_LOWREP_STRETCH  0x2C10
#define SHT31_MEAS_HIGHREP         0x2400
#define SHT31_MEAS_MEDREP          0x240B
#define SHT31_MEAS_LOWREP          0x2416
#define SHT31_READSTATUS           0xF32D
#define SHT31_CLEARSTATUS          0x3041
#define SHT31_SOFTRESET            0x30A2
#define SHT31_HEATEREN             0x306D
#define SHT31_HEATERDIS            0x3066

class Adafruit_SHT31 {
 public:
  Adafruit_SHT31();
  boolean begin(uint8_t i2caddr = SHT31_DEFAULT_ADDR);
  float readTemperature(void);
  float readHumidity(void);
  uint16_t readStatus(void);
  void reset(void);
  void heater(boolean);
  uint8_t crc8(const uint8_t *data, int len);

 private:
  boolean readTempHum(void);
  void writeCommand(uint16_t cmd);

  uint8_t _i2caddr;
  boolean readData(void);
  float humidity, temp;
};

class SHT30{
public:
    bool setAddress(int a0);
    bool update();
    double temperature;
    double humidity;
    
private:
    int address = 0x44;
    int buffer[6] = {0,0,0,0,0,0};
};

Adafruit_SHT30.cpp

C/C++
#include "Adafruit_SHT30.h"
#define ARDUINO  200

Adafruit_SHT31::Adafruit_SHT31() {
}


boolean Adafruit_SHT31::begin(uint8_t i2caddr) {
  Wire1.begin();
  _i2caddr = i2caddr;
  reset();
  //return (readStatus() == 0x40);
  return true;
}

uint16_t Adafruit_SHT31::readStatus(void) {
  writeCommand(SHT31_READSTATUS);
  Wire1.requestFrom(_i2caddr, (uint8_t)3);
  uint16_t stat = Wire1.read();
  stat <<= 8;
  stat |= Wire1.read();
  //Serial.println(stat, HEX);
  return stat;
}

void Adafruit_SHT31::reset(void) {
  writeCommand(SHT31_SOFTRESET);
  delay(10);
}

void Adafruit_SHT31::heater(boolean h) {
  if (h)
    writeCommand(SHT31_HEATEREN);
  else
    writeCommand(SHT31_HEATERDIS);
}


float Adafruit_SHT31::readTemperature(void) {
  if (! readTempHum()) return NAN;

  return temp;
}
  

float Adafruit_SHT31::readHumidity(void) {
  if (! readTempHum()) return NAN;

  return humidity;
}


boolean Adafruit_SHT31::readTempHum(void) {
  uint8_t readbuffer[6];

  writeCommand(SHT31_MEAS_HIGHREP);
  
  delay(500);
  Wire1.requestFrom(_i2caddr, (uint8_t)6);
  if (Wire1.available() != 6) 
    return false;
  for (uint8_t i=0; i<6; i++) {
    readbuffer[i] = Wire1.read();
  //  Serial.print("0x"); Serial.println(readbuffer[i], HEX);
  }
  uint16_t ST, SRH;
  ST = readbuffer[0];
  ST <<= 8;
  ST |= readbuffer[1];

  if (readbuffer[2] != crc8(readbuffer, 2)) return false;

  SRH = readbuffer[3];
  SRH <<= 8;
  SRH |= readbuffer[4];

  if (readbuffer[5] != crc8(readbuffer+3, 2)) return false;

 // Serial.print("ST = "); Serial.println(ST);
  double stemp = ST;
  stemp *= 175;
  stemp /= 0xffff;
  stemp = -45 + stemp;
  temp = stemp-CALIB_TEMP;
  
//  Serial.print("SRH = "); Serial.println(SRH);
  double shum = SRH;
  shum *= 100;
  shum /= 0xFFFF;
  
  humidity = shum+CALIB_HUM;
  
  return true;
}

void Adafruit_SHT31::writeCommand(uint16_t cmd) {
  Wire1.beginTransmission(_i2caddr);
  Wire1.write(cmd >> 8);
  Wire1.write(cmd & 0xFF);
  Wire1.endTransmission();  
}

uint8_t Adafruit_SHT31::crc8(const uint8_t *data, int len)
{


  const uint8_t POLYNOMIAL(0x31);
  uint8_t crc(0xFF);
  
  for ( int j = len; j; --j ) {
      crc ^= *data++;

      for ( int i = 8; i; --i ) {
	crc = ( crc & 0x80 )
	  ? (crc << 1) ^ POLYNOMIAL
	  : (crc << 1);
      }
  }
  return crc;
}

main.ino

C/C++
// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_SHT30.h"

// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_TMP007.h"

//for the display theory, please refer to 
//http://www.atmel.com/images/doc8103.pdf



#define PORT_COM1 C0
#define PORT_COM2 C1
#define PORT_COM3 C2
#define PORT_COM4 C3

#define COM1    1
#define COM2    2
#define COM3    3
#define COM4    4

#define SEG_A D0
#define SEG_B D1
#define SEG_F D2
#define SEG_G D3
#define SEG_C D4
#define SEG_E D5
#define SEG_D D6
#define SEG_P D7


//this is used for polority flip 
#define POSITIVE 1
#define NEGATIVE 0

#define TEMP 1
#define HUMIDITY    2
#define UNIT_C  0xa7    //the temperature unit of 'C'       0xa6|0x01
//#define MARK_C  0x01    //the temperature mark of `round circule`
#define UNIT_H  0x7D    //the humidity unit of 'H'      0X7C|0X01
#define MARK_DOT    0x01
#define MARK_DOT_NONE   0x00


//0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90
uint8_t displayTable[10]={0xee,0x48,0xd6,0xda,0x78,0xba,0xbe,0xc8,0xfe,0xfa};



SYSTEM_MODE(MANUAL);

Adafruit_SHT31 sht31;

float t,h;
unsigned long interval = 0;

//init the GPIO for LCD display
void lcdDisplayInit(void)
{
    pinMode(C0,OUTPUT);
    pinMode(C1,INPUT);
    pinMode(C2,INPUT);
    pinMode(C3,INPUT);
    pinMode(D0,OUTPUT);
    pinMode(D1,OUTPUT);
    pinMode(D2,OUTPUT);
    pinMode(D3,OUTPUT);
    pinMode(D4,OUTPUT);
    pinMode(D5,OUTPUT);
    pinMode(D6,OUTPUT);
    pinMode(D7,OUTPUT);  
}

void loadDisplayTable(uint8_t data)
{
    
    digitalWrite(SEG_A,((data>>7)&0x01));
    digitalWrite(SEG_B,((data>>6)&0x01));    
    digitalWrite(SEG_F,((data>>5)&0x01));
    digitalWrite(SEG_G,((data>>4)&0x01));  
    digitalWrite(SEG_C,((data>>3)&0x01));
    digitalWrite(SEG_E,((data>>2)&0x01));  
    digitalWrite(SEG_D,((data>>1)&0x01));
    digitalWrite(SEG_P,((data>>0)&0x01));   
}


//displayData had beem enlarged by 10
void lcdDisplay(uint16_t displayData,uint8_t unit)
{
    static uint8_t comCounter = 1;
    static uint8_t lastDisplayData=0;
    static uint8_t firstBit=0,secondBit=0,thirdBit=0;
    static uint8_t dotDisplay = MARK_DOT;       //display the dot when in default mode
    static uint8_t comPolarity = NEGATIVE;  //the default voltage on COM port is 0v

    uint8_t tempValue = 0;
    
    if(lastDisplayData!=displayData)    //update bits only input value had changed
    {
        lastDisplayData = displayData;
        if(displayData<=999)        
        {
            firstBit = displayData/100;               
            secondBit = displayData%100/10;
            thirdBit = displayData%10; 
            dotDisplay = MARK_DOT;        //need to display dot when the value is smaller than 100degree,like 23.2 or 02.3
        }
        else       
        {
            firstBit = displayData/1000;               
            secondBit = displayData%1000/100;
            thirdBit = displayData%100/10;  //omit the last fourth bit   
            dotDisplay = MARK_DOT_NONE;    //only display integer when the value is bigger than 99.9degree   
        }
    }
    switch(comCounter)
    {
        case COM1:
            pinMode(PORT_COM2,INPUT);
            pinMode(PORT_COM3,INPUT);
            pinMode(PORT_COM4,INPUT);
            if(comPolarity==POSITIVE)
                tempValue = ~displayTable[firstBit];    
            else
                tempValue = displayTable[firstBit];    
                
            loadDisplayTable(tempValue);
            pinMode(PORT_COM1,OUTPUT);
            digitalWrite(PORT_COM1,comPolarity);
            break;
        case COM2:
            pinMode(PORT_COM1,INPUT);
            pinMode(PORT_COM3,INPUT);
            pinMode(PORT_COM4,INPUT);
            if(comPolarity==POSITIVE)
                tempValue = ~(displayTable[secondBit]|dotDisplay); 
            else
                tempValue = displayTable[secondBit]|dotDisplay;    
            loadDisplayTable(tempValue);
            pinMode(PORT_COM2,OUTPUT);
            digitalWrite(PORT_COM2,comPolarity);
            break;
        case COM3:
            pinMode(PORT_COM1,INPUT);
            pinMode(PORT_COM2,INPUT);
            pinMode(PORT_COM4,INPUT);
            if(comPolarity==POSITIVE)
                tempValue = ~displayTable[thirdBit];   
            else
                tempValue = displayTable[thirdBit];    
                
            loadDisplayTable(tempValue); 
            pinMode(PORT_COM3,OUTPUT);
            digitalWrite(PORT_COM3,comPolarity);
            break;
        case COM4:
            pinMode(PORT_COM1,INPUT);
            pinMode(PORT_COM2,INPUT);
            pinMode(PORT_COM3,INPUT);
            if(unit==TEMP)
                tempValue = UNIT_C; // UNIT_C|MARK_C;
            else
                tempValue = UNIT_H;
            if(comPolarity==POSITIVE)
                tempValue = ~tempValue;  //displayTable[firstBit]    
            loadDisplayTable(tempValue);
            pinMode(PORT_COM4,OUTPUT);
            digitalWrite(PORT_COM4,comPolarity);
            break;
        default:
            break;
    }
    /*
    comCounter++;
    if(comCounter==5)
    {
        comCounter = 1;
        comPolarity=(comPolarity==1)? 0:1;
    }
    */
    //which means one seg had finished the AC from 0-1
    if(comPolarity==1)  //0-->1--0-->1
    {
        comCounter++;
        if(comCounter==5)
        {
            comCounter=0;
            comPolarity=1;  //start from negative after execut the below program 
        }
    }
    comPolarity = (comPolarity==1)?0:1;
}



//display the seg every 2ms, which is around 60HZ
Timer timer(2,updateDisplay);
void setup(void)
{
    lcdDisplayInit();
    Serial.begin(9600);
    if (! sht31.begin(0x44)) {  
    Serial.println("Couldn't find SHT30");
    }
    timer.start();
}


void updateDisplay()
{
    lcdDisplay((uint16_t)t,TEMP);  
}


void loop(void)
{
    
    if((millis()-interval)>=1000)
    {
        interval = millis();
        t = sht31.readTemperature();
        t*=10;
        h = sht31.readHumidity();
        h*=10;
    }
    
}

Credits

Eric yuan

Eric yuan

4 projects • 1 follower

Comments