上一篇介绍了i2c协议,SHT20是使用标准的i2c接口的温湿度传感器,我们首先要完成树莓派与SHT20传感器的连接:
使能内核I2C驱动模块:
liruiyan@cloud-ubuntu18:~$ sudo raspi-config
重启树莓派,系统启动之后会自动安装i2c的相关驱动:
liruiyan@cloud-ubuntu18:~$ sudo reboot
liruiyan@cloud-ubuntu18:~$ sudo apt-get install i2c-tools
liruiyan@cloud-ubuntu18:~$ lsmod | grep i2c
i2c_bcm2835 16384 0
i2c_dev 16384 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
使用i2cdetect命令可以查看到SHT21温湿度传感器设备地址0x40。
i2c设备驱动有两种模式:一种是用户模式设备驱动,这种驱动依赖于i2c子系统中i2c-dev驱动,这种驱动对应用程序员的要求很高,要
求应用程序员了解硬件的一些东西,了解时序、地址等;另一种是普通的设备驱动,应用程序员在使用的时候就像读写文件
一样,不过这里的read()和write()函数只能对应一条消息。
liruiyan@cloud-ubuntu18:~$ vim sht20.c
1 #include <stdio.h>
2 #include <fcntl.h>
3 #include <unistd.h>
4 #include <sys/ioctl.h>
5 #include <linux/types.h>
6 #include <sys/stat.h>
7 #include <linux/i2c.h>
8 #include <linux/i2c-dev.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <string.h>
13 #include <stdint.h>
14 #include <time.h>
15 #include <errno.h>
16 #include <string.h>
17 #define SOFTRESET 0xFE
18 #define TRIGGER_TEMPERATURE_NO_HOLD 0xF3 //监测温度
19 #define TRIGGER_HUMIDITY_NO_HOLD 0xF5 //监测湿度
20 //#define I2C_API_IOCTL /* Use I2C userspace driver ioctl API */
21 #define I2C_API_RDWR /* Use I2C userspace driver read/write API */
22 static inline void msleep(unsigned long ms);
23 static inline void dump_buf(const char *prompt, uint8_t *buf, int size);
24 int sht2x_init(void); int sht2x_softreset(int fd);
25 int sht2x_get_serialnumber(int fd, uint8_t serialnumber, int size);
26 int sht2x_get_temp_humidity(int fd, float temp, float *rh);
27
28
29 static inline void msleep(unsigned long ms)
30 {
31 struct timespec cSleep;
32 unsigned long ulTmp;
33 cSleep.tv_sec = ms / 1000;
34
35 if (cSleep.tv_sec == 0)
36 {
37 ulTmp = ms * 10000;
38 cSleep.tv_nsec = ulTmp * 100;
39 }
40 else
41 {
42 cSleep.tv_nsec = 0;
43 }
44 nanosleep(&cSleep, 0);
45 }
46
47 static inline void dump_buf(const char *prompt, uint8_t *buf, int size)
48 {
49 int i;
50 if( !buf )
51 {
52 return ;
53 }
54 if( prompt )
55 {
56 printf("%s ", prompt);
57 }
58 for(i=0; i<size; i++)
59 {
60 printf("%02x ", buf[i]);
61 }
62 printf("\n");
63 return ;
64 }
65 /*设备初始化*/
66 int sht2x_init(void)
67 {
68 int fd;
69 if( (fd=open("/dev/i2c-1", O_RDWR)) < 0)
70 {
71 printf("i2c device open failed: %s\n", strerror(errno));
72 return -1;
73 }
74 /* set I2C mode and SHT2x slave address */
75 ioctl(fd, I2C_TENBIT, 0); /* Not 10-bit but 7-bit mode */
76 ioctl(fd, I2C_SLAVE, 0x40); /* 我的sht20设备地址 */
77 return fd;
78 }
79
80 /* 软复位 */
81 int sht2x_softreset(int fd)
82 {
83 uint8_t buf[4];
84 if( fd<0 )
85 {
86 printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
87 return -1;
88 }
89 /* software reset SHT2x */
90 memset(buf, 0, sizeof(buf));
91 buf[0] = SOFTRESET;
92 write(fd, buf, 1);
93 msleep(50);
94
95 return 0;
96 }
97
98 /*获取温湿度*/
99 int sht2x_get_temp_humidity(int fd, float *temp, float *rh) //获取温湿度
100 {
101 uint8_t buf[4];
102 if( fd<0 || !temp || !rh )
103 {
104 printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
105 return -1;
106 }
107
108 /* send trigger temperature measure command and read the data */
109 memset(buf, 0, sizeof(buf));
110 buf[0]=TRIGGER_TEMPERATURE_NO_HOLD;
111 write(fd, buf, 1); //发送监测温度命令
112
113 msleep(85); /* datasheet: typ=66, max=85 */
114 memset(buf, 0, sizeof(buf));
115 read(fd, buf, 3); //读取温度
116 dump_buf("Temperature sample data: ", buf, 3);
117 *temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85;
118
119 /* send trigger humidity measure command and read the data */
120
121 memset(buf, 0, sizeof(buf));
122 buf[0] = TRIGGER_HUMIDITY_NO_HOLD;
123 write(fd, buf, 1); //发送湿度监测命令
124 msleep(29); /* datasheet: typ=22, max=29 */
125 memset(buf, 0, sizeof(buf));
126 read(fd, buf, 3);
127 dump_buf("Relative humidity sample data: ", buf, 3);
128 *rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6;
129
130 return 0;
131 }
132 /*获取序列号*/
133 int sht2x_get_serialnumber(int fd, uint8_t *serialnumber, int size)
134 {
135 uint8_t buf[4];
136 if( fd<0 || !serialnumber || size!=8 )
137 {
138 printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
139 return -1;
140 }
141 memset(buf, 0, sizeof(buf));
142 buf[0] = 0xfa;
143 buf[1] = 0x0f;
144 write(fd, buf, 2);
145
146 memset(buf, 0, sizeof(buf));
147 read(fd, buf, 4);
148
149 serialnumber[5]=buf[0]; /* Read SNB_3 */
150 serialnumber[4]=buf[1]; /* Read SNB_2 */
151 serialnumber[3]=buf[2]; /* Read SNB_1 */
152 serialnumber[2]=buf[3]; /* Read SNB_0 */
153
154 memset(buf, 0, sizeof(buf) );
155 buf[0]=0xfc; /* command for readout on-chip memory */
156 buf[1]=0xc9; /* on-chip memory address */
157 write(fd, buf, 2);
158
159 memset(buf, 0, sizeof(buf) );
160 read(fd, buf, 4);
161 serialnumber[1]=buf[0]; /* Read SNC_1 */
162 serialnumber[0]=buf[1]; /* Read SNC_0 */
163 serialnumber[7]=buf[2]; /* Read SNA_1 */
164 serialnumber[6]=buf[3]; /* Read SNA_0 */
165 dump_buf("SHT2x Serial number: ", serialnumber, 8);
166
167 return 0;
168 }
169 int main(int argc, char **argv)
170 {
171 int fd;
172 float temp;
173 float rh;
174 uint8_t serialnumber[8];
175 fd = sht2x_init();
176 if(fd < 0)
177 {
178 printf("SHT2x initialize failure\n");
179 return 1;
180 }
181 if( sht2x_softreset(fd) < 0 )
182 {
183 printf("SHT2x softreset failure\n");
184 return 2;
185 }
186 if( sht2x_get_serialnumber(fd, serialnumber, 8) < 0)
187 {
188 printf("SHT2x get serial number failure\n");
189 return 3;
190 }
运行结果:
SHT2x Serial number: 40 01 7c 38 da 3e 00 c9
Temperature sample data: 72 28 dd
Relative humidity sample data: 9e 66 3d
Temperature=31.507563 ℃ relative humidity=71.342987%