59 linux i2c设备驱动之dht12驱动

来源:互联网 发布:java字符串比较大小 编辑:程序博客网 时间:2024/06/14 07:23

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 1typedef 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");