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文库