IIC设备驱动程序(七)————设备层驱动程序实现实例

bus-drv-dev模型及写程序
设备:at24cxx_dev.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>


static struct i2c_board_info at24cxx_info = {   
    I2C_BOARD_INFO("at24c08", 0x50),
};

static struct i2c_client *at24cxx_client;

static int at24cxx_dev_init(void)
{
    struct i2c_adapter *i2c_adap;

    i2c_adap = i2c_get_adapter(0);
    at24cxx_client = i2c_new_device(i2c_adap, &at24cxx_info);
    i2c_put_adapter(i2c_adap);

    return 0;
}

static void at24cxx_dev_exit(void)
{
    i2c_unregister_device(at24cxx_client);
}


module_init(at24cxx_dev_init);
module_exit(at24cxx_dev_exit);
MODULE_LICENSE("GPL");

驱动:at24cxx_drv.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <asm/uaccess.h>


static int major;
static struct class *class;
static struct i2c_client *at24cxx_client;

/* 传入: buf[0] : addr
 * 输出: buf[0] : data
 */
static ssize_t at24cxx_read(struct file * file, char __user *buf, size_t count, loff_t *off)
{
    unsigned char addr, data;

    copy_from_user(&addr, buf, 1);
    data = i2c_smbus_read_byte_data(at24cxx_client, addr);
    copy_to_user(buf, &data, 1);
    return 1;
}

/* buf[0] : addr
 * buf[1] : data
 */
static ssize_t at24cxx_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
{
    unsigned char ker_buf[2];
    unsigned char addr, data;

    copy_from_user(ker_buf, buf, 2);
    addr = ker_buf[0];
    data = ker_buf[1];

    printk("addr = 0x%02x, data = 0x%02x\n", addr, data);

    if (!i2c_smbus_write_byte_data(at24cxx_client, addr, data))
        return 2;
    else
        return -EIO;    
}

static struct file_operations at24cxx_fops = {
    .owner = THIS_MODULE,
    .read  = at24cxx_read,
    .write = at24cxx_write,
};

static int __devinit at24cxx_probe(struct i2c_client *client,
                  const struct i2c_device_id *id)
{
    at24cxx_client = client;

    //printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    major = register_chrdev(0, "at24cxx", &at24cxx_fops);
    class = class_create(THIS_MODULE, "at24cxx");
    device_create(class, NULL, MKDEV(major, 0), NULL, "at24cxx"); /* /dev/at24cxx */

    return 0;
}

static int __devexit at24cxx_remove(struct i2c_client *client)
{
    //printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    device_destroy(class, MKDEV(major, 0));
    class_destroy(class);
    unregister_chrdev(major, "at24cxx");

    return 0;
}

static const struct i2c_device_id at24cxx_id_table[] = {
    { "at24c08", 0 },
    {}
};


/* 1. 分配/设置i2c_driver */
static struct i2c_driver at24cxx_driver = {
    .driver = {
        .name   = "100ask",
        .owner  = THIS_MODULE,
    },
    .probe      = at24cxx_probe,
    .remove     = __devexit_p(at24cxx_remove),
    .id_table   = at24cxx_id_table,
};

static int at24cxx_drv_init(void)
{
    /* 2. 注册i2c_driver */
    i2c_add_driver(&at24cxx_driver);

    return 0;
}

static void at24cxx_drv_exit(void)
{
    i2c_del_driver(&at24cxx_driver);
}


module_init(at24cxx_drv_init);
module_exit(at24cxx_drv_exit);
MODULE_LICENSE("GPL");


测试:i2c_test.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


/* i2c_test r addr
 * i2c_test w addr val
 */

void print_usage(char *file)
{
    printf("%s r addr\n", file);
    printf("%s w addr val\n", file);
}

int main(int argc, char **argv)
{
    int fd;
    unsigned char buf[2];

    if ((argc != 3) && (argc != 4))
    {
        print_usage(argv[0]);
        return -1;
    }

    fd = open("/dev/at24cxx", O_RDWR);
    if (fd < 0)
    {
        printf("can't open /dev/at24cxx\n");
        return -1;
    }

    if (strcmp(argv[1], "r") == 0)
    {
        buf[0] = strtoul(argv[2], NULL, 0);
        read(fd, buf, 1);
        printf("data: %c, %d, 0x%2x\n", buf[0], buf[0], buf[0]);
    }
    else if ((strcmp(argv[1], "w") == 0) && (argc == 4))
    {
        buf[0] = strtoul(argv[2], NULL, 0);
        buf[1] = strtoul(argv[3], NULL, 0);
        if (write(fd, buf, 2) != 2)
            printf("write err, addr = 0x%02x, data = 0x%02x\n", buf[0], buf[1]);
    }
    else
    {
        print_usage(argv[0]);
        return -1;
    }

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这里提供一个简单的IIC驱动程序,可用于AT89C51单片机,供参考。 ```c #include <reg51.h> sbit SDA=P2^0; //SDA引脚定义 sbit SCL=P2^1; //SCL引脚定义 void IIC_Start() { SDA=1; //SDA先置高电平 SCL=1; //SCL先置高电平 SDA=0; //SDA由高电平变为低电平,发起起始信号 SCL=0; //SCL保持低电平 } void IIC_Stop() { SDA=0; //SDA先置低电平 SCL=1; //SCL先置高电平 SDA=1; //SDA由低电平变为高电平,发起停止信号 SCL=0; //SCL保持低电平 } void IIC_SendByte(unsigned char dat) { unsigned char i; for(i=0;i<8;i++) //循环8次发送8位数据 { if(dat&0x80) //从高位开始发送 SDA=1; else SDA=0; SCL=1; //SCL置高电平,数据线SDA上的数据被读取 SCL=0; //SCL置低电平 dat<<=1; //数据左移一位,准备发送下一位 } } unsigned char IIC_RecvByte() { unsigned char i; unsigned char dat=0; for(i=0;i<8;i++) //循环8次读取8位数据 { dat<<=1; //数据左移一位,准备接收下一位 SCL=1; //SCL置高电平,数据线SDA上的数据被读取 if(SDA) //如果SDA上的数据为1,则将dat的最低位设为1 dat|=0x01; SCL=0; //SCL置低电平 } return dat; } unsigned char IIC_Write(unsigned char addr,unsigned char dat) { IIC_Start(); //发起起始信号 IIC_SendByte(addr); //发送设备地址 if(IIC_RecvByte()!=0x00) //如果从设备返回的应答信号不为0x00,则说明设备没有响应,返回错误 { IIC_Stop(); return 1; } IIC_SendByte(dat); //发送数据 if(IIC_RecvByte()!=0x00) //如果从设备返回的应答信号不为0x00,则说明设备没有响应,返回错误 { IIC_Stop(); return 1; } IIC_Stop(); //发起停止信号 return 0; //写操作成功,返回0 } unsigned char IIC_Read(unsigned char addr,unsigned char *dat) { IIC_Start(); //发起起始信号 IIC_SendByte(addr); //发送设备地址 if(IIC_RecvByte()!=0x00) //如果从设备返回的应答信号不为0x00,则说明设备没有响应,返回错误 { IIC_Stop(); return 1; } *dat=IIC_RecvByte(); //读取数据 IIC_SendByte(0x00); //向从设备发送一个应答信号 IIC_Stop(); //发起停止信号 return 0; //读操作成功,返回0 } ``` 以上代码中,IIC_Start()函数用于发起起始信号,IIC_Stop()函数用于发起停止信号,IIC_SendByte()函数用于发送一个字节的数据,IIC_RecvByte()函数用于接收一个字节的数据,IIC_Write()函数用于向设备写入一个字节的数据,IIC_Read()函数用于从设备读取一个字节的数据。 需要注意的是,IIC通信需要同时控制SDA和SCL两个引脚,因此需要使用bit位来定义这两个引脚。此外,在发送和接收数据时,需要按照IIC通信协议的规定进行操作,包括先发送设备地址,再发送数据等等。如果不按照协议规定进行操作,可能会导致通信失败。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值