K210(SiPEED MaixBit)MicroPython使用参考(九、温湿度传感器HTS221驱动)

11 篇文章 8 订阅

1.HTS221是ST出品的电容式温湿度数字传感器,工作电压1.7-3.6V,温度测量范围-40°C-120°C,湿度测量范围0-100%,16位数据输出,提供SPI和I²C数据接口。其器件地址(device address)如下,即读时为BF,写时BE,若只用7位则为5F(即下表的SAD):

1)寄存器地址如下:

2)寄存器30-3F被称做Calibration registers,意思是校准寄存器,这是因为在制造时都存在个体差异,出厂时将校准数据写入该寄存器,正常使用时加入校准数据,这也是很多传感器的常规做法。

不过需要注意的是,H0_rH_x2和H1_rH_x2所存储值是真实校准值的2倍,猜测有以下原因:提高精度,制造方便,计算简单且快速。T0_degC_x8和T1_degC_x8亦是如此。另外,H_OUT,T_OUT,H0_T0_OUT ,H1_T0_OUT,T0_OUT和T1_OUT的数据类型都是s16,官方资料说的是“signed 16-bit quantity using two's complement”,有符号的16位数,最高位为0时表示整数,最高位为1时表示负数,参考计算如下(以8位二进数为例):

但实际上,绝大多数参考代码均将之看作是无符号的16位数,并没有特意处理,即默认该寄存器最大值是32767,最小值是0。

2.官方资料提供的计算步骤
1)温度计算:
The steps for the temperature conversion from ADC_OUT (LSB) to °C are described as follows: 
(1)Read the value of coefficients T0_degC_x8 and T1_degC_x8 from registers 0x32 & 0x33
(2)Divide by 8 the content of registers 0x32 (T0_degC_x8) and 0x33 (T1_degC_x8) in order to obtain the value of coefficients T0_degC and T1_degC
(3)Read the MSB bits of T1_degC (T1.9 and T1.8 bit) and T0_degC (T0.9 and T0.8 bit) from register 0x35 to compute T0_DegC and T1_DegC
(4)Read from registers 0x3C & 0x3D the value of T0_OUT
(5)Read the value of T1_OUT from registers 0x3E & 0x3F
(6)Read the value T_OUT (ADC_OUT) from 0x2A & 0x2B registers
(7)Compute the T [degC] value, by linear interpolation, applying the following formula:


2)湿度计算:
The steps for the humidity conversion from ADC_OUT (LSB) to RH % are described as follows:
(1)Read the value of coefficients H0_rH_x2 and H1_rH_x2 from registers 0x30 & 0x31
(2)Divide by two the content of registers 0x30 (H0_rH_x2) and 0x31 (H1_rH_x2) in order to obtain the value of coefficients H0_rH and H1_rH
(3)Read the value of H0_T0_OUT from registers 0x36 & 0x37
(4)Read the value of H1_T0_OUT from registers 0x3A & 0x3B
(5)Read the humidity value in raw counts H_T_OUT from registers 0x28 & 0x29
(6)Compute the RH [%] value, by linear interpolation, applying the formula below:

3.温湿度计算具体实现

1)官方资料的温湿度计算(C语言)

读出T0_degC_x8,T1_degC_x8
读T0_T1_DEGC_H2得到四位数tmp
T0_degC_x8,T1_degC_x8除以8后在最高位前,分别加tmp的末前两位得到T0_degC,T1_degC
读出T0_out
读出T1_out
读出T_out
计算出tmp32=(T_out-T0_out)*(T1_degC-T0_degC)*10
计算出温度值value=tmp32/(T1_out-T0_out)+T0_out*10

读H0_RH_X2,H1_RH_X2并除以2得到H0_rh,H1_rh
读H0_T0_OUT得到H0_T0_out
读H1_T0_OUT得到H1_T0_out
读H_T_OUT得到H_T_out
计算出tmp=(H_T_out-H0_T0_out)*(H1_rh-H0_rh)*10
计算出湿度值value=tmp/(H1_T0_out-H1_T0_out)+H1_T0_out*10

需要注意的是:返回的湿度值是1000制,源代码有判断语句,超过1000按照1000处理(可见该传感器测湿度很不准)

2)Arduino的温湿度计算方式(Nano 33 BLE Sense)

读T0_degC_x8_REG、T1_degC_x8_REG和T1_T0_MSB_REG得到t0degC、t1degC
读取得到t0Out、t1Out
计算出hts221TemperatureSlope = (t1degC - t0degC) / (8.0 * (t1Out - t0Out))
计算出_hts221TemperatureZero = (t0degC / 8.0) - _hts221TemperatureSlope * t0Out
读取HTS221_TEMP_OUT得到tout
计算出温度值tout * _hts221TemperatureSlope + _hts221TemperatureZero

读取得到h0rH、 h1rH
读取得到h0t0Out、h1t0Out
计算出_hts221HumiditySlope = (h1rH - h0rH) / (2.0 * (h1t0Out - h0t0Out))
计算出_hts221HumidityZero = (h0rH / 2.0) - _hts221HumiditySlope * h0t0Out
读取HTS221_HUMIDITY_OUT得到hout
计算出湿度值hout * _hts221HumiditySlope + _hts221HumidityZero

3)shaoziyang的MicroPython驱动

读出T0_OUT,T1_OUT
读T1/T0 msb寄存器(0x35)取低4位为t
读寄存器0x32,0x33,分别加上t的低高2位,计算出T0_degC,T1_degC
计算出K1=(T1_degC - T0_degC) / (T1_OUT -T0_OUT)
计算出(T0_degC + (get2reg(0x2A)-T0_OUT) *K1)/8

读出H0_OUT,H1_OUT
读寄存器0x30,0x31,乘5,计算出H0_rH,H1_rH
计算出K2=(H1_rH -H0_rH) / (H1_OUT -H0_OUT)
计算出(H0_rH + (get2reg(0x28) - H0_OUT) *K2)/10

该代码是少有的对有符号数据进行处理的,实测湿度结果略有差异,温度则相同。实际上,可能因为器件老化等原因,湿度测量数据很不准,数值很容易超过阈值,无法反映实际情况。另外,shaoziyang的驱动代码中还有使用中断获得数据的函数,计算方法类似,经过简化导致精度略低但速度更快。

4.ST有一款X-NUCLEO-IKS01A1扩展板,集成有HTS221传感器,具体如下:

5.shaoziyang驱动代码如下,需要将之命名为HTS221.py,注意是大写字母,并将之“发送文件到开发板”:

# HTS221 Humidity and temperature micropython drive
# ver: 2.0
# License: MIT
# Author: shaoziyang (shaoziyang@micropython.org.cn)
# v1.0 2016.4
# v2.0 2019.7

from machine import I2C

class HTS221(object):
    def __init__(self, i2c):
        self.i2c = i2c
        self.addr = 0x5F
        # data buffer
        self.tb = bytearray(1)
        self.rb = bytearray(1)
        self.oneshot = False
        self.irq_v = [0, 0]
        # HTS221 Temp Calibration registers
        self.T0_OUT = self.int16(self.get2reg(0x3C))
        self.T1_OUT = self.int16(self.get2reg(0x3E))
        t = self.getreg(0x35) % 16
        self.T0_degC = self.getreg(0x32) + (t%4) * 256
        self.T1_degC = self.getreg(0x33) + (t//4) * 256
        # HTS221 Humi Calibration registers
        self.H0_OUT = self.int16(self.get2reg(0x36))
        self.H1_OUT = self.int16(self.get2reg(0x3A))
        self.H0_rH = self.getreg(0x30) * 5
        self.H1_rH = self.getreg(0x31) * 5
        self.K1 = (self.T1_degC - self.T0_degC) / (self.T1_OUT - self.T0_OUT)
        self.K2 = (self.H1_rH - self.H0_rH) / (self.H1_OUT - self.H0_OUT)
        # set av conf: T=4 H=8
        self.setreg(0x10, 0x26)
        # set CTRL_REG1: PD=1 BDU=1 ODR=1
        self.setreg(0x20, 0x85)
        self.oneshot_mode(0)

    def oneshot_mode(self, oneshot = None):
        if oneshot is None:
            return self.oneshot
        else:
            self.getreg(0x20)
            self.oneshot = oneshot
            if oneshot: self.rb[0] &= 0xFC
            else: self.rb[0] |= 0x01
            self.setreg(0x20, self.rb[0])

    def ONE_SHOT(self, b):
        if self.oneshot:
            self.setreg(0x21, self.getreg(0x21) | 0x01)
            self.getreg(0x2d - b*2)
            while 1:
                if self.getreg(0x27) & b:
                    return

    def int16(self, d):
        return d if d < 0x8000 else d - 0x10000

    def setreg(self, reg, dat):
        self.tb[0] = dat
        self.i2c.writeto_mem(self.addr, reg, self.tb)

    def getreg(self, reg):
        self.i2c.readfrom_mem_into(self.addr, reg, self.rb)
        return self.rb[0]
   
    def get2reg(self, reg):
        return self.getreg(reg) + self.getreg(reg+1) * 256

    # calculate Temperature
    def temperature(self):
        try:
            self.ONE_SHOT(1)
            return round((self.T0_degC + (self.int16(self.get2reg(0x2A)) - self.T0_OUT) * self.K1)/8, 1)
        except MemoryError:
            return self.temperature_irq()

    # calculate Humidity
    def humidity(self):
        try:
            self.ONE_SHOT(2)
            return round((self.H0_rH + (self.int16(self.get2reg(0x28)) - self.H0_OUT) * self.K2)/10, 1)
        except MemoryError:
            return self.humidity_irq()

    def get(self):
        try:
            return self.temperature(), self.humidity()
        except MemoryError:
            return self.get_irq()

    def temperature_irq(self):
        self.ONE_SHOT(1)
        return (self.T0_degC + (self.int16(self.get2reg(0x2A)) - self.T0_OUT) * (self.T1_degC - self.T0_degC) // (self.T1_OUT - self.T0_OUT)) >> 3

    def humidity_irq(self):
        self.ONE_SHOT(2)
        return (self.H0_rH + (self.int16(self.get2reg(0x28)) - self.H0_OUT) * (self.H1_rH - self.H0_rH) // (self.H1_OUT - self.H0_OUT))//10

    def get_irq(self):
        self.irq_v[0] = self.temperature_irq()
        self.irq_v[1] = self.humidity_irq()
        return tuple(self.irq_v)

    def power(self, on=None):
        self.getreg(0x20)
        if on is None: return self.rb[0] & 0x80 > 0
        elif on: self.rb[0] |= 0x80
        else: self.rb[0] &= 0x7F 
        self.setreg(0x20, self.rb[0])

将HTS221接入电源,并将SCL、SDA分别连入K210的7脚和6脚,运行以下测试代码:

from machine import I2C,Timer
import time
import HTS221
i2c = I2C(I2C.I2C0, freq=100000, scl=7, sda=6)
devices = i2c.scan()
print(devices)
hts = HTS221.HTS221(i2c)
while True:
  time.sleep(1)
  print(hts.get())

i2c.scan返回I2C总线上所有的从机地址(故而可以用作I2C检测器),对于X-NUCLEO-IKS01A1来说,共有4个,分别是30(0x1E,LIS3MDL),93(0x5D,LPS25HB),95(0x5F,HTS221),107(0x6B,LSM6DSO)。hts.get返回值有两个,前者是温度,还算准确,后者是湿度,可能会相当不准,甚至于超过100。

6.HTS211的DatasheetHTS221温湿度传感器datasheet(英文)-OS文档类资源-CSDN文库

使用指南HTS221温湿度传感器的使用指南,官方所提供的资料-OS文档类资源-CSDN文库

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SDAU2005

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值