/********************************************************************************* * 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 * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }