基于树莓派的sht20温湿度传感器应用(c语言)

一.I2C协议

协议详解

1.1 I2C总线特征

I2C主要靠2根线来控制,一根是SDA(串行数据线),一根是SCL(串行时钟线),通过对SCL和SDA线电平高低的控制,来产生I2C总线协议所需要的信号进行数据传递。空闲时,两根线一般被接上上拉电阻拉高,保持高电平。

1.2 I2C总线特征

I2C总线上分为主设备与从设备,而且每一个设备都会对应一个唯一的地址,通常为7位,最后一位用来作为传输方向的标致,主从设备就通过地址来确定通讯双方。

在通常的应用中,我们把CPU带I2C总线接口的模块作为主设备,把挂接在总线上的其他设备都作为从设备。

1.3 I2C总线协议

I2C协议规定,总线上数据的传输必须以一个其实信号作为开始条件,以一个结束信号作为传输的停止条件。这些信号有主设备控制产生。

  • 起始条件
    总线处于空闲时,SCL与SDA均保持高电平,在此状态下,SDA线由高电平转为低电平,表示产生了一个起始信号
  • 结束信号
    当SCL为高而SDA由低到高跳变,则表示产生了一个结束信号

在这里插入图片描述
数据传输原理:

主设备在SCL线上产生每个时钟脉冲的过程中将在SDA线上传输一个数据位,当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位, 此时才认为一个字节真正的被传输完成。当然,并不是所有的字节传输都必须有一个应答位,比如:当从设备不能再接收主设备发送的数据时,从设备将回传一个否定应答位。

在这里插入图片描述
从上图可知
1.SCL为高,SDA由高跳变为低,表示起始条件;
2.SCL没产生一个时钟信号,SDA上传递1个位的数据;
3.传输完一个字节后,由从设备拉低SDA,回传给主设备一个ACK才能表示这一字节传输完成;
4.SCL为高,SDA由低跳变为高,表示主设备结束对总线的控制,总线重新处于空闲状态。

按地址传输:

I2C总线上的每一个设备都对应一个唯一的地址,主从设备之间的数据传输是建立在地址的基础上,也就是说,主设备在传输有效数据之前 要先指定从设备的地址,地址指定的过程和上面数据传输的过程一样,只不过大多数从设备的地址是7位的,然后协议规定再给地址添加一个最低位用来表示接下来 数据传输的方向,0表示主设备向从设备写数据,1表示主设备向从设备读数据

在这里插入图片描述
1.起始条件结束后,前7个位为从设备地址,第8个位用作传输方向的标致,即主设备 --> 从设备 或者从设备 --> 主设备;
2.每传输完一个字节,都需要从设备回传一个ACK位;
3.传输结束。

1.4 常见的几种传输

主从设备数据的传输,是通过读写文件描述符的方式展开的,下面是3种读写操作:

  1. 主设备向从设备写数据
    在这里插入图片描述

  2. 主设备从从设备中读数据
    在这里插入图片描述

  3. 主设备往从设备中写数据,然后重启起始条件,紧接着从从设备中读取数据;或者是主设备从从设备中读数据,然后重启起始条件,紧接着主设备往从设备中写数据
    在这里插入图片描述

二. sht2x温湿度传感器模块

用户手册:Users Guide SHT20
SHT20是使用标准I2C接口的温湿度传感器,通过sht20的datasheet我们可以了解很多信息,例如:
在这里插入图片描述
1111 1110是16进制的0xFE,当使用这个模块前,需要给从设备写入这个十六进制数,从而在不重启电源的情况下让sht20传感器重启并初始化各项指标。
又如:
在这里插入图片描述
向从设备发送 1110 0011 表示温度测量命令,1110 0101 表示湿度测量命令,前面的1110表示主机模式,而我们应该将命令改为:1111 0011 与 1111 0101 代表非主机模式
只要区别是主机模式时,SCL线被封锁,有传感器进行控制,非主机模式的SCL线处于开放状态,可进行其他通信.
详细请参考sht20用户手册。

三. 基于树莓派的温湿度传感器的应用

3.1 使能i2c驱动

sudo raspi-config 

在这里插入图片描述
在这里插入图片描述
重启树莓派才能生效

3.2 接线

在这里插入图片描述
前面提到,I2C总线上的每个设备都有自己的地址,用下面命令可查看地址:

pi@raspberrypi:~ $  sudo i2cdetect -y 1 
     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: -- -- -- -- -- -- -- --                         

可以看到,我的sht20传感器位于0x40这个地址上
接下来就是获取温湿度的代码了:

3.3 C代码

/*********************************************************************************
 *      Copyright:  (C) 2020 Xiao yang IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  sht20.c
 *    Description:  获取温湿度 
 *                 
 *        Version:  1.0.0(06/20/2020)
 *         Author:  Lu Xiaoyang <[email protected]>
 *      ChangeLog:  1, Release initial version on "06/20/2020 09:06:49 AM"
 *                 
 ********************************************************************************/
#include <stdio.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/ioctl.h> 
#include <linux/types.h> 
#include <sys/stat.h> 
#include <linux/i2c.h> 
#include <linux/i2c-dev.h> 
#include <stdio.h> 
#include <stdlib.h>
#include <sys/types.h> 
#include <string.h> 
#include <stdint.h> 
#include <time.h> 
#include <errno.h> 
#include <string.h>
#define SOFTRESET                        0xFE 
#define TRIGGER_TEMPERATURE_NO_HOLD      0xF3   //监测温度
#define TRIGGER_HUMIDITY_NO_HOLD         0xF5   //监测湿度
//#define I2C_API_IOCTL  /* Use I2C userspace driver ioctl API */
 #define I2C_API_RDWR /* Use I2C userspace driver read/write API */
 
static inline void msleep(unsigned long ms); 
static inline void dump_buf(const char *prompt, uint8_t *buf, int size); 
int sht2x_init(void); int sht2x_softreset(int fd); 
int sht2x_get_serialnumber(int fd, uint8_t *serialnumber, int size); 
int sht2x_get_temp_humidity(int fd, float *temp, float *rh); 

int main(int argc, char **argv) 
{        
        int          fd;        
        float        temp;        
        float        rh;        
        uint8_t      serialnumber[8];
        fd = sht2x_init();     
           
        if(fd < 0)        
        {                
                 printf("SHT2x initialize failure\n");                
                 return 1;        
        }
        if( sht2x_softreset(fd) < 0 )        
        {                
                 printf("SHT2x softreset failure\n");                
                 return 2;        
        }
        
        if( sht2x_get_serialnumber(fd, serialnumber, 8) < 0)        
        {
                printf("SHT2x get serial number failure\n");                
                return 3;        
        }
        if( sht2x_get_temp_humidity(fd, &temp, &rh) < 0 )        
        {                
                printf("SHT2x get get temperature and relative humidity failure\n");                
                return 3;        
        }
        
        printf("Temperature=%lf ℃ relative humidity=%lf%\n", temp, rh);
        
        close(fd); 
 }
 
static inline void msleep(unsigned long ms) 
{        
        struct timespec cSleep;        
        unsigned long ulTmp;               
        cSleep.tv_sec = ms / 1000;  
              
        if (cSleep.tv_sec == 0)        
        {                   
                ulTmp = ms * 10000;                
                cSleep.tv_nsec = ulTmp * 100;        
        }           
        else        
        {                   
                cSleep.tv_nsec = 0;        
        }   
        nanosleep(&cSleep, 0); 
}

static inline void dump_buf(const char *prompt, uint8_t *buf, int size) 
{        
        int          i;
        if( !buf )        
        {                
                return ;        
        }
        if( prompt )        
        {                
                printf("%s ", prompt);        
        }
        for(i=0; i<size; i++)        
        {                
                 printf("%02x ", buf[i]);        
        }        
        printf("\n");
        return ; 
}

int sht2x_init(void) 
{        
        int     fd;
        if( (fd=open("/dev/i2c-1", O_RDWR)) < 0)        
        {                
                printf("i2c device open failed: %s\n", strerror(errno));                
                return -1;        
        }
        /* set I2C mode and SHT2x slave address */        
        ioctl(fd, I2C_TENBIT, 0);    /* Not 10-bit but 7-bit mode */
        ioctl(fd, I2C_SLAVE, 0x40); /* 我的sht20设备地址 */
        return fd; 
}

/* 初始化设备 */
int sht2x_softreset(int fd) 
{        
        uint8_t           buf[4];
        if( fd<0 )        
        {                
                printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); 
                return -1;        
        }
        /* software reset SHT2x */        
        memset(buf, 0, sizeof(buf));
        buf[0] = SOFTRESET;        
        write(fd, buf, 1);
        msleep(50);
        
        return 0; 
}

int sht2x_get_temp_humidity(int fd, float *temp, float *rh) 
{        
        uint8_t           buf[4];
        if( fd<0 || !temp || !rh )        
        {                
                printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );                   
                return -1;        
        }
        /* send trigger temperature measure command and read the data */        
        memset(buf, 0, sizeof(buf));        
        buf[0]=TRIGGER_TEMPERATURE_NO_HOLD;          
        write(fd, buf, 1);  //发送监测温度命令
        
        msleep(85); /* datasheet: typ=66, max=85 */
        memset(buf, 0, sizeof(buf));        
        read(fd, buf, 3);  //读取温度  
        dump_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;        
         write(fd, buf, 1);  //发送湿度监测命令
         msleep(29); /* datasheet: typ=22, max=29 */        
         memset(buf, 0, sizeof(buf));
         read(fd, buf, 3);        
         dump_buf("Relative humidity sample data: ", buf, 3);        
         *rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6;
         
        return 0; 
}

3.4 运行实现

在这里插入图片描述
sht20温湿度传感器获取数据的方式与ds18b20温度传感器有着很大的差别,一个是通过I2C协议通讯的到相关信息,而后者则是通过一线协议在文件中读取,较为简单。

猜你喜欢

转载自blog.csdn.net/weixin_45121946/article/details/106969284