/********************************************************************************* * 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) * SDA <-----> #Pin3(SDA, BCM GPIO2) * SCL <-----> #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 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); static inline void msleep(unsigned long ms); static inline void dump_buf(const char *prompt, uint8_t *buf, int size); static inline void banner(const char *progname) { printf("%s program Version v1.0.0\n", progname); printf("Copyright (C) 2023 LingYun IoT System Studio.\n"); } static void program_usage(const char *progname) { printf("Usage: %s [OPTION]...\n", progname); printf(" %s is SHT20 temperature and humidity sensor program. \n", progname); printf(" -d[device ] Specify I2C device, such as /dev/i2c-1\n"); printf(" -h[help ] Display this help information\n"); printf(" -v[version ] Display the program version\n"); printf("\n"); banner(progname); return; } int main(int argc, char **argv) { int fd, rv; float temp, rh; char *dev = "/dev/i2c-1"; char *progname=NULL; uint8_t buf[4]; struct option long_options[] = { {"device", required_argument, NULL, 'd'}, {"version", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; progname = basename(argv[0]); /* Parser the command line parameters */ while ((rv = getopt_long(argc, argv, "d:vh", long_options, NULL)) != -1) { switch (rv) { case 'd': /* Set I2C device path: /dev/i2c-1 */ dev = optarg; break; case 'v': /* Get software version */ banner(progname); return EXIT_SUCCESS; case 'h': /* Get help information */ program_usage(progname); return 0; default: break; } } /*+--------------------------------+ *| open /dev/i2c-x device | *+--------------------------------+*/ if( (fd=open(dev, O_RDWR)) < 0) { printf("i2c device '%s' open failed: %s\n", dev, strerror(errno)); return -1; } /*+--------------------------------+ *| software reset SHT20 sensor | *+--------------------------------+*/ buf[0] = 0xFE; i2c_write(fd, 0x40, buf, 1); msleep(50); /*+--------------------------------+ *| trigger temperature measure | *+--------------------------------+*/ buf[0] = 0xF3; i2c_write(fd, 0x40, buf, 1); msleep(85); /* datasheet: typ=66, max=85 */ memset(buf, 0, sizeof(buf)); i2c_read(fd, 0x40, buf, 3); dump_buf("Temperature sample data: ", buf, 3); if( !sht20_checksum(buf, 2, buf[2]) ) { printf("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, 0x40, buf, 1); msleep(29); /* datasheet: typ=22, max=29 */ memset(buf, 0, sizeof(buf)); i2c_read(fd, 0x40, buf, 3); dump_buf("Relative humidity sample data: ", buf, 3); if( !sht20_checksum(buf, 2, buf[2]) ) { printf("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 | *+--------------------------------+*/ printf("Temperature=%lf 'C relative humidity=%lf%%\n", temp, rh); cleanup: close(fd); return 0; } 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) { printf("%s() invalid input arguments!\n", __func__); return -1; } i2cdata.nmsgs = 1; i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs ); if ( !i2cdata.msgs ) { printf("%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 ) { printf("%s() msgs malloc failed!\n", __func__); rv = -3; goto cleanup; } memcpy(i2cdata.msgs[0].buf, data, len); if( ioctl(fd, I2C_RDWR, &i2cdata)<0 ) { printf("%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) { printf("%s() invalid input arguments!\n", __func__); return -1; } i2cdata.nmsgs = 1; i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs ); if ( !i2cdata.msgs ) { printf("%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 ) { printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); rv = -4; } free( i2cdata.msgs ); return rv; } static inline void msleep(unsigned long ms) { struct timespec cSleep; unsigned long ulTmp; cSleep.tv_sec = ms / 1000; if (cSleep.tv_sec == 0) { ulTmp = ms * 10000; cSleep.tv_nsec = ulTmp * 100; } else { cSleep.tv_nsec = 0; } nanosleep(&cSleep, 0); return ; } static inline void dump_buf(const char *prompt, uint8_t *buf, int size) { int i; if( !buf ) { return ; } if( prompt ) { printf("%-32s ", prompt); } for(i=0; i