MM32F3277 I2C 访问 HTS221 温湿度传感器
MM32F3277 I2C 访问 HTS221 温湿度传感器
主控芯片:MM32F3277
传感器:HTS221 温湿度传感器
开发环境:IAR 7.80.4
I2C 原理
I2C 总线接口使用两条串行线,SDA 和 SCL,分别用于数据和时钟的传输,工作方式是半双工。I2C 分为主从模式,Master 和 Slave,每一个 I2C 设备都有一个固定的地址。
I2C 总线物理拓扑结构
主控作为 Master,总线上可以挂多个 Slave 设备,Master 通过寻址控制各个 Slave
SCL 和 SDA 在总线空闲时,由上拉电阻拉高,保持高电平
I2C Start / Stop 条件
START 和 STOP 位由 Master 发送,
- Start:SCL 为高时,SDA 从高到低
- DATA:SCL 为高时获取稳定数据,SCL 为低时数据高低变化
- Stop:SCL 为高时,SDA 从低到高
I2C 寻址
MM32F3277 支持 7 位和 10 位地址,Master 发送 START 位之后,发送 Slave 的地址,如果 Slave 地址匹配上,Slave 应答 SAK
Read 为 1,Write 为 0
- 7 位地址
- 10 位地址
I2C Master 发送
Master 发送 DATA 后,Slave 回应 SAK;Master 发送完 DATA 后,产生 STOP 信号
I2C Master 接收
Master 接收 DATA 后,回应 MAK;接收完所有的 DATA 后,回应 NMAK,产生 STOP 信号
HTS221 温湿度传感器
[ST HTS221 温湿度传感器资料][hts221]
Features
- 16-bit humidity and temperature output data
- Embedded 16-bit ADC
- SPI and I2C interface
- Humidity accuracy: ± 3.5% rH, 20 to +80% rH
- Temperature accuracy: ±0.5℃, 15 to +40℃
Pin
- VDD: Power supply
- SCL / SPC: I2C serial clock / SPI serial port clock
- DRDY: Data Ready output signal
- SDA / SDI / SDO: I2C serial data / 3-wrie SPI serial data input or output
- GND: Ground
- CS: Set 1 when use I2C; Set 0 when use SPI
这里选择通过 I2C 进行通讯,所以 CS 管脚接 VDD (或者不接,内部可以上拉);若果选择 SPI 进行通讯,需要将 CS 管脚接地。
SCL 和 SDA 两个管脚必须是通过上拉电阻连接到 VDD!!!因为 START 信号是 SDA 由高到低,所以得先把 SDA 拉高。
HTS221 Address
HTS221 作为 I2C Slave,其地址为:
// HTS221 Address
#define SLAVE_ADDRESS 0x5F
#define SLAVE_ADDRESS_WRITE SLAVE_ADDRESS << 1 // 0xBE
#define SLAVE_ADDRESS_READ (SLAVE_ADDRESS << 1) | 0x01 // 0xBF
Master write data to Slave
Steps:
-
Master 发送 START 信号(SCL hold high, SDA high to low)
-
Master 发送 Slave 的 7 位地址 + 写信号
-
Slave 进行地址匹配,匹配成功回应 SAK
-
Master 发送 SubAddress,即 Slave 内部寄存器地址
如果一次 I2C 数据传输只操作一个寄存器
#define HTS221_CTRL_REG1 0x20 HTS221_Reg_Write(I2Cx, HTS221_CTRL_REG1, buffer, 1)
如果一次 I2C 数据传输操作多个地址连续的寄存器,将 SubAddr 的 MSB 置 1,SubAddr[6:0] 为寄存器地址
#define CONTINUOUS_ADDRESS(REG_ADDR) REG_ADDR | 0x80 HTS221_Reg_Write(I2Cx, CONTINUOUS_ADDRESS(HTS221_CTRL_REG1), buffer, 3)
-
Slave 应答 SubAddr
-
Master 发送 DATA,Slave 应答 SAK
-
Master 发送完后,产生 STOP 信号(SCL hold high, SDA lowto high)
Master read data from Slave
Steps:
- Master 发送 START 信号(SCL hold high, SDA high to low)
- Master 发送 Slave 的 7 位地址 + 写信号
- Slave 进行地址匹配,匹配成功回应 SAK
- Master 发送 SubAddress,即 Slave 内部寄存器地址,操作同上
- Slave 应答 SubAddr
- Master 发送 RESTART 信号,重新发送 Slave 的 7 位地址 + 读信号,Slave 回应 SAK
- Slave 发送 Data,Master 应答 MAK
- Master 接收最后一个数据后,不应答 NMAK,产生 STOP 信号(SCL hold high, SDA lowto high)
Register Map
-
WHO_AM_I
Reg Address is 0x0F, read only and default is 0xBC
// HTS221 Device ID #define DEVICE_ID_WHO_AM_I 0xBC
-
AV_CONF
Reg Address is 0x10, R/W and default is 0x1B
该寄存器主要控制温度和湿度的样本个数
-
CTRL_REG1
Reg Address is 0x20, R/W and default is 0x00
-
PD
控制传感器开关,置 1 为 active;置 0 为 power-down -
BDU
控制 MSB 和 LSB 数据读取的连续性,置 1 为读完 MSB 和 LSB 之后再更新输出数据;置 0 为实时更新,可能会导致读取的 MSB 和 LSB 不是同一组 -
ODR1
/ODR0
控制数据读取频率,00 为 one-shot,01 为 1Hz,10 为 7Hz,11 为 12.5Hz
-
-
CTRL_REG2
Reg Address is 0x21, R/W and default is 0x00
-
BOOT
用于重置寄存器的默认值 -
Heater
用于启动加热器,恢复传感器环境温度 -
ONE_SHOT
用于当ODR
为 00 时,ONE_SHOT
置 1 为使能一次读数据指令,读完后该位会硬件清 0
-
-
CTRL_REG3
Reg Address is 0x22, R/W and default is 0x00
-
DRDY_H_L
配置DRDY_EN
即 Pin3 管脚低有效还是高有效,0 为高有效,1 为低有效 -
PP_OD
控制 Pin3 管脚,置 1 为 open drain,置 0 为 push pull -
DRDY_EN
输出到 Pin3 管脚,为 1 时说明数据可读,为 0 时数据不可读,数据读取之后会自动清 0DRDY_EN
=STATUS_REG[1]
|STATUS_REG[0]
-
-
STATUS_REG
Reg Address is 0x27, read only and default is 0x00
H_DA
/T_DA
在 one-shot 或者每一个ODR
频率周期时,自动置 1,表示数据可读,读取后自动清 0
-
HUMIDITY_OUT_L
Reg Address is 0x28, read only
湿度数据 LSB
-
HUMIDITY_OUT_H
Reg Address is 0x29, read only
湿度数据 MSB
HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_HUMIDITY_OUT_L), buffer, 2); *H_T_OUT = (uint16_t)(buffer[1] << 8) | (uint16_t)buffer[0];
-
TEMP_OUT_L
Reg Address is 0x2A, read only
温度数据 LSB
-
TEMP_OUT_H
Reg Address is 0x2B, read only
温度数据 MSB
HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_TEMP_OUT_L), buffer, 2); *T_OUT = (uint16_t)(buffer[1] << 8) | (uint16_t)buffer[0];
-
CALIB_0…F
Reg Address is 0x30 - 0x3F, R/W
用于校准,出厂时存在内部 non-volatile memory 中,配合
HUMIDITY_OUT
/TEMP_OUT
得到准确的温湿度数据-
Humidity Calculation
H R H [ % ] = ( H 1 _ r H − H 0 _ r H ) × ( H _ T _ O U T − H 0 _ T 0 _ O U T ) H 1 _ T 0 _ O U T − H 0 _ T 0 _ O U T + H 0 _ r H H_{RH}[\%] = \frac{(H1\_rH - H0\_rH) × (H\_T\_OUT - H0\_T0\_OUT)}{H1\_T0\_OUT - H0\_T0\_OUT} + H0\_rH HRH[%]=H1_T0_OUT−H0_T0_OUT(H1_rH−H0_rH)×(H_T_OUT−H0_T0_OUT)+H0_rH -
Temperature Calculation
T [ d e g C ] = ( T 1 _ d e g C − T 0 _ d e g C ) × ( T _ O U T − T 0 _ O U T ) T 1 _ O U T − T 0 _ O U T + T 0 _ d e g C T[degC] = \frac{(T1\_degC - T0\_degC) × (T\_OUT - T0\_OUT)}{T1\_OUT - T0\_OUT} + T0\_degC T[degC]=T1_OUT−T0_OUT(T1_degC−T0_degC)×(T_OUT−T0_OUT)+T0_degC
-
HTS221 Humidity and Temperature Calculation
//
HTS221_Error_Typedef HTS221_Humidity_Calibration_Get(I2C_TypeDef *I2Cx)
{u8 buffer[2] = {0, 0};if(HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_H0_RH_X2), buffer, 2))return HTS221_ERROR;H_Cal_InitStruct.H0_rH = (int16_t)(buffer[0] >> 1); // H0_rH = H0_rH_x2 / 2H_Cal_InitStruct.H1_rH = (int16_t)(buffer[1] >> 1); // H1_rH = H1_rH_x2 / 2if(HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_H0_T0_OUT_L), buffer, 2))return HTS221_ERROR;H_Cal_InitStruct.H0_T0_OUT = (uint16_t)(buffer[1] << 8) | (uint16_t)buffer[0];if(HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_H1_T0_OUT_L), buffer, 2))return HTS221_ERROR;H_Cal_InitStruct.H1_T0_OUT = (uint16_t)(buffer[1] << 8) | (uint16_t)buffer[0];return HTS221_OK;
}//
HTS221_Error_Typedef HTS221_Temperature_Calibration_Get(I2C_TypeDef *I2Cx)
{u8 buffer[4] = {0, 0, 0, 0};uint8_t temp;if(HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_T0_DEGC_X8), buffer, 2))return HTS221_ERROR;if(HTS221_Reg_Read(I2Cx, HTS221_T1_T0_MSB, &temp, 1))return HTS221_ERROR;T_Cal_InitStruct.T0_degC_MSB = (int16_t)(temp & 0x03);T_Cal_InitStruct.T1_degC_MSB = (int16_t)((temp & 0x0C) >> 2);T_Cal_InitStruct.T0_degC = ((T_Cal_InitStruct.T0_degC_MSB << 8) | buffer[0]) >> 3;T_Cal_InitStruct.T1_degC = ((T_Cal_InitStruct.T1_degC_MSB << 8) | buffer[1]) >> 3;if(HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_H0_T0_OUT_L), buffer, 4))return HTS221_ERROR;T_Cal_InitStruct.T0_OUT = (uint16_t)(buffer[1] << 8) | (uint16_t)buffer[0];T_Cal_InitStruct.T1_OUT = (uint16_t)(buffer[3] << 8) | (uint16_t)buffer[2];return HTS221_OK;
}
HTS221_Error_Typedef HTS221_HUMIDITY_OUT_Get(I2C_TypeDef *I2Cx, int16_t *H_T_OUT)
{u8 buffer[2] = {0, 0};u8 one_shot = HTS221_CR2_ONE_SHOT;if(HTS221_Reg_Write(I2Cx, HTS221_CTRL_REG2, &one_shot, 1))return HTS221_ERROR;if(HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_HUMIDITY_OUT_L), buffer, 2))return HTS221_ERROR;*H_T_OUT = (uint16_t)(buffer[1] << 8) | (uint16_t)buffer[0];return HTS221_OK;
}
HTS221_Error_Typedef HTS221_TEMPERATURE_OUT_Get(I2C_TypeDef *I2Cx, int16_t *T_OUT)
{u8 buffer[2] = {0, 0};u8 one_shot = HTS221_CR2_ONE_SHOT;if(HTS221_Reg_Write(I2Cx, HTS221_CTRL_REG2, &one_shot, 1))return HTS221_ERROR;if(HTS221_Reg_Read(I2Cx, CONTINUOUS_ADDRESS(HTS221_TEMP_OUT_L), buffer, 2))return HTS221_ERROR;*T_OUT = (uint16_t)(buffer[1] << 8) | (uint16_t)buffer[0];return HTS221_OK;
}//
HTS221_Error_Typedef HTS221_Humidity_Calculation(I2C_TypeDef *I2Cx, uint16_t *value)
{int16_t H_T_OUT = 0x00;if(HTS221_HUMIDITY_OUT_Get(I2Cx, &H_T_OUT))return HTS221_ERROR;int32_t temp;temp = ((int32_t)(H_T_OUT - H_Cal_InitStruct.H0_T0_OUT)) * ((int32_t)(H_Cal_InitStruct.H1_rH - H_Cal_InitStruct.H0_rH) * 10);*value = (uint16_t)((temp / (H_Cal_InitStruct.H1_T0_OUT - H_Cal_InitStruct.H0_T0_OUT)) + H_Cal_InitStruct.H0_rH * 10);if(*value > 1000){*value = 1000;}printf("Get Humidity value : %d.%d %% \n", *value / 10, *value % 10);return HTS221_OK;
}//
HTS221_Error_Typedef HTS221_Temperature_Calculation(I2C_TypeDef *I2Cx, int16_t *value)
{int16_t T_OUT = 0x00;if(HTS221_TEMPERATURE_OUT_Get(I2Cx, &T_OUT))return HTS221_ERROR;int32_t temp;temp = ((int32_t)(T_OUT - T_Cal_InitStruct.T0_OUT)) * (((int32_t)(T_Cal_InitStruct.T1_degC - T_Cal_InitStruct.T0_degC) * 10));*value = (temp / (T_Cal_InitStruct.T1_OUT - T_Cal_InitStruct.T0_OUT)) + T_Cal_InitStruct.T0_degC * 10;printf("Get Temperature value : %d.%d C \n", *value / 10, *value % 10);return HTS221_OK;
}
The End
发现我内心世界真的非常 INFP,虽然我以前并没有意识到我是这样的……
- 压力都是自己给的,批评也是自己给的
- 从不后悔自己的决定,但是希望世界毁灭或人生重来
- 每个 INFP 都想成为艺术家,但因为怕吃不饱饭而没有成为艺术家
- 让我郁闷的是,我并不擅长 INFP 性格擅长的东西
- 大连伟世帮您留学
- 俞敏洪在北京大学2008年开学典礼上的演讲辞
- 【Linux】目录权限和默认权限
- 【时间复杂度】你还在担心时间复杂度太高吗?
- componentDidMount,react
- FlowFormer: Transformer结构光流估计
- 回溯法——回溯法的算法思想
- Service Principal 介绍
- 大数定律的形象理解
- HTK语音识别工具包的安装和编译
- EXT2和3区别
- IDEA的maven的package打包
- 人力资源的名词解释
- Java Integer值范围问题
- MBRGPT硬盘分区类型属性详解(Win下更改设置OEM恢复分区方法)
- Qt数据库:(三)利用QSqlQuery类执行SQL语句(一)
- 【C语言进阶】C语言实现通讯录