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>;
    };

};

效果演示

相关推荐
热爱嵌入式的小许2 小时前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
韩楚风6 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学6 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO6 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu77 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我7 小时前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、7 小时前
【Linux】进程地址空间(初步了解)
linux
栎栎学编程7 小时前
Linux中环境变量
linux
我是哈哈hh7 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
郭二哈7 小时前
C++——模板进阶、继承
java·服务器·c++