RaspberrPi project source code
Guo Wenxue
2024-12-29 8517494b239d652ea9a24457faa13f88f55979b9
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 the Lux sensor TSL2561 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      <----->      #Pin27(SDA, BCM GPIO0)
16  *                   SCL      <----->      #Pin28(SCL, BCM GPIO1)
17  *                   GND      <----->      GND
18  *
19  * /boot/config.txt:
20  *                  dtoverlay=i2c0,pins_0_1
21  *
22  ********************************************************************************/
23
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <math.h>
30 #include <time.h>
31 #include <errno.h>
32 #include <libgen.h>
33 #include <getopt.h>
34 #include <fcntl.h>
35 #include <sys/ioctl.h>
36 #include <linux/i2c.h>
37 #include <linux/i2c-dev.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40
41 #define TSL2561_I2C_ADDR                0x39
42
43 #define CONTROL_REG                     0x80
44 #define REG_COUNT                       4
45
46 #define POWER_UP                        0x03
47 #define POWER_DOWN                      0x00
48
49 #define OFF                             0
50 #define ON                              1
51
52 /* Register Address  */
53 enum
54 {
55     /* Channel_0 = DATA0HIGH<<8 + DATA0LOW */
56     DATA0LOW = 0x8C,
57     DATA0HIGH,
58
59     /* Channel_1 = DATA1HIGH<<8 + DATA1LOW */
60     DATA1LOW,
61     DATA1HIGH,
62 };
63
64 static const int  regs_addr[REG_COUNT]={DATA0LOW, DATA0HIGH, DATA1LOW, DATA1HIGH};
65
66 float tsl2561_get_lux(int fd);
67 static inline void print_datime(void);
68
69 static inline void banner(const char *progname)
70 {
71     printf("%s program Version v1.0.0\n", progname);
72     printf("Copyright (C) 2023 LingYun IoT System Studio.\n");
73 }
74
75 static void program_usage(const char *progname)
76 {
77
78     printf("Usage: %s [OPTION]...\n", progname);
79     printf(" %s is TSL2561 Lux sensor program.\n", progname);
80
81     printf(" -d[device  ]  Specify I2C device, such as /dev/i2c-0\n");
82     printf(" -h[help    ]  Display this help information\n");
83     printf(" -v[version ]  Display the program version\n");
84
85     printf("\n");
86     banner(progname);
87     return;
88 }
89
90 int main(int argc, char **argv)
91 {
92     int             fd, rv;
93     float           lux;
94     char           *dev = "/dev/i2c-0";
95     char           *progname=NULL;
96
97     struct option long_options[] = {
98         {"device", required_argument, NULL, 'd'},
99         {"version", no_argument, NULL, 'v'},
100         {"help", no_argument, NULL, 'h'},
101         {NULL, 0, NULL, 0}
102     };
103
104     progname = basename(argv[0]);
105
106     /* Parser the command line parameters */
107     while ((rv = getopt_long(argc, argv, "d:vh", long_options, NULL)) != -1)
108     {
109         switch (rv)
110         {
111             case 'd': /*  Set I2C device path: /dev/i2c-1 */
112                 dev = optarg;
113                 break;
114
115             case 'v':  /*  Get software version */
116                 banner(progname);
117                 return EXIT_SUCCESS;
118
119             case 'h':  /*  Get help information */
120                 program_usage(progname);
121                 return 0;
122
123             default:
124                 break;
125         }
126     }
127
128     /*+--------------------------------+
129      *|     open /dev/i2c-x device     |
130      *+--------------------------------+*/
131     if( (fd=open(dev, O_RDWR)) < 0)
132     {
133         printf("i2c device '%s' open failed: %s\n", dev, strerror(errno));
134         return -1;
135     }
136
137     while(1)
138     {
139         lux = tsl2561_get_lux(fd);
140
141         print_datime();
142         printf("TSLl2561 get lux: %.3f\n", lux);
143
144         sleep(1);
145     }
146
147     close(fd);
148     return 0;
149 }
150
151 static inline void print_datime(void)
152 {
153     time_t         tmp;
154     struct tm     *p;
155
156     time(&tmp);
157
158     p=localtime(&tmp);
159
160
161     printf("%d-%02d-%02d %02d:%02d:%02d\t", (p->tm_year+1900),(p->tm_mon+1),
162             p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
163
164 }
165
166 static inline void msleep(unsigned long ms)
167 {
168     struct timespec cSleep;
169     unsigned long ulTmp;
170
171     cSleep.tv_sec = ms / 1000;
172     if (cSleep.tv_sec == 0)
173     {
174         ulTmp = ms * 10000;
175         cSleep.tv_nsec = ulTmp * 100;
176     }
177     else
178     {
179         cSleep.tv_nsec = 0;
180     }
181
182     nanosleep(&cSleep, 0);
183     return ;
184 }
185
186 void tsl2561_power(int fd, int cmd)
187 {
188     struct i2c_msg               msg;
189     struct i2c_rdwr_ioctl_data   data;
190     unsigned char                buf[2];
191
192     msg.addr= TSL2561_I2C_ADDR;
193     msg.flags=0;  /* write */
194     msg.len= 1;
195     msg.buf= buf;
196
197     data.nmsgs= 1;
198     data.msgs= &msg;
199
200     msg.buf[0]=CONTROL_REG;
201     if( ioctl(fd, I2C_RDWR, &data) < 0 )
202     {
203         printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
204         return ;
205     }
206
207
208     if( cmd )
209         msg.buf[0]=POWER_UP;
210     else
211         msg.buf[0]=POWER_DOWN;
212
213     if( ioctl(fd, I2C_RDWR, &data) < 0 )
214     {
215         printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
216         return ;
217     }
218
219     return ;
220 }
221
222 int tsl2561_readreg(int fd, unsigned char regaddr, unsigned char *regval)
223 {
224     struct i2c_msg               msg;
225     struct i2c_rdwr_ioctl_data   data;
226     unsigned char                buf[2];
227
228     msg.addr= TSL2561_I2C_ADDR;
229     msg.flags=0;  /* write */
230     msg.len= 1;
231     msg.buf= buf;
232     msg.buf[0] = regaddr;
233
234     data.nmsgs= 1;
235     data.msgs= &msg;
236
237     if( ioctl(fd, I2C_RDWR, &data) < 0 )
238     {
239         printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
240         return -1;
241     }
242
243     memset(buf, 0, sizeof(buf));
244
245     msg.addr= TSL2561_I2C_ADDR;
246     msg.flags=I2C_M_RD;  /* read */
247     msg.len= 1;
248     msg.buf= buf;
249
250     data.nmsgs= 1;
251     data.msgs= &msg;
252
253     if( ioctl(fd, I2C_RDWR, &data) < 0 )
254     {
255         printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
256         return -1;
257     }
258
259     *regval = msg.buf[0];
260     return 0;
261 }
262
263 float tsl2561_get_lux(int fd)
264 {
265     int                 i;
266     unsigned char       reg_data[REG_COUNT];
267     unsigned char       buf;
268
269     int                 chn0_data = 0;
270     int                 chn1_data = 0;
271
272     float               div = 0.0;
273     float               lux = 0.0;
274
275     tsl2561_power(fd, ON);
276
277     msleep(410);  /* t(CONV) MAX 400ms */
278
279     /* Read register Channel0 and channel1 data from register */
280     for(i=0; i<REG_COUNT; i++)
281     {
282         tsl2561_readreg(fd, regs_addr[i], &reg_data[i]);
283     }
284
285     chn0_data = reg_data[1]*256 + reg_data[0]; /* Channel0 = DATA0HIGH<<8 + DATA0LOW  */
286     chn1_data = reg_data[3]*256 + reg_data[2]; /* channel1 = DATA1HIGH<<8 +  DATA1LOW */
287
288     if( chn0_data<=0 || chn1_data<0 )
289     {
290         lux = 0.0;
291         goto OUT;
292     }
293
294     div = (float)chn1_data / (float)chn0_data;
295
296     if( div>0 && div<=0.5 )
297         lux = 0.304*chn0_data-0.062*chn0_data*pow(div,1.4);
298
299     else if( div>0.5 && div<=0.61 )
300         lux = 0.0224*chn0_data-0.031*chn1_data;
301
302     else if( div>0.61 && div<=0.8 )
303         lux = 0.0128*chn0_data-0.0153*chn1_data;
304
305     else if( div>0.8 && div<=1.3 )
306         lux = 0.00146*chn0_data-0.00112*chn1_data;
307
308     else if( div>1.3 )
309         lux = 0.0;
310
311 OUT:
312     tsl2561_power(fd, OFF);
313     return lux;
314 }
315
316 static inline void dump_buf(const char *prompt, char *buf, int size)
317 {
318     int          i;
319
320     if( !buf )
321     {
322         return ;
323     }
324
325     if( prompt )
326     {
327         printf("%-32s ", prompt);
328     }
329
330     for(i=0; i<size; i++)
331     {
332         printf("%02x ", buf[i]);
333     }
334     printf("\n");
335
336     return ;
337 }