nrf52832驱动温湿度传感器hts221

尝试使用TWI读取温度湿度传感器hts221

hts221的介绍不细说,误差什么的去看手册吧~只说说它支持SPI 及 IIC通信,感觉相对来说,在传感器方面似乎iic用的更多.因为也用到了很多其他iic的设备,所以直接使用lps22hb的iic了~

IIC通信就不多说了,直接来看hts221 iic通信的格式:
address:0x5f, 所以如果是read address为0xbf, 如果是write address为0xbe.
和一般的iic读写过程没有什么区别~


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设备一样,连续读写时自动增加register地址,而是在最开始配置地址时如果bit7为1,才会自加,否则会一直读/写那一个寄存器地址.(最开始没看到,发现连续读总是一个值,仔细看了文档才发现.)

为了后面读写方便,写个iic读写子函数:

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]是配置寄存器,手册很清楚,根据手册配置吧.
需要注意的是CALIB_0..F,校准寄存器,读取出来的值需要根据这些寄存器里的值通过计算获得最终结果.


Decoding the coefficients in the sensor Flash

hts221初始化过程就很简单了:
配置配置寄存器,读取校准寄存器;当hts221准备好数据时就可以读取数据,通过校准数据校准值.
配置就不多说,看看校准相关的地方

校准

校准参数存在寄存器0x30-0x3f,自然需要读出.为了方便使用这些参数,根据寄存器创建了一个结构体(为了简单,直接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);

校准参数获取后就是获取实际值计算了.
实际上就是个求解线性方程y=kx+b而已,给出的校准值其实就是线性方程的两个解,使用这两个解求得线性方程的k b,将读取出的值带入求出即可.
官方给出的说明与例子:


已知两点坐标(x1,y1)(x2,y2),已知(x,y)中的x求y
使用(y2-y1)/(x2-x1)=(y-y1)/(x-x1) ===>y= (y2-y1)*(x-x1)/(x2-x1)+y1.
注意,最后的结果中,温度扩大了8倍,湿度扩大了2倍.
由于温度精确到了小数点1位,所以扩大了10倍后右移3位(相当于除8)
湿度通常只需要精确到个位,所以直接右移1位(相当于除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);

到此基本就结束了,不过因为使用了hts221的DRDY,所以在nrf52832中,读取温湿度时只是启动hts221了,在DRDY的事件中进行读取温湿度值.
以下为主要的初始化及读取温湿度值代码,与上面的有部分重复.

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,®_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);
}

你可能感兴趣的:(nrf52832驱动温湿度传感器hts221)