IGKBoard(imx6ull)-I2C接口编程之SHT20温湿度采样

news2024/9/21 14:29:40

文章目录

    • 1- 使能开发板I2C通信接口
    • 2- SHT20硬件连接
    • 3- 编码实现SHT20温湿度采样思路
      • (1)查看sht20从设备地址(i2cdetect)
      • (2)获取数据大体流程
        • 【1】软复位
        • 【2】触发测量与通讯时序
      • (3)返回数据处理
    • 4- SHT20温湿度采样编程源码
    • 5- 代码难点巩固
      • (1)ioctl函数讲解
      • (2)移位、与或处理数据


I2C 总线是一种同步、半双工、采用电平信号收发的串行总线。

关于I2C不了解的可以参考写的这篇文章:I2C协议介绍以及HAL库实现I2C对SHT30温湿度采样

1- 使能开发板I2C通信接口

在我的开发板上有两路I2C外设:

I2C2 ---> 触摸屏控制器,rtc时钟,摄像头控制器
I2C1 ---> 40pin扩展口使用,由DToverlay进行开启
GPIO01_IO03 ---> I2C1_SDA
GPIO01_IO03 ---> I2C1_SCL

想要使能40pin扩展口的I2C1的话,需要修改开发板上的DTOverlay配置文件,添加该管脚对I2C的支持,具体修改具体方法为修改 eMMC 启动介质的 boot 分区下的 config.txt 文件,将dtoverlay_i2c1的选项修改为yes:

root@igkboard:~# vi /run/media/mmcblk1p1/config.txt
# Enable I2C overlay
dtoverlay_i2c1=yes

修改完成后重启系统,系统启动时将会自动加载 I2C 协议驱动。查看/dev下是否存在I2C设备节点,或查看/sys/bus/i2c/devices中设备文件,已验证I2C驱动是否加载。

oot@igkboard:~# ls -l /dev/i2c-*
crw------- 1 root root 89, 0 Mar  1 10:24 /dev/i2c-0
crw------- 1 root root 89, 1 Mar  1 10:24 /dev/i2c-1
root@igkboard:~# ls /sys/bus/i2c/devices/
1-006f  i2c-0  i2c-1

由于驱动是从0开始编写的,故实际的I2C1对应的设备节点是i2c-0。


2- SHT20硬件连接

  • VCC:3.3V
  • GND:GND
  • SCL:I2C1_SCL
  • SDA:I2C1_SDA

在这里插入图片描述
参考图:
在这里插入图片描述
实物连接图:
在这里插入图片描述


3- 编码实现SHT20温湿度采样思路

(1)查看sht20从设备地址(i2cdetect)

总线上挂载I2C从设备,可通过i2cdetect扫描某个I2C总线上的所有设备。可通过控制台输入i2cdetect -y 1或0(确定哪一条总线) 来查看所有设备。

root@igkboard:~#  i2cdetect -y 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: -- -- -- -- -- -- -- --

显示的是以十六进制表示的设备地址的编号,40(16进制)即1000000(2进制)。

(2)获取数据大体流程

【1】软复位

此命令用于重新启动传感器系统,而无需重新上电。一旦接收到该命令,传感器系统将重新初始化并根据默认设置开始操作。软复位时间小于15ms。
在这里插入图片描述

【2】触发测量与通讯时序

下面右图:我们常用红色框选中的命令,使用非保持主机模式(no hold master)的命令,可以使sht20在测量时候,释放i2c总线,使得主机可以处理其他从设备的通信任务。
下面左图:我们可以看见sht20的通讯时序(时序的开始以及停止以及发送数据等的内容可以参考开头的文章。)。

  • Start开始,从地址+0通知sht30我们将要写入,收到ACK相响应成功;
  • 对sht20写入非保持主机模式(no hold master)的命令(即右图的11110101),收到ACK响应成功等待,Stop;
  • 然后发送地址+1读数据信号,返回ACK响应即可;
  • 后面就可以读取我们需要的数据了。

在这里插入图片描述

(3)返回数据处理

测量的数据,温度和湿度均为两个字节。而且无论哪一种传输模式,测量的最大分辨率最大14bit,数据的第二个字节SDA上最后两位是用来标记相关状态信息。其中bit1表示测量类型(0是温度,1是湿度)

SDA的输出数据被转换成两个字节的数据包,高字节MSB在前(左对齐)。每个字节后面都跟随一个应答位。两个状态位,即 LSB的后两位在进行物理计算前须置0。

我们上面时序的例子返回了两个字节数据:
高字节数据:0110 0011
低字节数据:0101 0010(bit1是1,说明返回的是湿度的测量数据)
在这里插入图片描述
我们需要将我们收到的数据用提供的计算方法计算出相对应的湿度值。
除去最后的2bit(就是将最后的2bit换为00),也就是0110 0011 0101 0000(2进制) = 25424(10进制),然后代入公式得到数据:

RH = -6 + 125*(25424 / 65536) = 42.4924 #单位为%

在这里插入图片描述


4- SHT20温湿度采样编程源码

源码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <linux/i2c-dev.h>

#define SOFTRESET          0xFE;//16进制软复位1111 11110
#define TRIGGER_T_NO_HOLD  0xF3;//16进制温度触发测量1111 0011
#define TRIGGER_RH_NO_HOLD 0xF5;//16进制湿度触发测量1111 0101

void mssleep(unsigned long ms);//毫秒级函数实现(nanosleep)
int sht20_init(char *i2c_dev);//初始化从设备函数
int sht20_softreset(int fd);//sht20命令复位函数
int sht20_get_t_rh(int fd, float *temperature, float *humidity);//buf处理函数

int main(int argc, char *argv[])
{
    int fd;
    float temperature;
    float humidity;

    if(argc != 2)
    {
        printf("This project is to obtain the temperature and humidity of sht20.\n");
        printf("Please input %s /dev/i2c-x\n", argv[0]);
        return 0;
    }
    fd = sht20_init(argv[1]);
    if(fd < 0)
    {
        printf("SHT20 init failure\n");
        return 1;
    }
    //printf("sht20_init success\n");
    while(1)
    {
        if(sht20_get_t_rh(fd, &temperature, &humidity) < 0)
        {
            printf("SHT20 get temperature and humidity failure\n");
            return 2;
        }
        //printf("sht20_get_t_rh success\n");
        printf("Temperature:%lf'C Humidity:%lf%% \n", temperature, humidity);
        sleep(1);
    }
    close(fd);

    return 0;
}

/*对buf里面的数据进行处理打印*/
static inline void manage_buf(uint8_t *buf, int size )
{
    int i;

    for(i = 0; i < size; i++)
    {
        printf("%02x ", buf[i]);//以16进制输出,不足2位左边补0
    }
    printf("\n");
}

/*获取sht20温湿度值*/
int sht20_get_t_rh(int fd, float *temperature, float *humidity)
{
    uint8_t buf[4];//一个字节8个位,比如buf[0]刚好读取一个字节,好操作
    int rv = 0;

    if(fd < 0 || !temperature || !humidity)
    {
        printf("%s get invalid input arguments\n", __FUNCTION__);
        return -1;
    }

    /*获取温度*/
    memset(buf, 0, sizeof(buf));
    buf[0] = TRIGGER_T_NO_HOLD;//16进制温度触发测量1111 0011
    if(rv = write(fd, buf, 1) < 0)
    {
        printf("Write TRIGGER_T_NO_HOLD error:%s\n", strerror(errno));
        return -2;
    }

    mssleep(85);//等待需要的时间

    memset(buf, 0, sizeof(buf));//读取数值放在buf中,需要将buf清0
    /*读取三个字节数据,后面的一个字节数据是CRC校验值*/
    if(rv = read(fd, buf, 3) < 0)
    {
        printf("Read temperature error:%s\n", strerror(errno));
        return -3;
    }
    manage_buf(buf, 3);//buf处理函数
    /*
    需要将读取到的buf[0]和buf[1]合并,
    buf[0]左移8bit,然后加上后面的buf[1],即可
    但是最后2bit是都需要变成0u,
    于是与1111 1100(0xfc)与(&),就可以将最后2bit变成0了
    
    1010 1111
   &1111 1100
   -----------
    1010 1100
    */
    *temperature = 175.72 * (((((int)buf[0]) << 8) + (buf[1] & 0xfc)) / 65536.0) - 46.85;//temperature计算(℃  )

    /*获取湿度*/
    memset(buf, 0, sizeof(buf));
    buf[0] = TRIGGER_RH_NO_HOLD;//16进制湿度触发测量1111 0101
    if(rv = write(fd, buf, 1) < 0)
    {
        printf("Write TRIGGER_RH_NO_HOLD error:%s\n", strerror(errno));
        return -4;
    }

    mssleep(29);//等待需要的时间

    memset(buf, 0, sizeof(buf));//读取数值放在buf中,需要将buf清0
    if(rv = read(fd, buf, 3) < 0)
    {
        printf("Read humidity error:%s\n", strerror(errno));
        return -5;
    }
    //读取三个字节数据,后面的一个字节数据是CRC校验值
    manage_buf(buf, 3);//buf处理函数
    *humidity = 125 * (((((int)buf[0]) << 8) + (buf[1] & 0xfc)) / 65536.0) - 6;//湿度处理函数

    return 0;
}

/*初始化sht20,从设备地址,位数以及软复位*/
int sht20_init(char *i2c_dev)
{
    int fd;

    if((fd = open(i2c_dev, O_RDWR)) < 0)
    {
        printf("Open %s error: %s\n", i2c_dev, strerror(errno));
        return -1;
    }

    ioctl(fd, I2C_TENBIT, 0);//选择地址长度0为7位地址,非0为10位
    ioctl(fd, I2C_SLAVE, 0x40);//设置从设备的地址
    if(sht20_softreset(fd) < 0)
    {
        printf("SHT20 softreset failure\n");
        return -2;
    }
    return fd;
}

/*软复位*/
int sht20_softreset(int fd)
{
    uint8_t buf[4];

    if(fd < 0)
    {
        printf("%s get invalid input arguments\n", __FUNCTION__);//无效的参数
        return -1;
    }
    memset(buf, 0, sizeof(buf));
    buf[0] = SOFTRESET;//0xfe二进制1111 1110
    write(fd, buf, 1);//写入数据执行软复位

    mssleep(50);

    return 0;
}

/*毫秒级别函数实现*/
void mssleep(unsigned long ms)
{
    struct timespec ts = {
        .tv_sec  = (long int) (ms / 1000),
        .tv_nsec = (long int) (ms % 1000) * 1000000ul
    };

    nanosleep(&ts, 0);
}

Makefile:

CC=arm-linux-gnueabihf-gcc
APP_NAME=sht20

all:clean
	@${CC} ${APP_NAME}.c -o ${APP_NAME}

clean:
	@rm -f ${APP_NAME}

tftp搭建有问题的可以参考这篇文章:wpa_supplicant无线网络配置imx6ull以及搭建tftp服务器
tftp服务器下载到开发板运行:

root@igkboard:~# tftp -gr sht20 192.168.0.172
root@igkboard:~# chmod a+x sht20             
root@igkboard:~# ./sht20 /dev/i2c-0          
67 7c 7e 
67 6e 5f 
Temperature:24.182322'C Humidity:44.498962% 
67 80 81 
67 6e 5f 
Temperature:24.193047'C Humidity:44.498962% 
67 84 45 
67 6e 5f 
Temperature:24.203772'C Humidity:44.498962% 
67 88 38 
67 7e 1c 
Temperature:24.214497'C Humidity:44.529480% 
68 ec de 
68 4e 40 
Temperature:25.169031'C Humidity:44.926208% 
69 34 97 
7e 5e 37 
Temperature:25.362083'C Humidity:55.698914% 
6b 18 b5 
95 aa 1d 
Temperature:26.659819'C Humidity:67.074341% 
6b 68 4d 
a6 12 84 
Temperature:26.874321'C Humidity:75.085205% 
6e 14 bf 
b2 76 16 
Temperature:28.708313'C Humidity:81.135315% 
6c ac 60 
bb 06 2d 
Temperature:27.743053'C Humidity:85.316223% 
6b a0 b3 
c0 a6 f0 
Temperature:27.024473'C Humidity:88.062805% 

对着传感器哈气,就会看见温湿度的变化。
毫秒级别函数实现可以参考这篇文章:C语言中usleep与nanosleep函数讲解以及毫秒级休眠实现


5- 代码难点巩固

(1)ioctl函数讲解

#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);

在代码中我们使用ioctl函数给初始化sht20的从地址,以及设置选择地址的长度为7位地址。
request参数我们用到了:

  • I2C_SLAVE :设置从机地址
  • I2C_TENBIT :选择地址长度0为7位地址,非0为10位
  • I2C_RETRIES :设置收不到ACK时的重试次数,默认为1(没有用到,但是可以了解)

参数使用就需要调用#include <linux/i2c-dev.h>头文件了

从时序中我们可以看见如果需要读和写的话需要发送1个字节数据然后等待从设备响应返回ACK,但是如果使用ioctl系统调用初始化好i2c设备后,设置从设备地址后,便可以使用write和read系统调用进行数据的写入和读取,方便很多。

(2)移位、与或处理数据

下面程序帮助理解,都有注释,实际应用中用多了也就比较熟练了。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char *argv[])
{
    uint8_t buf[4];
    buf[0] = 0xFF;//0xFF(十六进制),1111 1111(二进制),255(十进制)
    buf[1] = 0xFC;//0xFC(十六进制),1111 1100(二进制),252(十进制)
    buf[2] = 0xAA;//0xAA(十六进制),1010 1010(二进制),170(十进制)
    buf[3] = 0x0B;//0x0B(十六进制),0000 0011(二进制),11 (十进制)
    /*
    其实只需要知道:
    0&x = 0, 1&x = x ;
    0|x = x,1|x = 1 ; 
    */

    printf("我想要将1111 1111 右移8bit:\n");
    printf("1111 1111 << 8 : %d  (1111 1111 0000 0000)\n\n", buf[0] << 8); 
    
    printf("我想让1010 1010 的最后2bit都变成00:\n");
    printf("1010 1010 & 1111 1100 : %d (1010 1000)\n\n", buf[2] & buf[1]);

    printf("我想让1010 1010 的最后2bit都变成11:\n");
    printf("1010 1010 | 0000 0011 : %d (1010 1011)\n", buf[2] | buf[3]);

    return 0;
}

wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/tftpboot$ gcc shift_and_circuit.c 
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/tftpboot$ ./a.out 
我想要将1111 1111 右移8bit:
1111 1111 << 8 : 65280  (1111 1111 0000 0000)

我想让1010 1010 的最后2bit都变成001010 1010 & 1111 1100 : 168 (1010 1000)

我想让1010 1010 的最后2bit都变成111010 1010 | 0000 0011 : 171 (1010 1011)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/383830.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

日志收集笔记(Kibana,Watcher)

1 Kibana Kibana 是一个开源的分析与可视化平台&#xff0c;可以用 Kibana 搜索、查看存放在 Elasticsearch 中的数据&#xff0c;就跟谷歌的 elasticsearch head 插件类似&#xff0c;但 Kibana 与 Elasticsearch 的交互方式是各种不同的图表、表格、地图等&#xff0c;直观的…

【python】控制台中文输出乱码解决方案

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录控制台原因解决方法方法一方法二方法三如果是os.system函数乱码控制台原因 一般的情况下&#xff0c;还是我们的源码文件的编码格式问题。我们一般是要把源码文件的编码格式改成utf-8就好了&#xff0c;但是…

zeppelin安装及hive配置

一、zeppelin安装包 链接&#xff1a;https://pan.baidu.com/s/1DVmvY2TM7WmCskejTn8dzA 提取码&#xff1a;fl7r 二、安装zeppelin 将安装包传入Centos的/opt/install目录下 # 解压 tar -zxf /opt/install/zeppelin-0.10.0-bin-all.tgz -C /opt/soft/ # 重命名 mv /opt/sof…

Nodejs环境配置 | Linux安装nvm | windows安装nvm

文章目录一. 前言二. Linux Nodejs环境配置1. 安装nvm2. 配置npm三. Windows Nodejs环境配置1. 安装nvm2. 配置npm四. nvm基本使用一. 前言 由于在实际开发中一些不同的项目需要不同的npm版本来启动&#xff0c;所以本篇文章会基于nvm这个node版本管理工具来进行Linux和Winodw…

[AI助力] 2022.3.2 考研英语学习 2011 英语二翻译

[AI助力] 2022.3.2 考研英语学习 2011 英语二翻译 文章目录[AI助力] 2022.3.2 考研英语学习 2011 英语二翻译2011年英语二翻译真题自己写的看看AI的翻译谷歌翻译New Bing&#x1f602;让AI自我评价chatgpt&#x1f923;让AI自我评价DeepL有道腾讯翻译百度翻译IDEA翻译积累&…

智能家居项目(八)之树莓派+摄像头进行人脸识别

目录 1、编辑Camera.c 2、编辑contrlDevices.h 3、编辑mainPro.c 4、进行编译&#xff1a; 5、运行结果&#xff1a; ./test1 6、项目图片演示 智能家居项目&#xff08;七&#xff09;之Libcurl库与HTTPS协议实现人脸识别_Love小羽的博客-CSDN博客 经过上一篇文章&…

redhawk:Low Power Analysis

1.rush current与switch cell 在standby状态下为了控制leakage power我们选择power gating的设计方式&#xff0c;使用power switch cell关闭block/power domain的电源。 power switch的基本介绍可见: 低功耗设计-Power Switch power switch的table中有四种状态&#xff0c;…

Simulink 自动代码生成电机控制:优化Simulink生成的代码提升代码运行效率

目录 优化需求 优化方法 从模型配置优化 优化结果对比 从算法层优化 优化结果对比 总结 优化需求 本次优化的目的是提升FOC代码执行速度&#xff0c;以普通滑模观测器为例&#xff0c;优化前把速度环控制放到2ms的周期单独运行&#xff0c;把VOFA上位机通信代码放到主循…

mongodb入门到使用(上)

mongodb的安装与使用前言一、linux下载二、mongodb配置三、 mongodb服务管理启动服务查看停止四、远程连接五、SpringBoot整合总结前言 本文主要针对一些项目的部署服务器在使用方面用到了mongodb&#xff0c;参考解决一些部署方面遇到的问题。 一、linux下载 使用wget下载 w…

代数小课堂:向量代数(通过向量夹角理解不同的维度)

文章目录 引言I 计算向量的夹角1.1 毕达哥拉斯定理1.2 余弦定理1.3 计算向量的夹角II 向量夹角的应用2.1 用计算机自动筛选简历(对人进行分类)2.2 计算机进行文本自动分类的原理引言 根据余弦定理计算两个向量的夹角向量夹角的应用: 对文本进行自动分类、自动筛选简历。如果…

【上位机入门常见问题】Visual Studio 2022安装指导

Visual Studio 2022安装指导 这里给大家指导安装Visual Studio 2022 Community版本&#xff0c;也就是我们常说的社区版&#xff0c;这个版本是微软给开发者学习技术专门定制的免费版本&#xff0c;其他的专业版和企业版都是商业收费版本。对于我们学习&#xff0c;大家使用社…

使用Docker、navicat部署和连接GaussDB

一、在CentOS7上安装Docker工具 1.卸载之前老版本的Docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \docker-engine \docker-ce 2.安装D…

TLS协议

TLS全称传输层安全协议&#xff0c;上一代是安全套接层&#xff08;SSL,不安全&#xff09;&#xff0c;用途广泛&#xff0c;最知名的是用于http&#xff0c;使http升级为https协议&#xff0c;最新版本为TLSv1.3&#xff08;推荐使用&#xff09;。TLS通过建立客户端和服务器…

Vue-router的引入和安装

什么是Vue-Router&#xff1f;Vue路由器是Vue.js的官方路由器&#xff0c;它与Vue.js核心深度集成&#xff0c;使用Vue轻松构建单页应用程序变得轻而易举。功能包括&#xff1a;嵌套路线映射动态路由模块化&#xff0c;基于组件的路由器配置路由参数&#xff0c;查询&#xff0…

常用的hive sql

细节&#xff1a;sql 中有涉及到正则匹配函数的&#xff0c;要注意转义符号 因为在不同语言下正则匹配规则是否需要加转义符号是不同的&#xff0c;举例&#xff0c;regexp_replace 函数&#xff0c;在hive sql的正则匹配规则的 \d 需要前面给它加上转义符号\&#xff0c;而在j…

RocketMQ5.0.0事务消息

目录 一、事务消息概览 二、事务消息实现机制 1. 事务消息发送流程 1)&#xff1a;发送事务消息类图 2)&#xff1a;生产端发送事务消息 3)&#xff1a;Broker存储事务消息 2. 生产者提交或回滚事务消息 1)&#xff1a;生产者发送提交或回滚事务请求 2)&#xff1a;Broker处…

【谷粒学院】微信扫码支付(224~238)

224.项目第十五天内容介绍 225.课程评论实现过程分析 226.课程支付功能需求分析 1、课程支付说明 &#xff08;1&#xff09;课程分为免费课程和付费课程&#xff0c;如果是免费课程可以直接观看&#xff0c;如果是付费观看的课程&#xff0c;用户需下单支付后才可以观看 &am…

CAD轴测图怎么画?

很多新手设计师小伙伴&#xff0c;不知道CAD轴测图怎么画&#xff1f;其实很简单&#xff0c;浩辰CAD中的超级轴测功能&#xff0c;可以方便地将CAD平面图转化为轴侧图&#xff0c;是绘制管线系统图的好帮手。今天就和小编一起来看看在浩辰CAD软件中通过调用超级轴测命令来绘制…

[数据结构]:08-顺序查找(顺序表指针实现形式)(C语言实现)

目录 前言 已完成内容 顺序查找实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-PSeqListFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容&#xff0c;除其中使用到C引用外&#xff0c;全为C语言代码。使用C引用主要是为了简化指针的使用&a…

webpack生产环境配置

3 webpack生产环境配置 由于笔记文档没有按照之前的md格式书写&#xff0c;所以排版上代码上存在问题&#x1f622;&#x1f622;&#x1f622;&#x1f622; 09 提取css成单独文件 使用下载插件 npm i mini-css-extract-plugin0.9.0 -D webpack配置此时a,b提取成单独文件,并且…