Linux内核:Linux3.0.8
硬件:友善之臂smart210开发板,A8内核
编译器:arm-linux-gcc 4.5.1
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.oelsePWD := $(shell pwd)KDIR:= /home/bishe/kernel/linux-3.0.8all: 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创建。
联系客服