RaspberrPi project source code
guowenxue
2024-03-14 d973d6f8e12b16c3cdd84e63e19b61187424f4ce
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)
@@ -20,6 +20,7 @@
 *                  dtoverlay=i2c1,pins_2_3
 *
 ********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -53,22 +54,26 @@
    MODE_RDWR,  /* I2C device API use read()/write() */
};
typedef struct sht2x_s
typedef struct i2c_s
{
    char           *dev;    /* SHT20 connect I2C device, /dev/i2c-N */
    int             addr;   /* SHT20 7-bits slave address */
    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 */
} sht2x_t;
} i2c_t;
int sht2x_init(sht2x_t *sht2x);
int sht2x_get_serialnumber(sht2x_t *sht2x, uint8_t *serialnumber, int size);
int sht2x_get_temp_humidity(sht2x_t *sht2x, float *temp, float *rh);
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);
static int i2c_write(sht2x_t *sht2x, uint8_t *data, int len);
static int i2c_read(sht2x_t *sht2x, uint8_t *buf, int size);
void print_buf(const char *prompt, uint8_t *buf, int size);
void dump_buf(const char *prompt, char *buf, size_t len);
static inline void banner(const char *progname)
{
@@ -94,11 +99,13 @@
int main(int argc, char **argv)
{
    char           *dev="/dev/i2c-1";
    char           *progname=NULL;
    int             mode = MODE_IOCTL;
    int             rv;
    float           temp, rh;
    uint8_t         serialnumber[8];
    char            *progname=NULL;
    sht2x_t         sht2x;
    i2c_t           i2c;
    struct option long_options[] = {
        {"device", required_argument, NULL, 'd'},
@@ -110,21 +117,17 @@
    progname = basename(argv[0]);
    memset(&sht2x, 0, sizeof(sht2x));
    sht2x.addr = SHT2X_CHIPADDR;
    sht2x.dev = "/dev/i2c-1";
    /* Parser the command line parameters */
    while ((rv = getopt_long(argc, argv, "d:m:vh", long_options, NULL)) != -1)
    {
        switch (rv)
        {
            case 'd': /*  Set I2C device path: /dev/i2c-1 */
                sht2x.dev = optarg;
                dev = optarg;
                break;
            case 'm': /*  Set I2C API mode: 0,1 */
                sht2x.mode = atoi(optarg) ? MODE_RDWR : MODE_IOCTL;
                mode = atoi(optarg) ? MODE_RDWR : MODE_IOCTL;
                break;
            case 'v':  /*  Get software version */
@@ -140,19 +143,25 @@
        }
    }
    if( sht2x_init(&sht2x) < 0 )
    if( i2c_init(&i2c, mode, dev, SHT2X_CHIPADDR) < 0 )
    {
        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(&sht2x, serialnumber, 8) < 0)
    if( sht2x_get_serialnumber(&i2c, serialnumber, 8) < 0)
    {
        printf("SHT2x get serial number failure\n");
        return 3;
    }
    if( sht2x_get_temp_humidity(&sht2x, &temp, &rh) < 0 )
    if( sht2x_get_temp_humidity(&i2c, &temp, &rh) < 0 )
    {
        printf("SHT2x get get temperature and relative humidity failure\n");
        return 3;
@@ -160,14 +169,16 @@
    printf("Temperature=%lf ℃ relative humidity=%lf.\n", temp, rh);
    close(sht2x.fd);
    i2c_term(&i2c);
    return 0;
}
int sht2x_softreset(sht2x_t *sht2x)
int sht2x_softreset(i2c_t *i2c)
{
    uint8_t           buf[1];
    if( !sht2x || sht2x->fd<0 )
    if( !i2c || i2c->fd<0 )
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
        return -1;
@@ -175,7 +186,7 @@
    /* software reset SHT2x */
    buf[0] = SOFTRESET;
    if( i2c_write(sht2x, buf, 1) < 0 )
    if( i2c_write(i2c, buf, 1) < 0 )
    {
        return -2;
    }
@@ -185,35 +196,11 @@
    return 0;
}
int sht2x_init(sht2x_t *sht2x)
{
    if( (sht2x->fd=open(sht2x->dev, O_RDWR)) < 0)
    {
        printf("i2c device open failed: %s\n", strerror(errno));
        return -1;
    }
    if( MODE_RDWR == sht2x->mode )
    {
        /* set I2C mode and SHT2x slave address */
        ioctl(sht2x->fd, I2C_TENBIT, 0);    /* Not 10-bit but 7-bit mode */
        ioctl(sht2x->fd, I2C_SLAVE, SHT2X_CHIPADDR); /* set SHT2x slave address 0x40*/
    }
    if( sht2x_softreset(sht2x) < 0 )
    {
        printf("SHT2x softreset failure\n");
        return -2;
    }
    return 0;
}
int sht2x_get_temp_humidity(sht2x_t *sht2x, float *temp, float *rh)
int sht2x_get_temp_humidity(i2c_t *i2c, float *temp, float *rh)
{
    uint8_t           buf[4];
    if( !sht2x || !temp || !rh || sht2x->fd<0 )
    if( !i2c || !temp || !rh || i2c->fd<0 )
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
        return -1;
@@ -222,35 +209,35 @@
    /* send trigger temperature measure command and read the data */
    memset(buf, 0, sizeof(buf));
    buf[0]=TRIGGER_TEMPERATURE_NO_HOLD;
    i2c_write(sht2x, buf, 1);
    i2c_write(i2c, buf, 1);
    msleep(85); /* datasheet: typ=66, max=85 */
    memset(buf, 0, sizeof(buf));
    i2c_read(sht2x, 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;
    /* send trigger humidity measure command and read the data */
    memset(buf, 0, sizeof(buf));
    buf[0] = TRIGGER_HUMIDITY_NO_HOLD;
    i2c_write(sht2x, buf, 1);
    i2c_write(i2c, buf, 1);
    msleep(29); /* datasheet: typ=22, max=29 */
    memset(buf, 0, sizeof(buf));
    i2c_read(sht2x, buf, 3);
    dump_buf("Relative humidity sample data: ", buf, 3);
    i2c_read(i2c, buf, 3);
    print_buf("Relative humidity sample data: ", buf, 3);
    *rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6;
    return 0;
}
int sht2x_get_serialnumber(sht2x_t *sht2x, uint8_t *serialnumber, int size)
int sht2x_get_serialnumber(i2c_t *i2c, uint8_t *serialnumber, int size)
{
    uint8_t           buf[4]={0x0};
    if( !sht2x || sht2x->fd<0 || !serialnumber || size!=8 )
    if( !i2c || i2c->fd<0 || !serialnumber || size!=8 )
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
        return -1;
@@ -260,10 +247,10 @@
    memset(buf, 0, sizeof(buf));
    buf[0] = 0xfa;  /* command for readout on-chip memory */
    buf[1] = 0x0f;  /* on-chip memory address */
    i2c_write(sht2x, buf, 2);
    i2c_write(i2c, buf, 2);
    memset(buf, 0, sizeof(buf));
    i2c_read(sht2x, buf, 4);
    i2c_read(i2c, buf, 4);
    if( !buf[0] && !buf[1] && !buf[2] && !buf[3] )
    {
@@ -280,24 +267,65 @@
    memset(buf, 0, sizeof(buf) );
    buf[0]=0xfc;  /* command for readout on-chip memory */
    buf[1]=0xc9;  /* on-chip memory address */
    i2c_write(sht2x, buf, 2);
    i2c_write(i2c, buf, 2);
    memset(buf, 0, sizeof(buf) );
    i2c_read(sht2x, buf, 4);
    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 */
    dump_buf("SHT2x Serial number: ", serialnumber, 8);
    print_buf("SHT2x Serial number: ", serialnumber, 8);
    return 0;
}
static int i2c_write(sht2x_t *sht2x, 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;
    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)
@@ -307,35 +335,35 @@
    }
    /* I2C device program API: read()/write() */
    if( MODE_RDWR == sht2x->mode )
    if( MODE_RDWR == i2c->mode )
    {
        write(sht2x->fd, data, len);
        write(i2c->fd, data, len);
        return 0;
    }
    /* I2C device program API: ioctl() */
    i2cdata.nmsgs = 1;
    i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs );
    if ( !i2cdata.msgs )
    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 = sht2x->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(sht2x->fd, I2C_RDWR, &i2cdata)<0 )
    if( ioctl(i2c->fd, I2C_RDWR, &tr)<0 )
    {
        printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
        rv = -4;
@@ -343,18 +371,18 @@
    }
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;
}
static int i2c_read(sht2x_t *sht2x, uint8_t *buf, int size)
int i2c_read(i2c_t *i2c, uint8_t *buf, int size)
{
    struct i2c_rdwr_ioctl_data      i2cdata;
    struct i2c_rdwr_ioctl_data      tr;
    int                             rv = 0;
    if( !buf || size<= 0)
@@ -364,40 +392,40 @@
    }
    /* I2C device program API: read()/write() */
    if( MODE_RDWR == sht2x->mode )
    if( MODE_RDWR == i2c->mode )
    {
        read(sht2x->fd, buf, size);
        read(i2c->fd, buf, size);
        return 0;
    }
    /* I2C device program API: ioctl() */
    i2cdata.nmsgs = 1;
    i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs );
    if ( !i2cdata.msgs )
    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 = sht2x->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(sht2x->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 |
 *+----------------+*/
/*+----------------------+
 *|    Misc functions    |
 *+----------------------+*/
static inline void msleep(unsigned long ms)
{
@@ -418,7 +446,7 @@
    nanosleep(&cSleep, 0);
}
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;
@@ -440,3 +468,75 @@
    return ;
}
#define LINELEN 81
#define CHARS_PER_LINE 16
static char *print_char =
"                "
"                "
" !\"#$%&'()*+,-./"
"0123456789:;<=>?"
"@ABCDEFGHIJKLMNO"
"PQRSTUVWXYZ[\\]^_"
"`abcdefghijklmno"
"pqrstuvwxyz{|}~ "
"                "
"                "
" ???????????????"
"????????????????"
"????????????????"
"????????????????"
"????????????????"
"????????????????";
void dump_buf(const char *prompt, char *buf, size_t len)
{
    int rc;
    int idx;
    char prn[LINELEN];
    char lit[CHARS_PER_LINE + 2];
    char hc[4];
    short line_done = 1;
    if( prompt )
        printf("%s", prompt);
    rc = len;
    idx = 0;
    lit[CHARS_PER_LINE] = '\0';
    while (rc > 0)
    {
        if (line_done)
            snprintf(prn, LINELEN, "%08X: ", idx);
        do
        {
            unsigned char c = buf[idx];
            snprintf(hc, 4, "%02X ", c);
            strncat(prn, hc, LINELEN);
            lit[idx % CHARS_PER_LINE] = print_char[c];
        }
        while (--rc > 0 && (++idx % CHARS_PER_LINE != 0));
        line_done = (idx % CHARS_PER_LINE) == 0;
        if (line_done)
        {
            printf("%s  %s\r\n", prn, lit);
        }
    }
    if (!line_done)
    {
        int ldx = idx % CHARS_PER_LINE;
        lit[ldx++] = print_char[(int)buf[idx]];
        lit[ldx] = '\0';
        while ((++idx % CHARS_PER_LINE) != 0)
            strncat(prn, "   ", sizeof(prn)-strlen(prn));
        printf("%s  %s\r\n", prn, lit);
    }
}