您的位置:首页 > 运维架构 > Linux

ds18b20 Linux驱动

2016-05-20 09:55 399 查看
DS18B20是常用的温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。工作电压 3.0~5.5V/DC

超低功耗静态功耗<3uA,测温范围 -55℃~+125℃,

测量结果以9~12位数字量方式串行传送。

面对着扁平的那一面,左负右正,一旦接反就会立刻发热,有可能烧毁!同时,接反也是导致该传感器总是显示85℃的原因。
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创建。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: