通过si7006完成对温湿度的读写,驱动代码,应用层代码如下

si7006.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include "si7006.h"
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/uaccess.h>
/*    节点信息
&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="okey";
    /delete-property/dmas;
    /delete-property/dma-names;
}


*/

struct i2c_client *cli;   //存放设备驱动和哪个总线驱动匹配成功


//用于挂载节点
struct cdev *cdev;
struct class *cls;
struct device *dev;
dev_t devno;
unsigned int count=1;   //申请使用和挂载的节点数
#if 0
    unsigned int major=0;   //动态
#else
    unsigned int major=500;//静态
#endif
unsigned int minor=0;


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


//close()
int si7006_close(struct inode *node, struct file *file)
{
    printk("%s:%s:%d",__FILE__,__func__,__LINE__);
    return 0;
}

//获取温度和湿度根据寄存器地址
unsigned short i2c_read_hum_tem(unsigned char reg)
{
    int ret;
    char r_buf[]={reg};
    unsigned short val;//数据
    //读消息结构体
    struct i2c_msg r_msg[]={
        [0]={
            .addr=cli->addr,
            .flags=0,
            .len=1,
            .buf=r_buf,
        },
        [1]={
            .addr=cli->addr,
            .flags=1,
            .len=2,
            .buf=(char*)&val,
        },

    };
    //向控制器发送读写请求并读写
    ret=i2c_transfer(cli->adapter,r_msg,ARRAY_SIZE(r_msg));
    if(ret!=ARRAY_SIZE(r_msg))
    {
        printk("i2c_transfer 读取温湿度失败\n");
        return ret;
    }
    return val;
}

long si7006_ioctl(struct file *node, unsigned int cmd, unsigned long arg)
{
    int tem,hum;
    int ret;
    switch (cmd)
    {
    case GET_TEM:
        //获取温度
        tem=i2c_read_hum_tem(0xE3);
        ret=copy_to_user((void *)arg,(void *)&tem,sizeof(int));
        if(ret)
        {
            printk("给用户拷贝数据失败\n");
            return -EINVAL;
        }
        break;

    case GET_HUM:
        //获取湿度
        hum=i2c_read_hum_tem(0xE5);
        ret=copy_to_user((void *)arg,(void *)&hum,sizeof(int));
        if(ret)
        {
            printk("给用户拷贝数据失败\n");
            return -EINVAL;
        }
        break;
    
    default:
        break;
    }
    return 0;
}
//操作方法结构体的初始化
struct file_operations fops={
    .open=si7006_open,
    .release=si7006_close,
    .unlocked_ioctl=si7006_ioctl,
};


int si7006_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret,i;

    cli=client;    
//用于挂载节点-----分步
    //申请驱动设备结构体空间
    cdev=cdev_alloc();
    if(cdev==NULL)
    {
        printk("cdev alloc memory err\n");
        
        ret = -ENOMEM;
        goto ERR1;
    }
    printk("对象分配成功\n");

    //对象的初始化
    cdev_init(cdev,&fops);

    //设备号的申请
    if(major==0)//动态申请
    {
        ret=alloc_chrdev_region(&devno,minor,count,"my_i2c");
        if(ret)
        {
            printk("动态申请设备号失败\n");
            goto ERR2;
        }
        major = MAJOR(devno);
        minor = MINOR(devno);
        printk("动态申请设备号成功\n");
    }
    else
    {
        ret=register_chrdev_region(MKDEV(major,minor),count,"my_i2c");
        if(ret)
        {
            printk("静态申请设备号失败\n");
            goto ERR2;
        }
        printk("静态申请设备号成功\n");
    }

    ret=cdev_add(cdev,MKDEV(major,minor),count);
    if(ret)
    {
        printk("字符设备驱动注册失败\n");
        goto ERR3;
    }
    printk("注册字符设备驱动成功\n");
    
    //自动创建设备节点
    cls = class_create(THIS_MODULE,"home");
    if(IS_ERR(cls))
    {
        printk("创建逻辑节点目录失败\n");
        ret=PTR_ERR(cls);
        goto ERR4;
    }
    printk("创建逻辑节点目录成功\n");

    //向上提交节点信息
    for(i=0;i<count;i++)
    {
      dev = device_create(cls,NULL,MKDEV(major,i),NULL,"si7006");
        if(IS_ERR(dev))
         {
          printk("创建逻辑节点失败\n");
          ret = PTR_ERR(dev);
          goto ERR5;
         }
    }
    printk("创建逻辑节点成功\n");
    return 0;

    ERR5:
        for(--i;i>=0;i--)
        {
            device_destroy(cls,MKDEV(major,i));
        }
        class_destroy(cls);
    ERR4:
        cdev_del(cdev);
    ERR3:
        unregister_chrdev_region(MKDEV(major,minor),count);
    ERR2:
        kfree(cdev);
    ERR1:
        return ret;
}

int si7006_remove(struct i2c_client *client)
{
     int i;
    //1.销毁设备节点
    for(i=0;i<count;i++)
    {
        device_destroy(cls,MKDEV(major,i)); 
    }
    class_destroy(cls);
    //2.注销字符设备驱动
    cdev_del(cdev);
    //3.释放设备号
    unregister_chrdev_region(MKDEV(major,minor),count);
    //4.释放动态申请的空间
    kfree(cdev);

    return 0;
}

struct of_device_id oftable[]={
    {.compatible="hqyj,si7006"},
    {},
};
MODULE_DEVICE_TABLE(of,oftable);


struct i2c_driver si7006={
    .probe=si7006_probe,
    .remove=si7006_remove,
    .driver={
        .name="hum and tem_driver",
        .of_match_table = oftable,
    },

};

module_i2c_driver(si7006);
MODULE_LICENSE("GPL");

si7006.h

#ifndef __SI7006_H__
#define __SI7006_H__


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

读取温度的主函数

#include<stdio.h>
#include<sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "si7006.h"
#include <stdlib.h>
#include <arpa/inet.h>

int main(int argc,char const *argv[])
{
    int hum,tem;
    float hum1,tem1;
    int fd=open("/dev/si7006",O_RDWR);
    if(fd<0)
    {
        perror("open err\n");
        exit(-1);
    }
    printf("打开文件成功\n");
    printf("开始读取温湿度\n");

    while (1)
    {
        ioctl(fd,GET_TEM,&tem);
        ioctl(fd,GET_HUM,&hum);

        //大小端转化
        tem=ntohs(tem);
        hum=ntohs(hum);

        tem1= 175.72*tem/65536-46.85;
        hum1= 125*hum/65536-6;
        printf("tem=%f  hum=%f\n",tem1,hum1);
        
    }
    return 0;
    

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值