树莓派采集温湿度传感器Si7021



1.前言

Si7021是一款微型数字温湿度传感器,其通过IIC与外部处理器通信,常用于采集环境信息。。本文首先介绍Si7021芯片关键特性,再在树莓派基于Bcm2835库开发Si7021驱动库。树莓派安装Bcm2835库参考这篇文章

2.Si7021

Si7021供电1.9-3.6V,湿度量程0-80%,最高精度±3%,温度量程-10-85℃,最高精度±0.4℃。其通过IIC与外部芯片通信,芯片地址0x40。
他有以下基础指令:
在这里插入图片描述

  1. 重置(0xFE),软件重置需要等待芯片15ms;

  2. 读(0xE7)写(0xE6)用户寄存器,用户寄存器的D7和D0可以配置温湿度ADC的位数,设置的位数不同,ADC转换耗时不同,D6可以看出供电是否正常,D2可以配置是否启用加热器。
    在这里插入图片描述

  3. 读取序列号1st Bytes(0xFA 0xDF)和2nd Bytes(0xFC 0xC9),读取第一组序列号时,共需要8个字节(含4个CRC),读取第二组序列号时,需要接收6个字节(含2个CRC)。根据SNB_3的数值可以区分该模块的具体信号:0x0D=Si7013,0x14=Si7020,0x15=Si7021;
    在这里插入图片描述

  4. 读取固件版本号(0x84 0xB8);

  5. 湿度测量,No Hold Master Mode(0xF5),测量湿度时,会先测量一次温度,即该条指令下去,会先ADC测量温度,再ADC测量湿度。ADC转换时间为两个通道耗时之和。
    在这里插入图片描述

  6. 读取上个RH测量的温度值(0xE0),通常在湿度测量之后,因为湿度测量会自动进行一次温度测量,因此,无需再进行一次温度测量,只需读取就行。
    在这里插入图片描述
    两个通道的ADC转换时间,和温湿度转换公式,和其他详细情况可参考芯片手册。

3.在树莓派移植Si7021库

在树莓派中基于Bcm2835移植Si7021库,参考Adafruit_Si7021_Library,做了对序列号2st Bytes的读取的修改。
si7021.h

#ifndef SI7021_H
#define SI7021_H

#include <bcm2835.h>
#include <cstdio>
#include <cstdint>

/*!
 *  I2C ADDRESS/BITS
 */
#define SI7021_DEFAULT_ADDRESS 0x40

#define SI7021_MEASRH_HOLD_CMD                                                 \
  0xE5 /**< Measure Relative Humidity, Hold Master Mode */
#define SI7021_MEASRH_NOHOLD_CMD                                               \
  0xF5 /**< Measure Relative Humidity, No Hold Master Mode */
#define SI7021_MEASTEMP_HOLD_CMD                                               \
  0xE3 /**< Measure Temperature, Hold Master Mode */
#define SI7021_MEASTEMP_NOHOLD_CMD                                             \
  0xF3 /**< Measure Temperature, No Hold Master Mode */
#define SI7021_READPREVTEMP_CMD                                                \
  0xE0 /**< Read Temperature Value from Previous RH Measurement */
#define SI7021_RESET_CMD 0xFE           /**< Reset Command */
#define SI7021_WRITERHT_REG_CMD 0xE6    /**< Write RH/T User Register 1 */
#define SI7021_READRHT_REG_CMD 0xE7     /**< Read RH/T User Register 1 */
#define SI7021_WRITEHEATER_REG_CMD 0x51 /**< Write Heater Control Register */
#define SI7021_READHEATER_REG_CMD 0x11  /**< Read Heater Control Register */
#define SI7021_REG_HTRE_BIT 0x02        /**< Control Register Heater Bit */
#define SI7021_ID1_CMD 0xFA0F           /**< Read Electronic ID 1st Byte */
#define SI7021_ID2_CMD 0xFCC9           /**< Read Electronic ID 2nd Byte */
#define SI7021_FIRMVERS_CMD 0x84B8      /**< Read Firmware Revision */

#define SI7021_REV_1 0xff /**< Sensor revision 1 */
#define SI7021_REV_2 0x20 /**< Sensor revision 2 */

/** An enum to represent sensor types **/
enum si_sensorType {
  SI_Engineering_Samples,
  SI_7013,
  SI_7020,
  SI_7021,
  SI_UNKNOWN,
};

/*!
 *  @brief  Class that stores state and functions for interacting with
 *          Si7021 Sensor
 */

class SI7021{
	public:
		SI7021(uint8_t addr = SI7021_DEFAULT_ADDRESS);
		bool begin();
		
		float readHumi();
		float readTemp();
		void reset();

	  /*!
	   *  @brief  Returns sensor revision established during init
	   *  @return model value
	   */
	  uint8_t getRevision() { return _revision; };
	  
	  /*!
	   *  @brief  Returns sensor sensor types
	   *  @return sensor types
	   */
	  si_sensorType getModel(){ return _model; };

	private:
		uint8_t _addr;
		si_sensorType _model;
		uint8_t _revision;
		uint32_t sernum_a; /**< Serialnum A */
		uint32_t sernum_b; /**< Serialnum B */
		void _readRevision();
		uint8_t _readRegister8(uint8_t reg);
		void _readSerialNumber();

		uint8_t errCode;
		char sendBuf[3];
};
#endif

si7021.cpp

#include "si7021.h"

SI7021::SI7021(uint8_t addr)
{
	_addr = addr;
	sernum_a = sernum_b = 0;
	_model = SI_7021;
	_revision = 0;
}

/**
 * @brief Before SI7021::init(), please bcm2835_init() in main.c!
 **/
bool SI7021::begin()
{
	printf("SI7021 Init...\n");
	if(!bcm2835_i2c_begin())
	{
		printf("bcm2835_i2c_begin failed at %s:%d\n",__FILE__ ,__LINE__);
		return false;
	}
	bcm2835_i2c_setSlaveAddress(_addr);
	bcm2835_i2c_set_baudrate(100000);
	
	if (_readRegister8(SI7021_READRHT_REG_CMD) != 0x3A)
		return false;
	_readSerialNumber();
	_readRevision();
	return true;
}

uint8_t SI7021::_readRegister8(uint8_t reg)
{
	char value;
	sendBuf[0] = reg;
	if((errCode = bcm2835_i2c_write_read_rs(sendBuf,1,&value,1)))
	{
		printf("bcm2835_i2c_write_read_rs failed at%s:%d, errCode = 0x%x\n",__FILE__ ,__LINE__, errCode);
		return 0;
	}
	//printf("value = %d\n", value);
	return static_cast<uint8_t>(value);
}

void SI7021::_readSerialNumber()
{
	sendBuf[0] = static_cast<uint8_t>(SI7021_ID1_CMD >> 8);
	sendBuf[1] = static_cast<uint8_t>(SI7021_ID1_CMD & 0xFF);
	char recvBuf[8];
	if((errCode = bcm2835_i2c_write_read_rs(sendBuf,2,recvBuf,8)))
	{
		printf("bcm2835_i2c_write_read_rs failed at %s:%d, errCode = 0x%x\n", __FILE__, __LINE__, errCode);
		return;
	}
	sernum_a = (recvBuf[0]<<24)|(recvBuf[2]<<16)|(recvBuf[4]<<8)|(recvBuf[6]);
	//printf("sernum_a = %d\n", sernum_a);
	
	sendBuf[0] = static_cast<uint8_t>(SI7021_ID2_CMD >> 8);
	sendBuf[1] = static_cast<uint8_t>(SI7021_ID2_CMD & 0xFF);
	if((errCode = bcm2835_i2c_write_read_rs(sendBuf,2,recvBuf,6)))
	{
		printf("bcm2835_i2c_write_read_rs failed at %s:%d, errCode = 0x%x\n", __FILE__, __LINE__, errCode);
		return;
	}
	sernum_b = (recvBuf[0]<<24)|(recvBuf[1]<<16)|(recvBuf[3]<<8)|(recvBuf[4]);
	//printf("sernum_b = %d\n", sernum_b);
	
	switch (sernum_b >> 24) {
		case 0:
		case 0xff:
			_model = SI_Engineering_Samples;
		break;
		case 0x0D:
			_model = SI_7013;
		break;
		case 0x14:
			_model = SI_7020;
		break;
		case 0x15:
			_model = SI_7021;
		break;
		default:
			_model = SI_UNKNOWN;
		break;
	}
	//printf("_model = %d\n",_model);
}

void SI7021::_readRevision()
{
	sendBuf[0] = static_cast<uint8_t>(SI7021_FIRMVERS_CMD >> 8);
	sendBuf[1] = static_cast<uint8_t>(SI7021_FIRMVERS_CMD & 0xFF);
	char recvBuf[2];
	if((errCode = bcm2835_i2c_write_read_rs(sendBuf,2,recvBuf,2)))
	{
		printf("bcm2835_i2c_write_read_rs failed at %s:%d, errCode = 0x%x\n",__FILE__ ,__LINE__, errCode);
		return;
	}

	if(recvBuf[0] == SI7021_REV_1)
		_revision = 1;
	else if(recvBuf[0] == SI7021_REV_2)
		_revision = 2;
	else
		_revision = 0;
	//printf("_revision = %d\n",_revision);
}
/**
 * @brief Reset the SI7021 device, it takes almost 50 ms
 */
void SI7021::reset()
{
	bcm2835_i2c_setSlaveAddress(_addr);
	sendBuf[0] = SI7021_RESET_CMD;
	if((errCode = bcm2835_i2c_write(sendBuf,1)))
	{
		printf("bcm2835_i2c_write failed at %s:%d, errCode = 0x%x\n", __FILE__, __LINE__ ,errCode);
		return;
	}
	bcm2835_delay(20);
}

/**
 * @brief  Reads the humidity value from Si7021 (No Master hold), the function takes almost 20ms.
 * @return Returns humidity as float value or -1 when error
 */
float SI7021::readHumi()
{
	bcm2835_i2c_setSlaveAddress(_addr);
	sendBuf[0] = SI7021_MEASRH_NOHOLD_CMD;
	if((errCode = bcm2835_i2c_write(sendBuf,1)))
	{
		printf("bcm2835_i2c_write failed at %s:%d, errCode = 0x%x\n", __FILE__, __LINE__ ,errCode);
		return -1;
	}
	
	bcm2835_delay(20);
	
	char recvBuf[3];
	if((errCode = bcm2835_i2c_read(recvBuf,3)))
	{
		printf("bcm2835_i2c_read failed at %s:%d, errCode = 0x%x\n", __FILE__, __LINE__ ,errCode);
		return -1;
	}
	float humi = recvBuf[0]<<8 | recvBuf[1];
	humi *= 125;
	humi /= 65536;
	humi -= 6;
	return humi > 100.0 ? 100.0 : humi;
}

/**
 * @brief  Reads the temperature value from Si7021 (Read temperature value from previous RH measurement)
 * @return Returns temperature as float value or -1 when there is error
 */
float SI7021::readTemp()
{
	bcm2835_i2c_setSlaveAddress(_addr);
	sendBuf[0] = SI7021_READPREVTEMP_CMD;
	char recvBuf[2];
	if((errCode = bcm2835_i2c_write_read_rs(sendBuf,1,recvBuf,2)))
	{
		printf("bcm2835_i2c_write_read_rs failed at %s:%d, errCode = 0x%x\n", __FILE__, __LINE__ ,errCode);
		return -1;
	}
	float temp = recvBuf[0]<<8 | recvBuf[1];
	temp *= 175.72;
	temp /= 65536;
	temp -= 46.85;
	return temp;
}

testMain.cpp

#include "si7021.h"

int main()
{
	bcm2835_init();
	SI7021 si7021;
	if(!si7021.begin())
	{
		printf("SI7021 init failed\n");
		exit(-1);
	}
	float humi = 0;
	float temp = 0;
	while(1)
	{
		humi = si7021.readHumi();
		temp = si7021.readTemp();
		printf("Humi = %f, temp = %f\n",humi,temp);
		bcm2835_delay(500);
	}
	return 0;
}

//g++ si7021.cpp testMain.cpp -lbcm2835 -o testMain

源码可见github

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值