Linux安全网 - Linux操作系统_Linux 命令_Linux教程_Linux黑客

会员投稿 投稿指南 本期推荐:
搜索:
您的位置: Linux安全网 > Linux编程 > » 正文

mini2440上DS18B20的驱动程序(含简单测试)

来源: sg131971 分享至:

ds18b20_drv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/device.h>

/* 相关引脚定义,方便以后移植 */
#define DQ         S3C2410_GPF(3)
#define CFG_IN     S3C2410_GPIO_INPUT
#define CFG_OUT    S3C2410_GPIO_OUTPUT

// ds18b20主次设备号(动态分配)
static int ds18b20_major = 0;
static int ds18b20_minor = 0;
static int ds18b20_nr_devs = 1;

// 定义设备类型
static struct ds18b20_device
{
    struct cdev cdev;
};

struct ds18b20_device *ds18b20_devp;    /*设备结构体指针 */

static struct class *ds18b20_class;
static struct class_device *ds18b20_class_dev;

/* 函数声明 */
static int ds18b20_open(struct inode *inode, struct file *filp);
static int ds18b20_init(void);
static void write_byte(unsigned char data);
static unsigned char read_byte(void);
static ssize_t ds18b20_read(struct file *filp, char __user * buf, size_t count, loff_t * f_pos);
void ds18b20_setup.html' target='_blank'>setup_cdev(struct ds18b20_device *dev, int index);

static int ds18b20_open(struct inode *inode, struct file *filp)
{
    int flag = 0;

    flag = ds18b20_init();
    if (flag & 0x01)
    {
        printk(KERN_WARNING "open ds18b20 failed\n");
        return -1;
    }
    printk(KERN_NOTICE "open ds18b20 successful\n");
    return 0;
}

static int ds18b20_init(void)
{
    int retval = 0;

    s3c2410_gpio_cfgpin(DQ, CFG_OUT);
    s3c2410_gpio_pullup(DQ, 0);

    s3c2410_gpio_setpin(DQ, 1);
    udelay(2);
    s3c2410_gpio_setpin(DQ, 0); // 拉低ds18b20总线,复位ds18b20
    udelay(500);                // 保持复位电平500us

    s3c2410_gpio_setpin(DQ, 1); // 释放ds18b20总线
    udelay(60);

    // 若复位成功,ds18b20发出存在脉冲(低电平,持续60~240us)
    s3c2410_gpio_cfgpin(DQ, CFG_IN);
    retval = s3c2410_gpio_getpin(DQ);

    udelay(500);
    s3c2410_gpio_cfgpin(DQ, CFG_OUT);
    s3c2410_gpio_pullup(DQ, 0);
    s3c2410_gpio_setpin(DQ, 1); // 释放总线

    return retval;
}

static void write_byte(unsigned char data)
{
    int i = 0;

    s3c2410_gpio_cfgpin(DQ, CFG_OUT);
    s3c2410_gpio_pullup(DQ, 1);

    for (i = 0; i < 8; i++)
    {
        // 总线从高拉至低电平时,就产生写时隙
        s3c2410_gpio_setpin(DQ, 1);
        udelay(2);
        s3c2410_gpio_setpin(DQ, 0);
        s3c2410_gpio_setpin(DQ, data & 0x01);
        udelay(60);
        data >>= 1;
    }
    s3c2410_gpio_setpin(DQ, 1); // 重新释放ds18b20总线
}

static unsigned char read_byte(void)
{
    int i;
    unsigned char data = 0;

    for (i = 0; i < 8; i++)
    {
        // 总线从高拉至低,只需维持低电平17ts,再把总线拉高,就产生读时隙
        s3c2410_gpio_cfgpin(DQ, CFG_OUT);
        s3c2410_gpio_pullup(DQ, 0);
        s3c2410_gpio_setpin(DQ, 1);
        udelay(2);
        s3c2410_gpio_setpin(DQ, 0);
        udelay(2);
        s3c2410_gpio_setpin(DQ, 1);
        udelay(8);
        data >>= 1;
        s3c2410_gpio_cfgpin(DQ, CFG_IN);
        if (s3c2410_gpio_getpin(DQ))
            data |= 0x80;
        udelay(50);
    }
    s3c2410_gpio_cfgpin(DQ, CFG_OUT);
    s3c2410_gpio_pullup(DQ, 0);
    s3c2410_gpio_setpin(DQ, 1); // 释放ds18b20总线
    return data;
}

static ssize_t ds18b20_read(struct file *filp, char __user * buf, size_t count, loff_t * f_pos)
{
    int flag;
    unsigned long err;
    unsigned char result[2] = { 0x00, 0x00 };
    //struct ds18b20_device *dev = filp->private_data;

    flag = ds18b20_init();
    if (flag & 0x01)
    {
        printk(KERN_WARNING "ds18b20 init failed\n");
        return -1;
    }

    write_byte(0xcc);
    write_byte(0x44);

    flag = ds18b20_init();
    if (flag & 0x01)
        return -1;

    write_byte(0xcc);
    write_byte(0xbe);

    result[0] = read_byte();    // 温度低八位
    result[1] = read_byte();    // 温度高八位

    err = copy_to_user(buf, &result, sizeof(result));
    return err ? -EFAULT : min(sizeof(result), count);
}

static struct file_operations ds18b20_dev_fops = {
    .owner = THIS_MODULE,
    .open = ds18b20_open,
    .read = ds18b20_read,
};

void ds18b20_setup_cdev(struct ds18b20_device *dev, int index)
{
    int err, devno = MKDEV(ds18b20_major, ds18b20_minor + index);

    cdev_init(&dev->cdev, &ds18b20_dev_fops);
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add(&(dev->cdev), devno, 1);
    if (err)
    {
        printk(KERN_NOTICE "ERROR %d add ds18b20\n", err);
    }
}

static int __init ds18b20_dev_init(void)
{
    int result;
    dev_t dev = 0;

    dev = MKDEV(ds18b20_major, ds18b20_minor);

    if (ds18b20_major)
    {
        result = register_chrdev_region(dev, ds18b20_nr_devs, "ds18b20");
    }
    else
    {
        result = alloc_chrdev_region(&dev, ds18b20_minor, ds18b20_nr_devs, "ds18b20");
        ds18b20_major = MAJOR(dev);
    }
    if (result < 0)
    {
        printk(KERN_WARNING "ds18b20: failed to get major\n");
        return result;
    }

    /* 为新设备分配内存和初始化 */
    ds18b20_devp = kmalloc(sizeof(struct ds18b20_device), GFP_KERNEL);
    if (!ds18b20_devp)
    {                           /*申请失败 */
        result = -ENOMEM;
        goto fail_malloc;
    }
    memset(ds18b20_devp, 0, sizeof(struct ds18b20_device));

    ds18b20_setup_cdev(ds18b20_devp, 0);

    /* 自动创建设备节点 */
    ds18b20_class = class_create(THIS_MODULE, "ds18b20_sys_class");
    if (IS_ERR(ds18b20_class))
        return PTR_ERR(ds18b20_class);

    ds18b20_class_dev =
        device_create(ds18b20_class, NULL, MKDEV(ds18b20_major, 0), NULL, "ds18b20");
    if (unlikely(IS_ERR(ds18b20_class_dev)))
        return PTR_ERR(ds18b20_class_dev);

    return 0;

  fail_malloc:
    unregister_chrdev_region(dev, 1);
    return result;
}

static void __exit ds18b20_dev_exit(void)
{
    cdev_del(&ds18b20_devp->cdev);  /*注销cdev */
    kfree(ds18b20_devp);        /*释放设备结构体内存 */
    unregister_chrdev_region(MKDEV(ds18b20_major, 0), ds18b20_nr_devs); /*释放设备号 */
    device_unregister(ds18b20_class_dev);
    class_destroy(ds18b20_class);
}

module_init(ds18b20_dev_init);
module_exit(ds18b20_dev_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("sg131971@qq.com");
app-ds18b20.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/ioctl.h>

// 函数声明
void ds18b20_delay(int i);

int main()
{
    int fd, i;
    unsigned char result[2];    // 从ds18b20读出的结果,result[0]存放低八位
    unsigned char integer_value = 0;
    float decimal_value = 0;    // 温度数值,decimal_value为小数部分的值
    float temperature = 0;

    fd = open("/dev/ds18b20", 0);
    if (fd < 0)
    {
        perror("open device failed\n");
        exit(1);
    }
    while (1)
    {
        i++;
        read(fd, &result, sizeof(result));
        integer_value = ((result[0] & 0xf0) >> 4) | ((result[1] & 0x07) << 4);
        // 精确到0.25度
        decimal_value = 0.5 * ((result[0] & 0x0f) >> 3) + 0.25 * ((result[0] & 0x07) >> 2);
        temperature = (float)integer_value + decimal_value;
        printf("Current Temperature:%6.2f\n", temperature);

        ds18b20_delay(500);
    }
}

void ds18b20_delay(int i)
{
    int j, k;
    for (j = 0; j < i; j++)
        for (k = 0; k < 50000; k++) ;
}

Makefile

ifneq ($(KERNELRELEASE),)
obj-m := ds18b20_drv.o

else
KDIR := /home/youshan/linux-2.6.32.2
MYAPP := app-ds18b20

all:
	make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
	arm-linux-gcc $(MYAPP).c -o $(MYAPP)
	
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul*
	rm -f $(MYAPP)
	
endif

运行结果:

[root@ShiGuang home]#
[root@ShiGuang home]#./app-ds18b20
open ds18b20 successful
Current Temperature: 23.50
Current Temperature: 23.50
Current Temperature: 23.25
Current Temperature: 23.50
Current Temperature: 23.50
Current Temperature: 23.50
^C
[root@ShiGuang home]#




Tags:
分享至:
最新图文资讯
1 2 3 4 5 6
验证码:点击我更换图片 理智评论文明上网,拒绝恶意谩骂 用户名:
关于我们 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 发展历史