RaspberrPi project source code
Guo Wenxue
2023-09-08 bffa2be267ab1fdafbc6c9348df053e477e63f49
commit | author | age
d6b4a7 1 /*********************************************************************************
G 2  *      Copyright:  (C) 2023 LingYun IoT System Studio
3  *                  All rights reserved.
4  *
5  *       Filename:  sht20.c
6  *    Description:  This file is temperature and relative humidity sensor SHT20 code
7  *
8  *        Version:  1.0.0(10/08/23)
9  *         Author:  Guo Wenxue <guowenxue@gmail.com>
10  *      ChangeLog:  1, Release initial version on "10/08/23 17:52:00"
11  *
12  * Pin connection:
13  *               STH20 Module            Raspberry Pi Board
14  *                   VCC      <----->      #Pin1(3.3V)
15  *                   SDA      <----->      #Pin3(SDA, BCM GPIO2)
16  *                   SCL      <----->      #Pin5(SCL, BCM GPIO3)
17  *                   GND      <----->      GND
18  *
19  * /boot/config.txt:
20  *                  dtoverlay=i2c1,pins_2_3
21  *
22  ********************************************************************************/
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <libgen.h>
31 #include <getopt.h>
32 #include <time.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <sys/ioctl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <linux/types.h>
39 #include <linux/i2c.h>
40 #include <linux/i2c-dev.h>
41
42 int i2c_write(int fd, uint8_t slave_addr, uint8_t *data, int len);
43 int i2c_read(int fd, uint8_t slave_addr, uint8_t *buf, int size);
44 int sht20_checksum(uint8_t *data, int len, int8_t checksum);
45 static inline void msleep(unsigned long ms);
46 static inline void dump_buf(const char *prompt, uint8_t *buf, int size);
47
48 static inline void banner(const char *progname)
49 {
50     printf("%s program Version v1.0.0\n", progname);
51     printf("Copyright (C) 2023 LingYun IoT System Studio.\n");
52 }
53
54 static void program_usage(const char *progname)
55 {
56
57     printf("Usage: %s [OPTION]...\n", progname);
58     printf(" %s is SHT20 temperature and humidity sensor program. \n", progname);
59
60     printf(" -d[device  ]  Specify I2C device, such as /dev/i2c-1\n");
61     printf(" -h[help    ]  Display this help information\n");
62     printf(" -v[version ]  Display the program version\n");
63
64     printf("\n");
65     banner(progname);
66     return;
67 }
68
69 int main(int argc, char **argv)
70 {
71     int             fd, rv;
72     float           temp, rh;
73     char           *dev = "/dev/i2c-1";
74     char           *progname=NULL;
75     uint8_t         buf[4];
76
77     struct option long_options[] = {
78         {"device", required_argument, NULL, 'd'},
79         {"version", no_argument, NULL, 'v'},
80         {"help", no_argument, NULL, 'h'},
81         {NULL, 0, NULL, 0}
82     };
83
84     progname = basename(argv[0]);
85
86     /* Parser the command line parameters */
87     while ((rv = getopt_long(argc, argv, "d:vh", long_options, NULL)) != -1)
88     {
89         switch (rv)
90         {
91             case 'd': /*  Set I2C device path: /dev/i2c-1 */
92                 dev = optarg;
93                 break;
94
95             case 'v':  /*  Get software version */
96                 banner(progname);
97                 return EXIT_SUCCESS;
98
99             case 'h':  /*  Get help information */
100                 program_usage(progname);
101                 return 0;
102
103             default:
104                 break;
105         }
106     }
107
108
109     /*+--------------------------------+
110      *|     open /dev/i2c-x device     |
111      *+--------------------------------+*/
112     if( (fd=open(dev, O_RDWR)) < 0)
113     {
114         printf("i2c device '%s' open failed: %s\n", dev, strerror(errno));
115         return -1;
116     }
117
118     /*+--------------------------------+
119      *|   software reset SHT20 sensor  |
120      *+--------------------------------+*/
121
122     buf[0] = 0xFE;
123     i2c_write(fd, 0x40, buf, 1);
124
125     msleep(50);
126
127
128     /*+--------------------------------+
129      *|   trigger temperature measure  |
130      *+--------------------------------+*/
131
132     buf[0] = 0xF3;
133     i2c_write(fd, 0x40, buf, 1);
134
135     msleep(85); /* datasheet: typ=66, max=85 */
136
137     memset(buf, 0, sizeof(buf));
138     i2c_read(fd, 0x40, buf, 3);
139     dump_buf("Temperature sample data: ", buf, 3);
140
141     if( !sht20_checksum(buf, 2, buf[2]) )
142     {
143         printf("Temperature sample data CRC checksum failure.\n");
144         goto cleanup;
145     }
146
147     temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85;
148
149
150     /*+--------------------------------+
151      *|    trigger humidity measure    |
152      *+--------------------------------+*/
153
154     buf[0] = 0xF5;
155     i2c_write(fd, 0x40, buf, 1);
156
157     msleep(29); /* datasheet: typ=22, max=29 */
158
159     memset(buf, 0, sizeof(buf));
160     i2c_read(fd, 0x40, buf, 3);
161     dump_buf("Relative humidity sample data: ", buf, 3);
162
163     if( !sht20_checksum(buf, 2, buf[2]) )
164     {
165         printf("Relative humidity sample data CRC checksum failure.\n");
166         goto cleanup;
167     }
168
169     rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6;
170
171     /*+--------------------------------+
172      *|    print the measure result    |
173      *+--------------------------------+*/
174
175     printf("Temperature=%lf 'C relative humidity=%lf%%\n", temp, rh);
176
177 cleanup:
178     close(fd);
179     return 0;
180 }
181
182 int sht20_checksum(uint8_t *data, int len, int8_t checksum)
183 {
184     int8_t crc = 0;
185     int8_t bit;
186     int8_t byteCtr;
187
188     //calculates 8-Bit checksum with given polynomial: x^8 + x^5 + x^4 + 1
189     for (byteCtr = 0; byteCtr < len; ++byteCtr)
190     {
191         crc ^= (data[byteCtr]);
192         for ( bit = 8; bit > 0; --bit)
193         {
194             /* x^8 + x^5 + x^4 + 1 = 0001 0011 0001 = 0x131 */
195             if (crc & 0x80) crc = (crc << 1) ^ 0x131;
196             else crc = (crc << 1);
197         }
198     }
199
200     if (crc != checksum)
201         return 0;
202     else
203         return 1;
204 }
205
206 int i2c_write(int fd, uint8_t slave_addr, uint8_t *data, int len)
207 {
208     struct i2c_rdwr_ioctl_data i2cdata;
209     int rv = 0;
210
211     if( !data || len<= 0)
212     {
213         printf("%s() invalid input arguments!\n", __func__);
214         return -1;
215     }
216
217     i2cdata.nmsgs = 1;
218     i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs );
219     if ( !i2cdata.msgs )
220     {
221         printf("%s() msgs malloc failed!\n", __func__);
222         return -2;
223     }
224
225     i2cdata.msgs[0].addr = slave_addr;
226     i2cdata.msgs[0].flags = 0; //write
227     i2cdata.msgs[0].len = len;
228     i2cdata.msgs[0].buf = malloc(len);
229     if( !i2cdata.msgs[0].buf )
230     {
231         printf("%s() msgs malloc failed!\n", __func__);
232         rv = -3;
233         goto cleanup;
234     }
235     memcpy(i2cdata.msgs[0].buf, data, len);
236
237
238     if( ioctl(fd, I2C_RDWR, &i2cdata)<0 )
239     {
240         printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
241         rv = -4;
242         goto cleanup;
243     }
244
245 cleanup:
246     if( i2cdata.msgs[0].buf )
247         free(i2cdata.msgs[0].buf);
248
249     if( i2cdata.msgs )
250         free(i2cdata.msgs);
251
252     return rv;
253 }
254
255 int i2c_read(int fd, uint8_t slave_addr, uint8_t *buf, int size)
256 {
257     struct i2c_rdwr_ioctl_data i2cdata;
258     int rv = 0;
259
260     if( !buf || size<= 0)
261     {
262         printf("%s() invalid input arguments!\n", __func__);
263         return -1;
264     }
265
266     i2cdata.nmsgs = 1;
267     i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs );
268     if ( !i2cdata.msgs )
269     {
270         printf("%s() msgs malloc failed!\n", __func__);
271         return -2;
272     }
273
274     i2cdata.msgs[0].addr = slave_addr;
275     i2cdata.msgs[0].flags = I2C_M_RD; //read
276     i2cdata.msgs[0].len = size;
277     i2cdata.msgs[0].buf = buf;
278     memset(buf, 0, size);
279
280     if( ioctl(fd, I2C_RDWR, &i2cdata)<0 )
281     {
282         printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
283         rv = -4;
284     }
285
286     free( i2cdata.msgs );
287     return rv;
288 }
289
290 static inline void msleep(unsigned long ms)
291 {
292     struct timespec cSleep;
293     unsigned long ulTmp;
294
295     cSleep.tv_sec = ms / 1000;
296     if (cSleep.tv_sec == 0)
297     {
298         ulTmp = ms * 10000;
299         cSleep.tv_nsec = ulTmp * 100;
300     }
301     else
302     {
303         cSleep.tv_nsec = 0;
304     }
305
306     nanosleep(&cSleep, 0);
307     return ;
308 }
309
310 static inline void dump_buf(const char *prompt, uint8_t *buf, int size)
311 {
312     int          i;
313
314     if( !buf )
315     {
316         return ;
317     }
318
319     if( prompt )
320     {
321         printf("%-32s ", prompt);
322     }
323
324     for(i=0; i<size; i++)
325     {
326         printf("%02x ", buf[i]);
327     }
328     printf("\n");
329
330     return ;
331 }