59 linux i2c设备驱动之dht12驱动

dth12的工作模式除了单总线外,还可以使用i2c接口的工作模式.
dht12的引脚说明
这里写图片描述

//
这里写图片描述
上图说明dht12芯片内部有5个寄存器,寄存器地址从0x00 ~ 0x04, 分别存放湿度数据,温度数据,校验和
同时需要特别注意:上面说dht12的设备地址为0xB8, 此地址已是包含读写位了,通常设备址地址只是7位的. 所以dht12的i2c设备地址为0x5c.

///
这里写图片描述
绿色的点为开始信号,红色的点为停止信号.

时序说明: 首先控制器发出开始信号, 接着发出0xB8(设备地址和读写位的写模式组成), 收到从机的应答信号后,再发出数据0(表示从地址为0x00的寄存器开始读),收到应答信号后,再接着重新发出开始信号, 应答后,再发出0xB9(设备地址和读组成), 收到应答后,接收从机发回的5上字节数据.最后发出停止信号.

//
在linux内核里声明dht12设备,  设备名为”mydht12”, 设备地址为0x5c.

dht12的简单设备驱动:
test.c


#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>

int myprobe(struct i2c_client *cli, const struct i2c_device_id *id)
{
    struct i2c_msg msg[2];
    char addr = 0, data[5], i;
//按dht12的读时序要求, 只需调用i2c_transfer函数一次, 和发出两条消息.
    printk("in myprobe ...%s, %x\n", id->name, id->driver_data);

    msg[0].addr = cli->addr;
    msg[0].flags = 0;
    msg[0].len = 1;
    msg[0].buf = &addr; //指定从地址为0x00的寄存器开始读

    msg[1].addr = cli->addr;
    msg[1].flags = I2C_M_RD; //读
    msg[1].len = 5; //共接收5字节数据
    msg[1].buf = data;

    if (i2c_transfer(cli->adapter,  msg, 2) < 0)
        return -ENODEV;

    for (i = 0; i < 5; i++)
        printk("%d  ", data[i]);

    printk("\n");
    return 0;
}

int myremove(struct i2c_client *cli)
{
    printk("in myremove ...\n");
    return 0;
}

struct i2c_device_id ids[] = {
    {"mydht12", 0x22},
    {},
};

struct i2c_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,

    .driver = {
        .name = "mydrv",
        .owner = THIS_MODULE,
    },

    .id_table = ids,
};

module_i2c_driver(mydrv);
MODULE_LICENSE("GPL");

/
加入字符设备接口的设备驱动代码:
test.c


#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/device.h>

#define MYMA  1314
#define COUNT 1

typedef struct {
    struct mutex mutex;
    struct cdev  cdev;
    struct i2c_client *cli; 
    struct class *cls;
}dht12_data_t;


ssize_t myread(struct file *fl, char __user *buf, size_t len, loff_t *off)
{
    struct cdev *cdev = fl->f_path.dentry->d_inode->i_cdev;
    dht12_data_t *data = container_of(cdev, dht12_data_t, cdev);
    int ret, sum, i;
    struct i2c_msg msgs[2];
    char data_rcv[5], addr = 0;
    struct i2c_client *cli = data->cli;

    //上锁,防止重入
    mutex_lock(&data->mutex);

    msgs[0].addr = cli->addr;
    msgs[0].flags = 0;
    msgs[0].len = 1;
    msgs[0].buf = &addr;

    msgs[1].addr = cli->addr;
    msgs[1].flags = I2C_M_RD;
    msgs[1].len = 5;
    msgs[1].buf = data_rcv;

    ret = i2c_transfer(cli->adapter, msgs, 2);
    if (ret != 2)
        goto out;

    //检查校验和
    sum = 0;
    for (i = 0; i < 4; i++)
        sum += data_rcv[i];
    if (sum != data_rcv[4])
    {
        ret = -EINVAL;
        goto out;
    }

    sprintf(buf, "humi: %d.%d ;  temp: %d.%d\n", data_rcv[0], data_rcv[1], data_rcv[2], data_rcv[3]);
    ret = strlen(buf);

out:
    mutex_unlock(&data->mutex);
    return ret;
}

struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = myread,
};

int myprobe(struct i2c_client *cli, const struct i2c_device_id *id)
{
    static int mi = 0; //记录次设备号
    dht12_data_t *data;
    dev_t devid;
    int ret;

    //注册设备号
    devid = MKDEV(MYMA, mi);
    ret = register_chrdev_region(devid, COUNT, cli->name);
    if (ret < 0)
        goto err0; 

    //准备每个匹配设备的数据
    data = kzalloc(sizeof(*data), GFP_KERNEL);
    if (NULL == data)
    {
        ret = -ENOMEM;
        goto err1;
    }

    //字符设备初始化
    cdev_init(&data->cdev, &fops);
    data->cdev.owner = THIS_MODULE;
    ret = cdev_add(&data->cdev, devid, COUNT);
    if (ret < 0)
        goto err2;

    //初始化互斥锁
    mutex_init(&data->mutex);   

    //创建设备文件
    data->cls = class_create(THIS_MODULE, cli->name);
    device_create(data->cls, NULL, devid, NULL, "%s.%d", cli->name, mi++);
    data->cli = cli;

    i2c_set_clientdata(cli, data); //dev_set_drvdata(&cli->dev, data);
    return 0;
err2:
    kfree(data);
err1:
    unregister_chrdev_region(devid, COUNT);
err0:
    return ret;
}

int myremove(struct i2c_client *cli)
{
    dht12_data_t *data = i2c_get_clientdata(cli); //dev_get_drvdata(&cli->dev);

    //移除设备文件
    device_destroy(data->cls, data->cdev.dev);
    class_destroy(data->cls);

    cdev_del(&data->cdev);
    unregister_chrdev_region(data->cdev.dev, COUNT);
    kfree(data);
    return 0;
}


struct i2c_device_id ids[] = {
    {"mykkk", 0x11},
    {"mydht12", 0x22},
    {},
};

struct i2c_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,

    .driver = {
        .name = "mydrv",
        .owner = THIS_MODULE,
    },

    .id_table = ids,
};


module_i2c_driver(mydrv);
MODULE_LICENSE("GPL");
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值