From 75843d7e163f97fd42f96661863c1de664b08cc8 Mon Sep 17 00:00:00 2001 From: Guo Wenxue <guowenxue@gmail.com> Date: Sun, 07 Jul 2024 19:28:29 +0800 Subject: [PATCH] Update modules led source code to support other pins --- modules/sht20.c | 406 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 295 insertions(+), 111 deletions(-) diff --git a/modules/sht20.c b/modules/sht20.c index d84877f..f549369 100644 --- a/modules/sht20.c +++ b/modules/sht20.c @@ -10,7 +10,7 @@ * ChangeLog: 1, Release initial version on "10/08/23 17:52:00" * * Pin connection: - * STH20 Module Raspberry Pi Board + * SHT20 Raspberry Pi 40Pin * VCC <-----> #Pin1(3.3V) * SDA <-----> #Pin3(SDA, BCM GPIO2) * SCL <-----> #Pin5(SCL, BCM GPIO3) @@ -39,11 +39,41 @@ #include <linux/i2c.h> #include <linux/i2c-dev.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); +/* SHT2X 7-bit I2C slave address */ +#define SHT2X_CHIPADDR 0x40 + +/* SHT2X trigger command */ +#define SOFTRESET 0xFE +#define TRIGGER_TEMPERATURE_NO_HOLD 0xF3 +#define TRIGGER_HUMIDITY_NO_HOLD 0xF5 + +/* Linux /dev/i2c-x device program API mode */ +enum +{ + MODE_IOCTL, /* I2C device API use ioctl() */ + MODE_RDWR, /* I2C device API use read()/write() */ +}; + +typedef struct i2c_s +{ + char *dev; /* I2C master device, /dev/i2c-N */ + int addr; /* 7-bits slave address */ + int fd; /* File description */ + int mode; /* I2C device API use read/write or ioctl mode */ +} i2c_t; + +int sht2x_softreset(i2c_t *i2c); +int sht2x_get_serialnumber(i2c_t *i2c, uint8_t *serialnumber, int size); +int sht2x_get_temp_humidity(i2c_t *i2c, float *temp, float *rh); + +int i2c_init(i2c_t *i2c, int mode, char *i2cdev, int addr); +int i2c_write(i2c_t *i2c, uint8_t *data, int len); +int i2c_read(i2c_t *i2c, uint8_t *buf, int size); +void i2c_term(i2c_t *i2c); + static inline void msleep(unsigned long ms); -static inline void dump_buf(const char *prompt, uint8_t *buf, int size); +void print_buf(const char *prompt, uint8_t *buf, int size); +void dump_buf(const char *prompt, char *buffer, size_t length); static inline void banner(const char *progname) { @@ -58,6 +88,7 @@ printf(" %s is SHT20 temperature and humidity sensor program. \n", progname); printf(" -d[device ] Specify I2C device, such as /dev/i2c-1\n"); + printf(" -m[mode ] Specify API mode, 0 for ioctl and 1 for read()/write()\n"); printf(" -h[help ] Display this help information\n"); printf(" -v[version ] Display the program version\n"); @@ -68,14 +99,17 @@ int main(int argc, char **argv) { - int fd, rv; - float temp, rh; - char *dev = "/dev/i2c-1"; + char *dev="/dev/i2c-1"; char *progname=NULL; - uint8_t buf[4]; + int mode = MODE_IOCTL; + int rv; + float temp, rh; + uint8_t serialnumber[8]; + i2c_t i2c; struct option long_options[] = { {"device", required_argument, NULL, 'd'}, + {"mode", required_argument, NULL, 'm'}, {"version", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} @@ -84,12 +118,16 @@ progname = basename(argv[0]); /* Parser the command line parameters */ - while ((rv = getopt_long(argc, argv, "d:vh", long_options, NULL)) != -1) + while ((rv = getopt_long(argc, argv, "d:m:vh", long_options, NULL)) != -1) { switch (rv) { case 'd': /* Set I2C device path: /dev/i2c-1 */ dev = optarg; + break; + + case 'm': /* Set I2C API mode: 0,1 */ + mode = atoi(optarg) ? MODE_RDWR : MODE_IOCTL; break; case 'v': /* Get software version */ @@ -105,108 +143,190 @@ } } - - /*+--------------------------------+ - *| open /dev/i2c-x device | - *+--------------------------------+*/ - if( (fd=open(dev, O_RDWR)) < 0) + if( i2c_init(&i2c, mode, dev, SHT2X_CHIPADDR) < 0 ) { - printf("i2c device '%s' open failed: %s\n", dev, strerror(errno)); + printf("I2C master device initial failed.\n"); + return 1; + } + + if( sht2x_softreset(&i2c) < 0 ) + { + printf("SHT2x initialize failure, maybe device not present!\n"); + return 1; + } + + if( sht2x_get_serialnumber(&i2c, serialnumber, 8) < 0) + { + printf("SHT2x get serial number failure\n"); + return 3; + } + + if( sht2x_get_temp_humidity(&i2c, &temp, &rh) < 0 ) + { + printf("SHT2x get get temperature and relative humidity failure\n"); + return 3; + } + + printf("Temperature=%lf ℃ relative humidity=%lf.\n", temp, rh); + + i2c_term(&i2c); + + return 0; +} + +int sht2x_softreset(i2c_t *i2c) +{ + uint8_t buf[1]; + + if( !i2c || i2c->fd<0 ) + { + printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); return -1; } - /*+--------------------------------+ - *| software reset SHT20 sensor | - *+--------------------------------+*/ - - buf[0] = 0xFE; - i2c_write(fd, 0x40, buf, 1); + /* software reset SHT2x */ + buf[0] = SOFTRESET; + if( i2c_write(i2c, buf, 1) < 0 ) + { + return -2; + } msleep(50); + return 0; +} - /*+--------------------------------+ - *| trigger temperature measure | - *+--------------------------------+*/ +int sht2x_get_temp_humidity(i2c_t *i2c, float *temp, float *rh) +{ + uint8_t buf[4]; - buf[0] = 0xF3; - i2c_write(fd, 0x40, buf, 1); + if( !i2c || !temp || !rh || i2c->fd<0 ) + { + printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); + return -1; + } + + /* send trigger temperature measure command and read the data */ + memset(buf, 0, sizeof(buf)); + buf[0]=TRIGGER_TEMPERATURE_NO_HOLD; + i2c_write(i2c, 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); + i2c_read(i2c, buf, 3); + print_buf("Temperature sample data: ", buf, 3); + *temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85; - 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); + /* send trigger humidity measure command and read the data */ + memset(buf, 0, sizeof(buf)); + buf[0] = TRIGGER_HUMIDITY_NO_HOLD; + i2c_write(i2c, 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; - } + i2c_read(i2c, buf, 3); + print_buf("Relative humidity sample data: ", buf, 3); + *rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6; - 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) +int sht2x_get_serialnumber(i2c_t *i2c, uint8_t *serialnumber, int size) { - int8_t crc = 0; - int8_t bit; - int8_t byteCtr; + uint8_t buf[4]={0x0}; - //calculates 8-Bit checksum with given polynomial: x^8 + x^5 + x^4 + 1 - for (byteCtr = 0; byteCtr < len; ++byteCtr) + if( !i2c || i2c->fd<0 || !serialnumber || size!=8 ) { - 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); - } + printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); + return -1; } - if (crc != checksum) - return 0; - else - return 1; + /* Read SerialNumber from Location 1 */ + memset(buf, 0, sizeof(buf)); + buf[0] = 0xfa; /* command for readout on-chip memory */ + buf[1] = 0x0f; /* on-chip memory address */ + i2c_write(i2c, buf, 2); + + memset(buf, 0, sizeof(buf)); + i2c_read(i2c, buf, 4); + + if( !buf[0] && !buf[1] && !buf[2] && !buf[3] ) + { + printf("ERROR: SHT2X device not detected!\n"); + return -2; + } + + serialnumber[5]=buf[0]; /* Read SNB_3 */ + serialnumber[4]=buf[1]; /* Read SNB_2 */ + serialnumber[3]=buf[2]; /* Read SNB_1 */ + serialnumber[2]=buf[3]; /* Read SNB_0 */ + + /* Read SerialNumber from Location 2 */ + memset(buf, 0, sizeof(buf) ); + buf[0]=0xfc; /* command for readout on-chip memory */ + buf[1]=0xc9; /* on-chip memory address */ + i2c_write(i2c, buf, 2); + + memset(buf, 0, sizeof(buf) ); + i2c_read(i2c, buf, 4); + + serialnumber[1]=buf[0]; /* Read SNC_1 */ + serialnumber[0]=buf[1]; /* Read SNC_0 */ + serialnumber[7]=buf[2]; /* Read SNA_1 */ + serialnumber[6]=buf[3]; /* Read SNA_0 */ + + print_buf("SHT2x Serial number: ", serialnumber, 8); + + return 0; } -int i2c_write(int fd, uint8_t slave_addr, uint8_t *data, int len) +/*+----------------------+ + *| I2C API functions | + *+----------------------+*/ + +int i2c_init(i2c_t *i2c, int mode, char *i2cdev, int addr) { - struct i2c_rdwr_ioctl_data i2cdata; - int rv = 0; + if( !i2c || !i2cdev || !addr ) + return -1; + + memset(i2c, 0, sizeof(*i2c)); + i2c->addr = addr; + i2c->dev = i2cdev; + i2c->mode = mode; + + if( (i2c->fd=open(i2cdev, O_RDWR)) < 0) + { + printf("open i2c device %s failed: %s\n", i2cdev, strerror(errno)); + return -1; + } + + if( MODE_RDWR == i2c->mode ) + { + /* set I2C mode and SHT2x slave address */ + ioctl(i2c->fd, I2C_TENBIT, 0); /* Not 10-bit but 7-bit mode */ + ioctl(i2c->fd, I2C_SLAVE, i2c->addr); /* set SHT2x slave address */ + } + + return 0; +} + +void i2c_term(i2c_t *i2c) +{ + if( !i2c ) + return; + + if( i2c->fd > 0) + close(i2c->fd); + + return ; +} + +int i2c_write(i2c_t *i2c, uint8_t *data, int len) +{ + struct i2c_rdwr_ioctl_data tr; + int rv = 0; if( !data || len<= 0) { @@ -214,28 +334,36 @@ return -1; } - i2cdata.nmsgs = 1; - i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs ); - if ( !i2cdata.msgs ) + /* I2C device program API: read()/write() */ + if( MODE_RDWR == i2c->mode ) + { + write(i2c->fd, data, len); + return 0; + } + + /* I2C device program API: ioctl() */ + tr.nmsgs = 1; + tr.msgs = malloc( sizeof(struct i2c_msg)*tr.nmsgs ); + if ( !tr.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 ) + tr.msgs[0].addr = i2c->addr; + tr.msgs[0].flags = 0; //write + tr.msgs[0].len = len; + tr.msgs[0].buf = malloc(len); + if( !tr.msgs[0].buf ) { printf("%s() msgs malloc failed!\n", __func__); rv = -3; goto cleanup; } - memcpy(i2cdata.msgs[0].buf, data, len); + memcpy(tr.msgs[0].buf, data, len); - if( ioctl(fd, I2C_RDWR, &i2cdata)<0 ) + if( ioctl(i2c->fd, I2C_RDWR, &tr)<0 ) { printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); rv = -4; @@ -243,19 +371,19 @@ } cleanup: - if( i2cdata.msgs[0].buf ) - free(i2cdata.msgs[0].buf); + if( tr.msgs[0].buf ) + free(tr.msgs[0].buf); - if( i2cdata.msgs ) - free(i2cdata.msgs); + if( tr.msgs ) + free(tr.msgs); return rv; } -int i2c_read(int fd, uint8_t slave_addr, uint8_t *buf, int size) +int i2c_read(i2c_t *i2c, uint8_t *buf, int size) { - struct i2c_rdwr_ioctl_data i2cdata; - int rv = 0; + struct i2c_rdwr_ioctl_data tr; + int rv = 0; if( !buf || size<= 0) { @@ -263,29 +391,41 @@ return -1; } - i2cdata.nmsgs = 1; - i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs ); - if ( !i2cdata.msgs ) + /* I2C device program API: read()/write() */ + if( MODE_RDWR == i2c->mode ) + { + read(i2c->fd, buf, size); + return 0; + } + + /* I2C device program API: ioctl() */ + tr.nmsgs = 1; + tr.msgs = malloc( sizeof(struct i2c_msg)*tr.nmsgs ); + if ( !tr.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; + tr.msgs[0].addr = i2c->addr; + tr.msgs[0].flags = I2C_M_RD; //read + tr.msgs[0].len = size; + tr.msgs[0].buf = buf; memset(buf, 0, size); - if( ioctl(fd, I2C_RDWR, &i2cdata)<0 ) + if( ioctl(i2c->fd, I2C_RDWR, &tr)<0 ) { printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); rv = -4; } - free( i2cdata.msgs ); + free( tr.msgs ); return rv; } + +/*+----------------------+ + *| Misc functions | + *+----------------------+*/ static inline void msleep(unsigned long ms) { @@ -304,10 +444,9 @@ } nanosleep(&cSleep, 0); - return ; } -static inline void dump_buf(const char *prompt, uint8_t *buf, int size) +void print_buf(const char *prompt, uint8_t *buf, int size) { int i; @@ -318,7 +457,7 @@ if( prompt ) { - printf("%-32s ", prompt); + printf("%s ", prompt); } for(i=0; i<size; i++) @@ -329,3 +468,48 @@ return ; } + +void dump_buf(const char *prompt, char *buffer, size_t length) +{ + size_t i, j; + + if (prompt) + { + printf("%s\n", prompt); + } + + for (i = 0; i < length; i += 16) + { + printf("%08zx: ", i); + + for (j = 0; j < 16; j++) + { + if (i + j < length) + { + printf("%02x ", buffer[i + j]); + } + else + { + printf(" "); + } + } + + printf(" "); + + for (j = 0; j < 16; j++) + { + if (i + j < length) + { + unsigned char c = buffer[i + j]; + printf("%c", (c >= 32 && c <= 126) ? c : '.'); + } + else + { + printf(" "); + } + } + + printf("\n"); + } +} + -- Gitblit v1.9.1