TI HDC1000 Temperature and Humidity Sensor

Dependents:   test_HDC1000

HDC1000.cpp

Committer:
Rhyme
Date:
2017-04-18
Revision:
2:f574cd898cba
Parent:
1:f2c04c5b28ab

File content as of revision 2:f574cd898cba:

#include "mbed.h"
#include "HDC1000.h"

#define REG_TEMPERATURE    0x00
#define REG_HUMIDITY       0x01
#define REG_CONFIGURATION  0x02
#define REG_ID_FIRST_WORD  0xFB
#define REG_ID_SECOND_WORD 0xFC
#define REG_ID_LAST_BYTE   0xFD
#define REG_MANUFACTURE_ID 0xFE
#define REG_DEVICE_ID      0xFF

/* Bit field of Configuration register */
/* bit[15]     RST Sowtware Rest Bit 0: Normal 1: Reset
 * bit[14:13] (Reserved) must be 00
 * bit[12]     MODE 0:Aquire Temp/Hum separately(16bit each) 1:Aquire both Temp/Hum same time (32bit)
 * bit[11]     BTST  Battery Test(?) 0:VDD > 2.8V 1:VDD < 2.8V
 * bit[10]     TRES  Temperature Resolution 0:14bit 1:11bit
 * bit[9:8]    HRES  Humidity Resolution 00:14bit 01:11bit 10:8bit
 * bit[7:0]    (Reserved) must be 00000000
 */
#define BIT_RESET          0x8000
#define BIT_MODE           0x1000
#define BIT_BTST           0x0800
#define BIT_TRES           0x0400
#define BIT_HRES14         0x0000
#define BIT_HRES11         0x0100
#define BIT_HRES08         0x0200

#if USE_READY_PIN
HDC1000::HDC1000(PinName sda, PinName scl, PinName rdy, int addr) : m_i2c(sda, scl), m_rdy(rdy), m_addr(addr<<1) {
#else
HDC1000::HDC1000(PinName sda, PinName scl, int addr) : m_i2c(sda, scl), m_addr(addr<<1) {
#endif
    // activate the peripheral
}

HDC1000::~HDC1000(void)
{
}

void HDC1000::reset(void)
{
    uint16_t conf = 0x8000 ;
    setConfig(conf) ;
}

float    HDC1000::u2f_temp(uint16_t utemp) 
{
    float ftemp ;
    
    utemp = (utemp >> 2) & 0x3FFF ;
    // note: the data sheet suggests to use 0x10000 for denominator
    // but to allow 100% I chose 0xFFFF instead, I may be wrong
    ftemp = ((float)(utemp)/ (float)0x3FFF)*165.0 - 40.0 ;
    return( ftemp ) ;
}

float    HDC1000::u2f_hume(uint16_t uhume) 
{
    float fhume ;
    uhume = (uhume>>2) & 0x3FFF ;
    
    // note: the data sheet suggests to use 0x10000 for denominator
    // but to allow 100% I chose 0xFFFF instead, I may be wrong
    fhume = ((float)(uhume) / (float)0x3FFF) * 100.0 ;
    return( fhume ) ;
}

float    HDC1000::readTemperature(void) 
{
    uint16_t utemp, uhum ;
    int mode ;
    float ftemp ;

    mode = getMode() ;
    switch(mode) {
    case 0: /* temp or hum can be acquired */
        utemp = getTemperature() ;
        break ;
    case 1: /* temp and hum can be acquired */
        getData(&utemp, &uhum) ;
        break ;
    default:
        printf("Error: unexpected mode %d\n",mode) ;
        break ;
    }

//    printf("utemp = 0x%04X ", utemp) ;
    ftemp = u2f_temp(utemp) ;
    return( ftemp ) ;
}

float    HDC1000::readHumidity(void) 
{
    uint16_t utemp, uhume ;
    int mode ;
    float fhume ;

    mode = getMode() ;
    switch(mode) {
    case 0: /* temp or hum can be acquired */
        uhume = getHumidity() ;
        break ;
    case 1: /* temp and hum can be acquired */
        getData(&utemp, &uhume) ;
        break ;
    default: 
        printf("Error: unexpected mode %d\n",mode) ;
        break ;
    }

//    printf("uhume = 0x%04X\n", uhume) ;
    fhume = u2f_hume(uhume) ;
    return( fhume ) ;
}

void HDC1000::readData(float *ftemp, float *fhume)
{
    uint16_t utemp, uhume ;
    getData(&utemp, &uhume) ;
//    printf("utemp: 0x%04X, uhume: 0x%04X\n", utemp, uhume) ;
    *ftemp = u2f_temp(utemp) ;
    *fhume = u2f_hume(uhume) ;
}

/* for mode 0 */
uint16_t HDC1000::getTemperature(void) 
{
    uint16_t temp ;
    uint8_t data[2] ;
#if USE_READY_PIN
    float delay ;
#endif
    data[0] = REG_TEMPERATURE ;
    data[1] = (m_addr << 1) | 0x01 ;
    m_i2c.write(m_addr, (const char*)data, 2, true);
    
#if USE_READY_PIN
    while(m_rdy == 1) { } /* wait for rdy */
#else
    delay = getTDelay() ;
    printf("Temp Delay = %.2f\n", delay) ;
    wait_us(1000 * delay) ;
#endif

    m_i2c.read(m_addr, (char *)data, 2);
    temp = (data[0] << 8) | data[1] ;
    return( temp ) ;
}

uint16_t HDC1000::getHumidity(void) 
{
    uint16_t hume ;
    uint8_t data[2] ;
 #if USE_READY_PIN
    float delay ;
#endif

    data[0] = REG_HUMIDITY ;
    data[1] = (m_addr << 1) | 0x01 ;
    m_i2c.write(m_addr, (const char*)data, 2, true);
    
#if USE_READY_PIN
    while(m_rdy == 1) { } /* wait for rdy */
#else
    delay = getHDelay() ;
printf("Hume Delay = %.2f\n", delay) ;
    wait_us(1000 * delay) ;
#endif

    m_i2c.read(m_addr, (char *)data, 2);
    hume = (data[0] << 8) | data[1] ;
    return( hume ) ;
}

/* for mode 1 */
void     HDC1000::getData(uint16_t *temp, uint16_t *hume) 
{
    uint8_t data[4] = { 0, 0, 0, 0 } ;
    int mode ;
#if USE_READY_PIN
    float delay ;
#endif

    mode = getMode() ;
    if (mode == 0) {
        *temp = getTemperature() ;
        *hume = getHumidity() ;
    } else { /* mode == 1 */
        data[0] = REG_TEMPERATURE ;
        data[1] = (m_addr << 1) | 0x01 ;
        m_i2c.write(m_addr,(const char *)data, 2, false);
#if USE_READY_PIN  
        while(m_rdy == 1) { } /* wait for rdy */
#else
 delay = getTDelay() + getHDelay() ;
 printf("Delay = %.2f ms\n", delay) ;
 wait( delay / 1000.0 ) ;
#endif
        m_i2c.read(m_addr, (char *)data, 4);
        *temp = (data[0] << 8) | data[1] ;
        *hume = (data[2] << 8) | data[3] ;
    }
}

void     HDC1000::setConfig(uint16_t conf) 
{
    uint8_t data[3] ;
    data[0] = REG_CONFIGURATION ;
    data[1] = (conf >> 8) & 0xFF ;
    data[2] = conf & 0xFF ;
    writeRegs(data, 3) ;
}

uint16_t HDC1000::getConfig(void) 
{
    uint8_t data[2] ;
    uint16_t conf ;
    readRegs(REG_CONFIGURATION, data, 2) ;
    conf = (data[0] << 8) | data[1] ;
    return( conf ) ;
}

void     HDC1000::setMode(int mode) 
{
    uint16_t conf ;
    conf = getConfig() ;
    if (mode) {
        conf |= BIT_MODE ;
    } else {
        conf ^= BIT_MODE ;
    }
    setConfig( conf ) ;
}

int      HDC1000::getMode(void) 
{
    uint16_t conf ;
    int mode ;
    conf = getConfig() ;
    if (conf & BIT_MODE) {
        mode = 1 ;
    } else {
        mode = 0 ;
    }
    return( mode ) ;
}

void     HDC1000::setTres(int tres) 
{
    uint16_t conf ;
    conf = getConfig() ;
    if (tres) {
        conf |= BIT_TRES ;
    } else {
        conf ^= BIT_TRES ;
    }
}

int      HDC1000::getTres(void) 
{
    uint16_t conf ;
    int tres ;
    conf = getConfig() ;
    if (conf & BIT_TRES) {
        tres = 1 ;
    } else {
        tres = 0 ;
    }
    return( tres ) ;
}

void     HDC1000::setHres(int hres) 
{
    uint16_t conf ;
    conf = getConfig() ;
    conf ^= (BIT_HRES11 | BIT_HRES08) ;
    conf |= ((hres & 0x03) << 8) ;
}

int      HDC1000::getHres(void) 
{
    uint16_t conf ;
    int hres ;
    conf = getConfig() ;
    hres = (conf >> 8)&0x03 ;
    return( hres ) ;
}

void     HDC1000::getSerialID(uint8_t data[]) 
{
    uint8_t udata[2] ;
    readRegs(REG_ID_FIRST_WORD,  &data[0], 2) ;
    readRegs(REG_ID_SECOND_WORD, &data[2], 2) ;
    readRegs(REG_ID_LAST_BYTE,      udata, 2) ;
    data[4] = udata[0] ;
}

uint16_t HDC1000::getManufactureID(void)  /* 0x5449 : Texas Instruments */
{
    uint8_t data[2] ;
    uint16_t id ;
    readRegs(REG_MANUFACTURE_ID, data, 2) ;
    id = (data[0] << 8) | data[1] ;
    return( id ) ;
}

uint16_t HDC1000::getDeviceID(void)     /* 0x1000 */
{
    uint8_t data[2] ;
    uint16_t id ;
    readRegs(REG_DEVICE_ID, data, 2) ;
    id = (data[0] << 8) | data[1] ;
    return( id ) ;
}

float    HDC1000::getTDelay(void) 
{
    int   tres ;
    float tdelay ;
    
    tres = getTres() ;
        switch(tres) {
    case 0: /* 14bit */
        tdelay = 6.35 ;
        break ;
    case 1: /* 11bit */
        tdelay = 3.65 ;
        break ;
    default:
        tdelay = 6.35 ;
        break ;
    }
    return(tdelay) ;
}

float    HDC1000::getHDelay(void) 
{
    int   hres ;
    float hdelay ;

    hres = getHres() ;
    switch(hres) {
    case 0: /* 14bit */
        hdelay = 6.5 ;
        break ;
    case 1: /* 11bit */
        hdelay = 3.85 ;
        break ;
    case 2: /*  8bit */
        hdelay = 2.5 ;
        break ;
    default:
        hdelay = 6.5 ; /* let's use the longest value */
        break ;
    }
    return(hdelay) ;
}

float    HDC1000::getDelay(void) 
{
    float tdelay, hdelay ;
    tdelay = getTDelay() ;
    hdelay = getHDelay() ;
    return( tdelay + hdelay ) ;
}

void HDC1000::readRegs(int addr, uint8_t * data, int len) {
    char t[1] = {addr};
    m_i2c.write(m_addr, t, 1, true);
    m_i2c.read(m_addr, (char *)data, len) ;
}

void HDC1000::writeRegs(uint8_t * data, int len) {
    m_i2c.write(m_addr, (char *)data, len);
}