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