DS18B20是常用的温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。工作电压 3.0~5.5V/DC
超低功耗静态功耗<3uA,测温范围 -55℃~+125℃,
测量结果以9~12位数字量方式串行传送。
面对着扁平的那一面,左负右正,一旦接反就会立刻发热,有可能烧毁!同时,接反也是导致该传感器总是显示85℃的原因。

DS18B20实物图
DS18B20实物图

DS18B20电路如图如下
DS18B20电路如图如下

驱动代码如下

DS18B20_driver.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>

#include <asm/uaccess.h>  //其中copy_to*在其中

#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>


/*基于友善之臂smart210开发板,DS18B20数据引脚GPH2(0),位于开发板左上角GPIO,第二排排针倒数第五引脚*/
spinlock_t lock;  //不用也行
unsigned int tmp_wendu ;

#define DEVICE_NAME "DS18B20"
#define NODE_NAME "DS18B20"
//********************************
//功能:设置引脚为输入功能
//********************************
void set_con_in(void)
{
    s3c_gpio_cfgpin(S5PV210_GPH2(0), S3C_GPIO_INPUT);
    //gpio_set_value(S5PV210_GPH2(0), 1);    
}
//********************************
//功能:设置引脚为输出功能
//********************************
void set_con_out(void)
{
    s3c_gpio_cfgpin(S5PV210_GPH2(0), S3C_GPIO_OUTPUT);
}
//********************************
//功能:引脚输出高或低电平功能,i=1(高)
//********************************
void set_output_data(int i)
{
    if (i == 0) {
        gpio_set_value(S5PV210_GPH2(0), 0);    
    }    else if(i == 1) {
        gpio_set_value(S5PV210_GPH2(0), 1);    
    }
}
//********************************
//功能:ds18b20复位
//********************************
int init_DS18B20(void)
{
    int result = 10;
    set_con_out();
    __udelay(3);    //短时间延迟
    set_output_data(1);
    __udelay(3);    //短时间延迟
    set_output_data(0);
    __udelay(550); //480-960us
    set_output_data(1);
    __udelay(20); //15-60us,最好大于15us
    set_con_in();
    __udelay(100); //60-240us, ds18b20回应值保持时间
    result = gpio_get_value(S5PV210_GPH2(0));
    printk("init_DS18B20--result:%d\n", result);

    set_con_out();
    __udelay(3);
    set_output_data(1);
    //__udelay(300);

    return result;

}

//*************************************
//功能:从ds18b20读一个字节的数据
//*************************************
unsigned char read_one_char(void)
{
    unsigned char i = 0;
    unsigned char dat = 0;
    unsigned char temp = 0;

    spin_lock(&lock);

    for(i=0; i<8; i++) {
        set_con_out();
        __udelay(3);
        set_output_data(1);
        dat >>= 1;
        set_output_data(0); //该行与下行等效该行上面的4行
        __udelay(18);  //按时序来延时,不能太小或太大

        set_con_in();
        __udelay(1);
        temp = gpio_get_value(S5PV210_GPH2(0)) & 0x01;
        if (temp)
            dat |= 0x80;
        else 
            dat |= 0x00;

        printk("read_one_char--temp: %d\n", temp);
        __udelay(65);    

    }
    spin_unlock(&lock);
    printk("read_one_char--dat: %d\n", dat);

    return dat;

}

//*************************************
//功能:向ds18b20写一个字节的数据
//*************************************
void write_one_char(unsigned char dat)
{
    //printk("write_one_char--dat: %d\n", dat);
    unsigned char i = 0;

    spin_lock(&lock);
    set_con_out();

    for(i=0; i<8; i++) {

        set_output_data(1);
        __udelay(1);

        set_output_data(0);
        __udelay(5);    
        set_output_data(dat & 0x01); 
        __udelay(55);
        set_output_data(1);
        __udelay(2);
        dat >>= 1;    
    }
    spin_unlock(&lock);
    __udelay(30);
}

//********************************
//功能:读取ds18b20的温度
//********************************
unsigned int read_wendu(void)
{
    unsigned char dat_L = 0, dat_H = 0;
    unsigned int wendu_value;
    int ds18b20_back_value;


    ds18b20_back_value  = init_DS18B20();

    if (ds18b20_back_value)
        printk("ds18b20 init error!!!\n");
    else 
        printk("ds18b20_back_value %d\n", ds18b20_back_value);
    write_one_char(0xCC);
    write_one_char(0x44);

    if (init_DS18B20())
        printk("ds18b20 init error!!!\n");
    else 
        printk("ds18b20 init ok \n");
    write_one_char(0xcc);
    write_one_char(0xBE);

    dat_L = read_one_char();
    dat_H = read_one_char();

    if((dat_H & 0xf8) != 0x00) {
        dat_L = (~dat_L) + 1;

        if (dat_L > 255)
            dat_H = (~dat_H) + 1;
    }
    wendu_value = (dat_H * 16 + dat_L/16) * 10 +((dat_L%16)*10/16);

    printk("read_wendu--dat_L: %d    dat_H: %d    wendu: %d.%d\n",dat_L, dat_H, \
        wendu_value/10, wendu_value%10);

    return(wendu_value);
}

static int ds18b20_open(struct inode *inode, struct file *filp)
{
    printk (KERN_INFO "Device opened\n");
    spin_lock_init(&lock);
    return 0;
}

 /*读取数据*/
static int ds18b20_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
{
    unsigned int wendu_value = 0;
    int res = 0;
    wendu_value = read_wendu();

    if (wendu_value>2000)
    {
        wendu_value = tmp_wendu;
    }
    tmp_wendu = wendu_value;
    printk("wendu_valu is %d\n", wendu_value); 
    res=copy_to_user(buffer, &wendu_value, sizeof(wendu_value));
    if (res < 0)
    {
        printk("copy_to_user error! ");
    }
    printk("copy_to_user len! %d\n ", res);
    return 0;   
}
/*写命令,在此置空*/
static int ds18b20_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
    return 0;
}

static int ds18b20_release(struct inode *inode,struct file *filp)
{
    printk (KERN_INFO "device closed\n");
    return 0;
}

static long ds18b20_ioctl(struct file *filp, unsigned int cmd,
        unsigned long arg)
{
    return 0;
}

static struct file_operations ds18b20_fops = {
    .owner  = THIS_MODULE,
    .open   =    ds18b20_open,
    .read   = ds18b20_read,
    .write  = ds18b20_write,
    .unlocked_ioctl    = ds18b20_ioctl,
    .release = ds18b20_release,
};

static struct miscdevice ds18b20_dev = {
    .minor            = MISC_DYNAMIC_MINOR,
    .name            = DEVICE_NAME,
    .nodename        = NODE_NAME,
    .fops            = &ds18b20_fops,
};

static int __init ds18b20_dev_init(void) {
    int ret;

    ret = gpio_request(S5PV210_GPH2(0), "DS18B20");
    if (ret) {
        printk("%s: request GPIO %d for GPE0 failed, ret = %d\n", DEVICE_NAME,
            S5PV210_GPH2(0), ret);
        return ret;

        s3c_gpio_cfgpin(S5PV210_GPH2(0), S3C_GPIO_OUTPUT);
        gpio_set_value(S5PV210_GPH2(0), 1);
    }

    ret = misc_register(&ds18b20_dev);//注册杂设备驱动

    printk(DEVICE_NAME"\tinitialized\n");

    return ret;
}

static void __exit ds18b20_dev_exit(void) {
    int i;

    for (i = 0; i < 1; i++) {
        gpio_free(S5PV210_GPH2(0));
    }

    misc_deregister(&ds18b20_dev);
}

module_init(ds18b20_dev_init);
module_exit(ds18b20_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("GaoZhe.");

Makefile

ifneq ($(KERNELRELEASE),)
obj-m := DS18B20_driver.o
else
PWD := $(shell pwd)
KDIR:= /home/bishe/kernel/linux-3.0.8
all:
    make -C $(KDIR) M=$(PWD)
clean:  
    rm -rf *.o *.order *.ko *.mod.c *.symvers *.c~ *~
endif

应用程序如下

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>

int main(int argc, char *argv[])
{
    int fd, i;
    char *buf;
    unsigned int a=0;
    fd = open("/dev/DS18B20", O_RDWR);
    if(-1 == fd)
        {
        perror("open file error\r\n");
        exit(-1);
        }
        printf("open /dev/DS18B20 success!\n");
    while(1)
        {
        int i=read(fd,&a,5);
        if(i<0)
        {
            printf("read tempture is error!\n");
        }   
    printf("test_temptureis:%d.%d\n",a/10,a%10); 
        sleep(1);
        }
    close(fd);
    return 0;
}

在这里用的是misc杂项设备的,#make之后,会生成DS18B20_driver.ko,然后#insmod DS18B20_driver.ko加载模块,执行#cat /proc/devices 发现并没有DS18B20这个驱动模块啊,而多了一个主设备号为10的misc,同时,#ls /dev 会发现自动生成了DS18B20设备文件,为什么呢?因为misc杂项设备驱动共用一个主设备号,区分不同设备的依据是次设备号,这里共用的是主设备号是10,次设备号是系统自动分配的。当#insmod后,系统会自动在/dev目录下创建设备文件,不需要手动mknod创建。

Logo

更多推荐