nrf52832驅(qū)動溫濕度傳感器hts221

嘗試使用TWI讀取溫度濕度傳感器hts221

hts221的介紹不細(xì)說,誤差什么的去看手冊吧~只說說它支持SPI 及 IIC通信,感覺相對來說,在傳感器方面似乎iic用的更多.因為也用到了很多其他iic的設(shè)備,所以直接使用lps22hb的iic了~

IIC通信就不多說了,直接來看hts221 iic通信的格式:
address:0x5f, 所以如果是read address為0xbf, 如果是write address為0xbe.
和一般的iic讀寫過程沒有什么區(qū)別~


hts221 IIC讀寫.png

注意:datasheet中有這樣一段話:

After the start condition (ST) a slave address is sent, once a slave acknowledge (SAK) has been returned, an 8-bit sub-address (SUB) will be transmitted: the 7 LSB represents the actual register address while the MSB enables address autoincrement. If the MSB of the SUB field is ‘1’, the SUB (register address) will be automatically increased to allow multiple data read/write.

也就是說,hts221并不想其他IIC設(shè)備一樣,連續(xù)讀寫時自動增加register地址,而是在最開始配置地址時如果bit7為1,才會自加,否則會一直讀/寫那一個寄存器地址.(最開始沒看到,發(fā)現(xiàn)連續(xù)讀總是一個值,仔細(xì)看了文檔才發(fā)現(xiàn).)

為了后面讀寫方便,寫個iic讀寫子函數(shù):

static uint32_t buf_read(uint8_t reg_addr, uint8_t * p_buf, uint32_t size)
{
    uint8_t reg=reg_addr;
    if(size>1)reg|=0x80;
    return user_drv_twi_read(HTS221_ADDR,reg,p_buf,size);
}

static uint32_t reg_write(uint8_t reg_addr, uint8_t reg_val)
{
    return user_drv_twi_tx_byte(HTS221_ADDR,reg_addr,reg_val);
}

Register address Map

之后就是register的配置了:


hts221 register

為了方便使用宏定義:

#define HTS221_WHO_AM_I_REG                         0x0F
#define HTS221_AV_CONF_REG                          0x10
#define HTS221_CTRL_REG1                            0x20
#define HTS221_CTRL_REG2                            0x21
#define HTS221_CTRL_REG3                            0x22
#define HTS221_STATUS_REG                           0x27
#define HTS221_HUMIDITY_OUT_L_REG                   0x28
#define HTS221_HUMIDITY_OUT_H_REG                   0x29
#define HTS221_TEMP_OUT_L_REG                       0x2A
#define HTS221_TEMP_OUT_H_REG                       0x2B

#define HTS221_CALIBRATION_REGS                     0x30
#define HTS221_CALIBRATION_REGS_NUM                 16

WHO_AM_I為只讀,值必須為0xbc,感覺可以使用讀這個寄存器來檢測硬件是否正常.
AV_CONF、CTRL_REG[1..3]是配置寄存器,手冊很清楚,根據(jù)手冊配置吧.
需要注意的是CALIB_0..F,校準(zhǔn)寄存器,讀取出來的值需要根據(jù)這些寄存器里的值通過計算獲得最終結(jié)果.


Decoding the coefficients in the sensor Flash

hts221初始化過程就很簡單了:
配置配置寄存器,讀取校準(zhǔn)寄存器;當(dāng)hts221準(zhǔn)備好數(shù)據(jù)時就可以讀取數(shù)據(jù),通過校準(zhǔn)數(shù)據(jù)校準(zhǔn)值.
配置就不多說,看看校準(zhǔn)相關(guān)的地方

校準(zhǔn)

校準(zhǔn)參數(shù)存在寄存器0x30-0x3f,自然需要讀出.為了方便使用這些參數(shù),根據(jù)寄存器創(chuàng)建了一個結(jié)構(gòu)體(為了簡單,直接copy自Nordic Thingy:52官方FW):

typedef struct
{
    uint8_t  H0_rH_x2;
    uint8_t  H1_rH_x2;
    uint16_t T0_degC_x8;
    uint16_t T1_degC_x8;
    int16_t  H0_T0_OUT;
    int16_t  H1_T0_OUT;
    int16_t  T0_OUT;
    int16_t  T1_OUT;
}drv_hts221_calib_t;

drv_hts221_calib_t p_calib;
    uint8_t  calib_raw[HTS221_CALIBRATION_REGS_NUM];
    err_code = user_drv_twi_read(HTS221_ADDR,HTS221_CALIBRATION_REGS,calib_raw,HTS221_CALIBRATION_REGS_NUM);
    if(err_code!=NRF_SUCCESS) return err_code;

    p_calib->H0_rH_x2   = calib_raw[0];
    p_calib->H1_rH_x2   = calib_raw[1];
    p_calib->T0_degC_x8 = (uint16_t)calib_raw[2] + ((uint16_t)(calib_raw[5] & 0x03) << 8);
    p_calib->T1_degC_x8 = (uint16_t)calib_raw[3] + ((uint16_t)((calib_raw[5] >> 2) & 0x03) << 8);
    p_calib->H0_T0_OUT  = (int16_t)calib_raw[6]  + ((int16_t)calib_raw[7]  << 8);
    p_calib->H1_T0_OUT  = (int16_t)calib_raw[10] + ((int16_t)calib_raw[11] << 8);
    p_calib->T0_OUT     = (int16_t)calib_raw[12] + ((int16_t)calib_raw[13] << 8);
    p_calib->T1_OUT     = (int16_t)calib_raw[14] + ((int16_t)calib_raw[15] << 8);

校準(zhǔn)參數(shù)獲取后就是獲取實際值計算了.
實際上就是個求解線性方程y=kx+b而已,給出的校準(zhǔn)值其實就是線性方程的兩個解,使用這兩個解求得線性方程的k b,將讀取出的值帶入求出即可.
官方給出的說明與例子:


已知兩點坐標(biāo)(x1,y1)(x2,y2),已知(x,y)中的x求y
使用(y2-y1)/(x2-x1)=(y-y1)/(x-x1) ===>y= (y2-y1)*(x-x1)/(x2-x1)+y1.
注意,最后的結(jié)果中,溫度擴(kuò)大了8倍,濕度擴(kuò)大了2倍.
由于溫度精確到了小數(shù)點1位,所以擴(kuò)大了10倍后右移3位(相當(dāng)于除8)
濕度通常只需要精確到個位,所以直接右移1位(相當(dāng)于除2)

    uint32_t err_code;
    NRF_LOG_DEBUG("HTS221 handler:%d,%d",pin,action);
    uint8_t sample_data[4];
    err_code=buf_read(HTS221_HUMIDITY_OUT_L_REG,sample_data,4);
        APP_ERROR_CHECK(err_code);
        Humidity=(int16_t)sample_data[0]  + ((int16_t)sample_data[1]  << 8);
    Temperature=(int16_t)sample_data[2]  + ((int16_t)sample_data[3]  << 8);
    NRF_LOG_INFO("humidity:0x%x%x",sample_data[1],sample_data[0]);
    NRF_LOG_INFO("Temperature:0x%x",Temperature);


    int16_t tep=((((int16_t)Temperature-(int16_t)p_calib.T0_OUT)*((int16_t)p_calib.T1_degC_x8-(int16_t)p_calib.T0_degC_x8)/((int16_t)p_calib.T1_OUT-(int16_t)p_calib.T0_OUT)+(int16_t)p_calib.T0_degC_x8)*10)>>3;
    int16_t hum=(((int16_t)Humidity-(int16_t)p_calib.H0_T0_OUT)*((int16_t)p_calib.H1_rH_x2-(int16_t)p_calib.H0_rH_x2)/((int16_t)p_calib.H1_T0_OUT-(int16_t)p_calib.H0_T0_OUT)+(int16_t)p_calib.H0_rH_x2)>>1;
        //Humidity range
        if(hum>100)hum=100;
        else if(hum<0) hum=0;
    
    NRF_LOG_INFO("Temperature:%d.%d     Humidity:%d",tep/10,tep%10,hum);

到此基本就結(jié)束了,不過因為使用了hts221的DRDY,所以在nrf52832中,讀取溫濕度時只是啟動hts221了,在DRDY的事件中進(jìn)行讀取溫濕度值.
以下為主要的初始化及讀取溫濕度值代碼,與上面的有部分重復(fù).

void user_hts221_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    uint32_t err_code;
    NRF_LOG_DEBUG("HTS221 handler:%d,%d",pin,action);
    uint8_t sample_data[4];
    err_code=buf_read(HTS221_HUMIDITY_OUT_L_REG,sample_data,4);
        APP_ERROR_CHECK(err_code);
        Humidity=(int16_t)sample_data[0]  + ((int16_t)sample_data[1]  << 8);
    Temperature=(int16_t)sample_data[2]  + ((int16_t)sample_data[3]  << 8);
    NRF_LOG_INFO("humidity:0x%x%x",sample_data[1],sample_data[0]);
    NRF_LOG_INFO("Temperature:0x%x",Temperature);


    int16_t tep=((((int16_t)Temperature-(int16_t)p_calib.T0_OUT)*((int16_t)p_calib.T1_degC_x8-(int16_t)p_calib.T0_degC_x8)/((int16_t)p_calib.T1_OUT-(int16_t)p_calib.T0_OUT)+(int16_t)p_calib.T0_degC_x8)*10)>>3;
    int16_t hum=(((int16_t)Humidity-(int16_t)p_calib.H0_T0_OUT)*((int16_t)p_calib.H1_rH_x2-(int16_t)p_calib.H0_rH_x2)/((int16_t)p_calib.H1_T0_OUT-(int16_t)p_calib.H0_T0_OUT)+(int16_t)p_calib.H0_rH_x2)>>1;
        //Humidity range
        if(hum>100)hum=100;
        else if(hum<0) hum=0;
    
    NRF_LOG_INFO("Temperature:%d.%d     Humidity:%d",tep/10,tep%10,hum);
    user_ble_gatts_notify(tep);
}

void user_hts221_init()
{
    uint32_t err_code;
    uint8_t  calib_raw[HTS221_CALIBRATION_REGS_NUM];


    err_code=user_drv_twi_tx_byte(HTS221_ADDR,0x20,0x80);   //active mode   One-shot
    err_code=user_drv_twi_tx_byte(HTS221_ADDR,0x22,0x84);   //active low

    uint8_t reg_val;
    err_code=user_drv_twi_read_byte(HTS221_ADDR,HTS221_WHO_AM_I_REG,&reg_val);
    if(err_code!=NRF_SUCCESS) NRF_LOG_ERROR("HTS221 user_drv_twi_read_byte error:%x",err_code);

    if(reg_val!=HTS221_WHO_AM_I_VAL)
    {
        NRF_LOG_ERROR("HTS221 verify error:%x",reg_val);
    } else  NRF_LOG_INFO("HTS221 verify ok");

    buf_read(HTS221_CALIBRATION_REGS,calib_raw,HTS221_CALIBRATION_REGS_NUM);
    p_calib.H0_rH_x2   = calib_raw[0];
    p_calib.H1_rH_x2   = calib_raw[1];
    p_calib.T0_degC_x8 = (uint16_t)calib_raw[2] + ((uint16_t)(calib_raw[5] & 0x03) << 8);
    p_calib.T1_degC_x8 = (uint16_t)calib_raw[3] + ((uint16_t)((calib_raw[5] >> 2) & 0x03) << 8);
    p_calib.H0_T0_OUT  = (int16_t)calib_raw[6]  + ((int16_t)calib_raw[7]  << 8);
    p_calib.H1_T0_OUT  = (int16_t)calib_raw[10] + ((int16_t)calib_raw[11] << 8);
    p_calib.T0_OUT     = (int16_t)calib_raw[12] + ((int16_t)calib_raw[13] << 8);
    p_calib.T1_OUT     = (int16_t)calib_raw[14] + ((int16_t)calib_raw[15] << 8);

    if(!nrf_gpio_pin_read(HT_INT))
    {
        user_hts221_handler(HT_INT,NRF_GPIOTE_POLARITY_HITOLO);
    }

    if(!nrfx_gpiote_is_init())
    {
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);

    }

    nrf_drv_gpiote_in_config_t in_config =
    {
        .is_watcher = false,
        .hi_accuracy = true,
        .sense = NRF_GPIOTE_POLARITY_HITOLO,
        .pull = NRF_GPIO_PIN_PULLUP,
    };


    err_code = nrf_drv_gpiote_in_init(HT_INT, &in_config, user_hts221_handler);
    APP_ERROR_CHECK(err_code);
    nrf_drv_gpiote_in_event_enable(HT_INT, true);
        
}

void user_hts221_conversion_start()
{
    uint32_t err_code;
    NRF_LOG_DEBUG("HTS221 conversion start");
    err_code=user_drv_twi_tx_byte(HTS221_ADDR,0x21,0x01);
    APP_ERROR_CHECK(err_code);
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容