/*********************************************************************************
|
* Copyright: (C) 2023 LingYun IoT System Studio
|
* All rights reserved.
|
*
|
* Filename: sht20.c
|
* Description: This file is temperature and relative humidity sensor SHT20 code
|
*
|
* Version: 1.0.0(10/08/23)
|
* Author: Guo Wenxue <guowenxue@gmail.com>
|
* ChangeLog: 1, Release initial version on "10/08/23 17:52:00"
|
*
|
* Pin connection:
|
* STH20 Module Raspberry Pi Board
|
* VCC <-----> #Pin1(3.3V)
|
* SDA1 <-----> #Pin3(SDA, BCM GPIO2)
|
* SCL1 <-----> #Pin5(SCL, BCM GPIO3)
|
* GND <-----> GND
|
*
|
* /boot/config.txt:
|
* dtoverlay=i2c1,pins_2_3
|
*
|
********************************************************************************/
|
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <stdint.h>
|
#include <string.h>
|
#include <unistd.h>
|
#include <libgen.h>
|
#include <getopt.h>
|
#include <time.h>
|
#include <errno.h>
|
#include <fcntl.h>
|
#include <sys/ioctl.h>
|
#include <sys/types.h>
|
#include <sys/stat.h>
|
#include <linux/types.h>
|
#include <linux/i2c.h>
|
#include <linux/i2c-dev.h>
|
|
#include "logger.h"
|
#include "util_proc.h"
|
#include "sht20.h"
|
|
int i2c_write(int fd, uint8_t slave_addr, uint8_t *data, int len);
|
int i2c_read(int fd, uint8_t slave_addr, uint8_t *buf, int size);
|
int sht20_checksum(uint8_t *data, int len, int8_t checksum);
|
|
int sht2x_get_temp_humidity(float *temp, float *rh)
|
{
|
int fd;
|
int rv = 0;
|
char *dev = SHT20_I2CDEV;
|
uint8_t buf[4];
|
|
if( !temp || !rh )
|
{
|
log_error("Invalid input arguments\n");
|
return -1;
|
}
|
|
/*+--------------------------------+
|
*| open /dev/i2c-x device |
|
*+--------------------------------+*/
|
if( (fd=open(dev, O_RDWR)) < 0)
|
{
|
log_error("i2c device '%s' open failed: %s\n", dev, strerror(errno));
|
return -2;
|
}
|
|
/*+--------------------------------+
|
*| software reset SHT20 sensor |
|
*+--------------------------------+*/
|
|
buf[0] = 0xFE;
|
i2c_write(fd, SHT20_I2CADDR, buf, 1);
|
|
msleep(50);
|
|
|
/*+--------------------------------+
|
*| trigger temperature measure |
|
*+--------------------------------+*/
|
|
buf[0] = 0xF3;
|
i2c_write(fd, SHT20_I2CADDR, buf, 1);
|
|
msleep(85); /* datasheet: typ=66, max=85 */
|
|
memset(buf, 0, sizeof(buf));
|
i2c_read(fd, SHT20_I2CADDR, buf, 3);
|
log_dump(LOG_LEVEL_DEBUG, "Temperature sample data: ", buf, 3);
|
|
if( !sht20_checksum(buf, 2, buf[2]) )
|
{
|
rv = -3;
|
log_error("Temperature sample data CRC checksum failure.\n");
|
goto cleanup;
|
}
|
|
*temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85;
|
|
|
/*+--------------------------------+
|
*| trigger humidity measure |
|
*+--------------------------------+*/
|
|
buf[0] = 0xF5;
|
i2c_write(fd, SHT20_I2CADDR, buf, 1);
|
|
msleep(29); /* datasheet: typ=22, max=29 */
|
|
memset(buf, 0, sizeof(buf));
|
i2c_read(fd, SHT20_I2CADDR, buf, 3);
|
log_dump(LOG_LEVEL_DEBUG, "Relative humidity sample data: ", buf, 3);
|
|
if( !sht20_checksum(buf, 2, buf[2]) )
|
{
|
rv = -4;
|
log_error("Relative humidity sample data CRC checksum failure.\n");
|
goto cleanup;
|
}
|
|
*rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6;
|
|
/*+--------------------------------+
|
*| print the measure result |
|
*+--------------------------------+*/
|
|
log_debug("Temperature=%lf 'C relative humidity=%lf%%\n", *temp, *rh);
|
|
cleanup:
|
close(fd);
|
return rv;
|
}
|
|
int sht20_checksum(uint8_t *data, int len, int8_t checksum)
|
{
|
int8_t crc = 0;
|
int8_t bit;
|
int8_t byteCtr;
|
|
//calculates 8-Bit checksum with given polynomial: x^8 + x^5 + x^4 + 1
|
for (byteCtr = 0; byteCtr < len; ++byteCtr)
|
{
|
crc ^= (data[byteCtr]);
|
for ( bit = 8; bit > 0; --bit)
|
{
|
/* x^8 + x^5 + x^4 + 1 = 0001 0011 0001 = 0x131 */
|
if (crc & 0x80) crc = (crc << 1) ^ 0x131;
|
else crc = (crc << 1);
|
}
|
}
|
|
if (crc != checksum)
|
return 0;
|
else
|
return 1;
|
}
|
|
int i2c_write(int fd, uint8_t slave_addr, uint8_t *data, int len)
|
{
|
struct i2c_rdwr_ioctl_data i2cdata;
|
int rv = 0;
|
|
if( !data || len<= 0)
|
{
|
log_error("%s() invalid input arguments!\n", __func__);
|
return -1;
|
}
|
|
i2cdata.nmsgs = 1;
|
i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs );
|
if ( !i2cdata.msgs )
|
{
|
log_error("%s() msgs malloc failed!\n", __func__);
|
return -2;
|
}
|
|
i2cdata.msgs[0].addr = slave_addr;
|
i2cdata.msgs[0].flags = 0; //write
|
i2cdata.msgs[0].len = len;
|
i2cdata.msgs[0].buf = malloc(len);
|
if( !i2cdata.msgs[0].buf )
|
{
|
log_error("%s() msgs malloc failed!\n", __func__);
|
rv = -3;
|
goto cleanup;
|
}
|
memcpy(i2cdata.msgs[0].buf, data, len);
|
|
|
if( ioctl(fd, I2C_RDWR, &i2cdata)<0 )
|
{
|
log_error("%s() ioctl failure: %s\n", __func__, strerror(errno));
|
rv = -4;
|
goto cleanup;
|
}
|
|
cleanup:
|
if( i2cdata.msgs[0].buf )
|
free(i2cdata.msgs[0].buf);
|
|
if( i2cdata.msgs )
|
free(i2cdata.msgs);
|
|
return rv;
|
}
|
|
int i2c_read(int fd, uint8_t slave_addr, uint8_t *buf, int size)
|
{
|
struct i2c_rdwr_ioctl_data i2cdata;
|
int rv = 0;
|
|
if( !buf || size<= 0)
|
{
|
log_error("%s() invalid input arguments!\n", __func__);
|
return -1;
|
}
|
|
i2cdata.nmsgs = 1;
|
i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs );
|
if ( !i2cdata.msgs )
|
{
|
log_error("%s() msgs malloc failed!\n", __func__);
|
return -2;
|
}
|
|
i2cdata.msgs[0].addr = slave_addr;
|
i2cdata.msgs[0].flags = I2C_M_RD; //read
|
i2cdata.msgs[0].len = size;
|
i2cdata.msgs[0].buf = buf;
|
memset(buf, 0, size);
|
|
if( ioctl(fd, I2C_RDWR, &i2cdata)<0 )
|
{
|
log_error("%s() ioctl failure: %s\n", __func__, strerror(errno));
|
rv = -4;
|
}
|
|
free( i2cdata.msgs );
|
return rv;
|
}
|