【IIC子系统之读取温湿度】

news2024/11/15 23:54:10

IIC子系统之读取温湿度

  • IIC总线协议
    • 主机读取一个字节
    • 主机发送一个字节
  • 设备树编写
  • IIC设备驱动层API
  • 编写程序读取温湿度
    • 应用层
    • 驱动
      • 读取温湿度函数解析
    • 头文件

IIC总线协议

1.I2C总线是PHLIPS公司在八十年代初推出的一种串行的半双工同步总线,主要用于连接整体电路。
1)同一个板子两个芯片之间的通信,使用IIC总线 SOC(stm32mp157aaa) <-----IIC----->温湿度传感器si7006
2)同一个板子两个设备之间的通信,使用UART总线 PC<-----UART----->Target
2.I2C总线为两线制,只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL
3.I2C硬件结构简单,接口连接方便,成本较低。因此在各个领域得到了广泛的应用
4.IIC总线传输速率
低速:100k
中速:400k
高速:3.4M
5.iic总线需要外接两个上拉电阻,这两个上拉电阻的作用:在IIC总线处于空闲状态时,是高电平状态。

主机读取一个字节

在这里插入图片描述

主机发送一个字节

在这里插入图片描述

设备树编写

&i2c1 {
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&i2c1_pins_b>;
    pinctrl-1 = <&i2c1_sleep_pins_b>;
    i2c-scl-rising-time-ns = <100>;
    i2c-scl-falling-time-ns = <7>;
    status = "okay";
    /delete-property/dmas;
    /delete-property/dma-names;

    si7006@40 {
        compatible = "hqyj,si7006";
        reg = <0x40>;        
    }
};

这是一个 I2C 设备在设备树中的描述,其中包含一个名为 &i2c1 的 I2C 控制器节点和一个名为 si7006@40 的子节点。

以下是每个属性的解释:

pinctrl-names:定义了该节点使用的引脚控制器名称,本例中定义了两个控制器,分别为默认和睡眠模式。
pinctrl-0 和 pinctrl-1:定义了节点在两种不同模式下使用的引脚配置。
i2c-scl-rising-time-ns 和 i2c-scl-falling-time-ns:定义了时序参数,用于在 I2C 通信过程中控制时钟线的上升和下降时间。
status:指示该节点当前状态,“okay” 表示该节点被启用。
/delete-property/dmas 和 /delete-property/dma-names:从节点中删除了 dmas 和 dma-names 属性。
子节点 si7006@40 的属性如下:

compatible:表示该设备与哪种驱动程序兼容,本例中为 “hqyj,si7006”。
reg:设备地址,本例中为 0x40。

IIC设备驱动层API

#include<linux/i2c.h>
1.对象结构体
struct i2c_driver {
    //与设备匹配成功执行
    int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
    //设备分离时执行
    int (*remove)(struct i2c_client *client);
    //设置名字匹配和设备树匹配
    struct device_driver driver;
    //设置id_table匹配
    const struct i2c_device_id *id_table;
};
struct device_driver {
    const char      *name;
    const struct of_device_id  *of_match_table;
    };
2.给对象分配空间并且初始化
int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    return 0;
}
int i2c_remove(struct i2c_client *client)
{
    return 0;
}
struct i2c_driver i2c_drv={
    .probe=i2c_probe,
    .remove=i2c_remove,
    .driver={
        .name="si7006",
        .of_match_table=设备树匹配表名,   
    },
};
3.注册
  #define i2c_add_driver(struct i2c_driver *driver) \
    i2c_register_driver(THIS_MODULE, driver)
4.注销
    void i2c_del_driver(struct i2c_driver *driver)
5.一键注册宏
#define module_i2c_driver(__i2c_driver) \
    module_driver(__i2c_driver, i2c_add_driver, \
            i2c_del_driver)
#define module_driver(__driver, __register, __unregister, ...) \
    static int __init __driver##_init(void) \
    { \
        return __register(&(__driver) , ##__VA_ARGS__); \
    } \
    module_init(__driver##_init); \
    static void __exit __driver##_exit(void) \
    { \
        __unregister(&(__driver) , ##__VA_ARGS__); \
    } \
    module_exit(__driver##_exit);

编写程序读取温湿度

应用层

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include<string.h>
#include <sys/ioctl.h>  
#include <arpa/inet.h>
#include"iic.h"
int main(int argc, const char *argv[])
{
    int tem, hum;
    float tem1, hum1;
    int fd = open("/dev/si7006", O_RDWR);
    if (fd < 0)
    {
        printf("设备文件打开失败\n");
        return -1;
    }
    while (1)
    {
        ioctl(fd, GET_HUM, &hum);
        ioctl(fd, GET_TEM, &tem);
        // 大小端转换
        hum = ntohs(hum);
        tem = ntohs(tem);
        hum1 = 125.0 * hum / 65536 - 6;
        tem1 = 175.72 * tem / 65536 - 46.85;
        printf("温度:%lf   湿度: %lf \n", tem1, hum1);
        sleep(1);
    }

    return 0;
}

驱动

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include "iic.h"

int major;
struct class *cls;
struct device *dev;
struct i2c_client *client1;
int i2c_read_hum_tem(unsigned char reg)
{
    int ret;
    char r_buf[] = {reg};
    short value;
    struct i2c_msg r_msg[] =
        {
            [0] = {
                .addr = client1->addr,
                .flags = 0,
                .len = 1,
                .buf = r_buf,
            },
            [1] = {
                .addr = client1->addr,
                .flags = 1,
                .len = 2,
                .buf = (char *)&value,
            },
        };
    ret = i2c_transfer(client1->adapter, r_msg, ARRAY_SIZE(r_msg));
    if (ret != ARRAY_SIZE(r_msg))
    {
        printk("消息传送失败\n");
        return ret;
    }
    return value;
}

int si7006_open(struct inode *inode, struct file *file)
{
    return 0;
}
long si7006_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int hum, tem;
    int ret;
    switch (cmd)
    {
    case GET_HUM:
        hum = i2c_read_hum_tem(0xe5);
        ret = copy_to_user((void *)arg, &hum, sizeof(int));
        if (ret)
        {
            printk("copy to user err\n");
            return -1;
        }
        break;
    case GET_TEM:
        tem = i2c_read_hum_tem(0xe3);
        ret = copy_to_user((void *)arg, &tem, sizeof(int));
        if (ret)
        {
            printk("copy to user err\n");
            return -1;
        }
        break;
    }
    return 0;
}
int si7006_close(struct inode *inode, struct file *file)
{
    return 0;
}

struct file_operations fops = {
    .open = si7006_open,
    .unlocked_ioctl = si7006_ioctl,
    .release = si7006_close,
};

int i2c_probe(struct i2c_client * client, const struct i2c_device_id *id)
{
    client1 = client;
    major = register_chrdev(0, "si7006", &fops);
    if (major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功\n");
    cls = class_create(THIS_MODULE, "si7006");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        return PTR_ERR(cls);
    }
    printk("向上提交目录成功\n");
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "si7006");
    if (IS_ERR(dev))
    {
        printk("向上提交设备失败\n");
        return PTR_ERR(dev);
    }
    printk("向上提交设备成功\n");
    return 0;
}
int i2c_remove(struct i2c_client *client)
{
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    unregister_chrdev(major, "si7006");
    return 0;
}

struct of_device_id oftable[] = {
    {
        .compatible = "hqyj,si7006",
    },
    {},
};
struct i2c_driver i2c_drv = {
    .probe = i2c_probe,
    .remove = i2c_remove,
    .driver = {
        .name = "si7006",
        .of_match_table = oftable,
    },
};
MODULE_DEVICE_TABLE(of, oftable);
module_i2c_driver(i2c_drv);
MODULE_LICENSE("GPL");

读取温湿度函数解析

int i2c_read_hum_tem(unsigned char reg)
{
    int ret;
    char r_buf[] = {reg};
    short value;

定义了一个名为 i2c_read_hum_tem 的函数,该函数接受一个 unsigned char 类型的参数 reg,表示要读取的寄存器地址。r_buf 是一个 char 类型的数组,用于存储要读取的寄存器地址。value 是一个 short 类型的变量,用于存储读取到的温湿度数据。

struct i2c_msg r_msg[] =
    {
        [0] = {
            .addr = client1->addr,
            .flags = 0,
            .len = 1,
            .buf = r_buf,
        },
        [1] = {
            .addr = client1->addr,
            .flags = 1,
            .len = 2,
            .buf = (char *)&value,
        },
    };

定义了一个名为 r_msg 的结构体数组,用于定义 I2C 传输中的读操作。该结构体数组包含两个元素,其中第一个元素是写操作,用于向设备发送要读取的寄存器地址,第二个元素是读操作,用于从设备中读取温湿度数据。client1->addr 表示要访问的 I2C 设备的地址,.flags 表示传输标志位,0 表示写操作,1 表示读操作,.len 表示数据长度,buf 表示数据缓冲区。

ret = i2c_transfer(client1->adapter, r_msg, ARRAY_SIZE(r_msg));
if (ret != ARRAY_SIZE(r_msg))
{
    printk("消息传送失败\n");
    return ret;
}

使用 i2c_transfer 函数将读写操作传输到 I2C 总线上,client1->adapter 表示要使用的 I2C 总线控制器。如果传输失败,将会输出一条错误信息并返回传输结果。如果传输成功,则返回读取到的温湿度数据。

    return value;
}

返回读取到的温湿度数据。

头文件

#ifndef __IIC_H__
#define __IIC_H__
#define GET_HUM _IOR('m',1,int)
#define GET_TEM _IOR('m',0,int)

#endif

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

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

相关文章

面试准备知识点与总结——(基础篇)

目录Java基础Java面向对象有哪些特征ArrayList和LinkedList有什么区别高并发的集合有哪些问题迭代器的fail-fast和fail-safeArrayList底层扩容机制HashMap面试合集解答设计模式单例设计模式哪些地方体现了单例模式Java基础 Java面向对象有哪些特征 Java面向对象有三大特征&am…

Win10显示dds及tga缩略图

整理之前做游戏MOD时收集的模型资源,3D游戏模型的贴图文件格式基本都是dds或tga的,毕竟无损压缩、支持嵌入MipMap、带透明通道、可以被GPU硬解balabala...道理我都懂但这俩玩意系统根本直接查看不了,就算装上专门的看图软件或插件,文件夹视图下也没有缩略图预览,只能一个个点开…

SQL查询的优化:如何调整SQL查询的性能

查询优化是在合理利用系统资源和性能指标的基础上&#xff0c;定义最有效、最优化的方式和技术&#xff0c;以提高查询性能的过程。查询调整的目的是找到一种方法来减少查询的响应时间&#xff0c;防止资源的过度消耗&#xff0c;并识别不良的查询性能。 在查询优化的背景下&a…

CF1795D Triangle Coloring (组合数学)

链接 题意&#xff1a; 给定一个 n 个点 n 条边的图 &#xff0c;n 为 6 的倍数&#xff0c;每条边都有边权。 这个图是由 n/3 个三元环构成的 [1,2,3],[4,5,6],[7,8,9],[10,11,12]...... 一个 n12 的图长成这个&#xff08;唯一&#xff09;&#xff1a; 现在你需要给图染上红…

厂商推送限制说明及极光的适配方案

背景 自2023年起&#xff0c;各个厂商逐步对营销类消息做数量管控&#xff0c;具体如下&#xff1a; 华为 自2023年1月5日起&#xff0c;华为PUSH通道将根据应用类型对资讯营销类消息的每日推送数量进行上限管理&#xff0c;服务与通讯类消息每日推送数量不受限制。详情请参考推…

使用MMDetection进行目标检测、实例和全景分割

MMDetection 是一个基于 PyTorch 的目标检测开源工具箱&#xff0c;它是 OpenMMLab 项目的一部分。包含以下主要特性&#xff1a; 支持三个任务 目标检测&#xff08;Object Detection&#xff09;是指分类并定位图片中物体的任务实例分割&#xff08;Instance Segmentation&a…

服务间调用方式 OpenFeign 的介绍和使用

文章目录前言1、 RestTemplate1.1、通用方法 exchange1.2、RestTemplate 和 OpenFeign 的区别2、RPC 和 HTTP2.1、RPC 是什么2.2、RPC 调用过程示意图2.3、HTTP 是什么2.4、HTTP 调用过程示意图2.5、对比3 、OpenFeign3.1 、OpenFeign 常用注解3.2 、案例前言 Feign 停更了&am…

空间复杂度与时间复杂度

1、时间复杂度和空间复杂度 &#xff08;1&#xff09;时间复杂度、空间复杂度是什么&#xff1f; 算法效率分析分为两种&#xff1a;第一种是时间效率&#xff0c;第二种是空间效率。时间效率被称为时间复杂度&#xff0c;空间效率被称作空间复杂度时间复杂度主要衡量的是一…

Python空间分析| 02 利用Python计算空间局部自相关(LISA)

局部空间自相关 import esda import numpy as np import pandas as pd import libpysal as lps import geopandas as gpd import contextily as ctx import matplotlib.pyplot as plt from geopandas import GeoDataFrame from shapely.geometry import Point from pylab im…

LeetCode 1139. 最大的以 1 为边界的正方形

原题链接 难度&#xff1a;middle\color{orange}{middle}middle 2023/2/17 每日一题 题目描述 给你一个由若干 000 和 111 组成的二维网格 gridgridgrid&#xff0c;请你找出边界全部由 111 组成的最大 正方形 子网格&#xff0c;并返回该子网格中的元素数量。如果不存在&am…

Transformer论文阅读:ViT算法笔记

标题&#xff1a;An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale 会议&#xff1a;ICLR2021 论文地址&#xff1a;https://openreview.net/forum?idYicbFdNTTy 文章目录Abstract1 Introduction2 Related Work3 Method3.1 Vision Transformer3.2…

【已解决】关于 luckysheet 设置纯文本,解决日期格式回显错误的办法

目录 一、现象 二、分析 三、思考过程 五、解决 六、参考链接 一、现象 在excel里面输入内容&#xff0c;如 2023-2-17 12:00 保存后&#xff0c;传回后端的数据被转化成了 数值类型&#xff0c;这显然是一种困扰。 如图所示 二、分析 查阅了文档和一些博客发现 Lucky…

2023美赛ICM F题 详细思路

对于本次美赛F题来说&#xff0c;核心之处就是综合评价模型&#xff0c;但考察我们这个模型的角度较以往常规的制定指标&#xff0c;计算得分给出排名然后分析结果这一套常规流程不同&#xff0c;这次美赛F题出题更贴合实际&#xff0c;整体聚焦在“制定完一个新指标后会带来的…

2019蓝桥杯真题数列求值(填空题) C语言/C++

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 给定数列 1,1,1,3,5,9,17,⋯&#xff0c;从第 4 项开始&#xff0c;每项都是前 3 项的和。 求第 20190324 项的最后 4 位数字。 运行限制 最大运行时间&#xff1a…

三分钟学会用Vim

Vim知识点 目录Vim知识点一&#xff1a;什么是vim二&#xff1a;vim常用的三种模式三&#xff1a;vim的基本操作一&#xff1a;什么是vim vim最小集 vim是一款多模式的编辑器—各种模式—每种模式的用法有差别—每种模式之间可以互相切换 但是我们最常用的就是3~5个模式 vi…

更换ssl证书

更换ssl证书常用证书查看以及转换网址阿里云判断流量以及配置证书判断接入点阿里云控制台配置证书WAFAzure判断流量以及配置证书&#xff1a;判断接入点Azure配置证书CDNAPP GateWay常用证书查看以及转换网址 https://www.chinassl.net/ssltools/convert-ssl.htmlhttps://myss…

【java 高并发编程之JUC】高阶JUC特性总结

1 线程中断机制 1.1 什么是中断&#xff1f; 首先 一个线程不应该由其他线程来强制中断或停止&#xff0c;而是应该由线程自己自行停止。所以&#xff0c;Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。 其次 在Java中没有办法立即停止一条线程&#xff0c;然…

TCP简单说明

前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开启了学习机器学习&#xff0c;本文就介绍了机器学习的基础内容。 提示&#xff1a;以下是本篇文…

基于深度学习的个性化推荐系统实时化改造与升级

省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库【免费下载】2023年1月份热门报告合集ChatGPT的发展历程、原理、技术架构及未来方向《ChatGPT&#xff1a;真格基金分享.pdf》2023年AIGC发展趋势报告&#xff1a;人工智能的下一时代2023年…

ChatGPT初体验step by step:ChatGPT解决人类提出的数理逻辑问题,Python编程实践

ChatGPT初体验step by step&#xff1a;ChatGPT解决人类提出的数理逻辑问题&#xff0c;Python编程实践 如果已有有效的open ai的api key&#xff0c;则跳过本文&#xff08;1&#xff09;&#xff08;2&#xff09;&#xff08;3&#xff09;&#xff08;4&#xff09;&#x…