linux_驱动_iic总线获取si7006温湿度

应用层si7006.c

复制代码
#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 "head.h"

int main(int argc,char const *argv[])
{
    int tem,hum;
    float tem1,hum1;
    int fd = open("/dev/si7006",O_RDWR);
    if(fd < 0)
    {
        printf("设备文件打开失败\n");
        exit(-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("tem=%f,hum=%f\n",tem1,hum1);
        sleep(1);
    }
    return 0;
}

驱动层myiic.c

复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/device.h>
#include "head.h"

unsigned int major;
struct class *cls;
struct device *dev;
struct i2c_client *client1;

// 读取温湿度的函数
int i2c_read_hum_tem(char reg)
{
    short value;
    char r_buf[] = {reg};
    int ret;
    // 封装消息
    struct i2c_msg r_msg[] = {
        [0] = {
            .addr = client1->addr,
            .flags = 0,
            .len = sizeof(r_buf),
            .buf = r_buf,
        },
        [1] = {
            .addr = client1->addr,
            .flags = 1,
            .len = 2,
            .buf = (char *)&value,
        },
    };
    // 将消息传送
    ret = i2c_transfer(client1->adapter, r_msg, 2);
    if (ret != 2)
    {
        printk("消息传输失败\n");
        return -EIO;
    }
    return value; // 将读取到的温度和湿度返回
}

int si7006_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long si7006_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int tem, hum, ret;
    switch (cmd)
    {
    case GET_HUM: // 读取湿度
        // 读取湿度的逻辑
        hum = i2c_read_hum_tem(0XE5);
        ret = copy_to_user((void *)arg, &hum, 4);
        if (ret < 0)
        {
            printk("向用户拷贝数据失败\n");
            return ret;
        }
        break;
    case GET_TEM: // 读取温度
                  // 读取温度的逻辑
        tem = i2c_read_hum_tem(0XE3);
        ret = copy_to_user((void *)arg, &tem, 4);
        if (ret < 0)
        {
            printk("向用户拷贝数据失败\n");
            return ret;
        }
        break;
    }
    return 0;
}

int si7006_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    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;
}

// remove 和设备信息分离时执行
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 = "vivi,si7006",
    },
    {

    },
};

// 分配iic驱动对象并初始化
struct i2c_driver i2c_drv = {
    .probe = i2c_probe,
    .remove = i2c_remove,
    .driver = {
        .name = "si7006",
        .of_match_table = oftable, // 设备树匹配
    },
};
module_i2c_driver(i2c_drv);
MODULE_LICENSE("GPL");

在根节点外添加设备树

复制代码
*********添加************
在stm32mp157a-fsmp1a.dts文件的根节点外部,添加如下内容:

&i2c1 {
    pinctrl-names = "default", "sleep";//关于pinctrl的一个列表,"default"表示默认工作模式
     //"sleep"表示低功耗模式
    pinctrl-0 = <&i2c1_pins_b>;//-0表示pinctrl-name列表中第一个值default
    pinctrl-1 = <&i2c1_sleep_pins_b>;
 //在stm32mp15-pinctrl.dtsi文件中存在内核添加的各种用于管脚复用的节点,i2c1_pins_a就是其中之一

    i2c-scl-rising-time-ns = <100>;
    i2c-scl-falling-time-ns = <7>;
    status = "okay";
    /delete-property/dmas;  //删除不必要的属性
    /delete-property/dma-names;
    
    si7006@40{  //添加SI7006的从机节点
        compatible="hqyj,si7006";
        reg=<0X40>;
    };

};

效果演示

相关推荐
shjita4 小时前
centos中安装docker
linux·docker·centos
程序猿老A4 小时前
阿里云linux服务器安装mysql并实现远程访问
linux·服务器·阿里云
wuminyu4 小时前
JVM虚拟线程的底层实现原理分析
java·linux·c语言·jvm·c++
M78佐菲4 小时前
ARM学习笔记(9)
linux·arm开发·笔记·嵌入式硬件·学习
赵民勇4 小时前
glib-compile-schemas命令详解
linux·运维
小小、码农5 小时前
〖Linux文件系统〗:彻底打通文件 IO 全链路
linux·开发语言·数据结构·c++·系统
大侠归来5 小时前
cJSON 源码解析:parse_string 函数深入剖析
linux·网络·算法
小小、码农5 小时前
〖Linux进程间通信〗IPC全家桶:匿名管道、FIFO、共享内存、消息队列与信号量一篇打通
linux·运维·服务器
阳光九叶草LXGZXJ5 小时前
达梦数据库-学习-67-SSL加密认证
linux·运维·数据库·sql·学习·ssl
掉进电商坑三年没爬出来的东叔5 小时前
2026最新:青龙面板搭建全自动薅羊毛脚本,云服务器24小时挂机教程
运维·服务器·pygame