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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容