首页 / 操作系统 / Linux / DS18B20 Linux驱动程序 基于AT91SAM9260
调试了很久的DS18B20驱动,前些日子出现的问题一直是读出为0 ,卡了4天之后终于解决了,之前在控制口没有加上拉电阻,后来想到可能是这个问题,加了个大电阻,果然好了~#include <linux/kernel.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <asm/uaccess.h>#include <mach/board.h>#include <mach/gpio.h>#include <linux/device.h>#define DEV_NAME "ds18b20"#define PFX "ds18b20: "#define ds18b20_MINOR 120 /*minor number of this ds18b20*//*commad*/#define SKIP_ROM 0xCC /*skip rom operation*/#define TEMP_CONVET 0x44 /*start temperature convertion*/#define READ_TEMP 0xBE /*start read temperature*/#define HIGH 1#define LOW 0static int char_major=231;unsigned char data[2];/** ds18s20_set_input:** @action: set input and pull low** @index: sensor select** @return: none*/static void ds18s20_set_input(int high){if(high){at91_set_gpio_input(AT91_PIN_PA24, HIGH);}else{at91_set_gpio_input(AT91_PIN_PA24, LOW);}}/** ds18b20_set_output:** @action: set output and clear io** @index: sensor select** @return: none*/static void ds18b20_set_output( int high){if(high){ at91_set_gpio_output(AT91_PIN_PA24, HIGH);}
if(!high){at91_set_gpio_output(AT91_PIN_PA24, LOW);}}/** ds18b20_get_io:** @action: get io value** @index: sensor select** @return: 1 for success* 0 for failure */static unsigned char ds18b20_get_io(void){unsigned char ret = 0; ret = at91_get_gpio_value(AT91_PIN_PA24);return ret;}/** ds18b20_write_byte:** @action: write byte to ds18b20 register** @b: the data value ready to write** @index: sensor select** @return: none*/static unsigned char ds18b20_write_byte(unsigned char b)//b=skip ROM operation{int i;/* // 写“1”时隙: // 保持总线在低电平1微秒到15微秒之间 // 然后再保持总线在高电平15微秒到60微秒之间 // 理想状态: 1微秒的低电平然后跳变再保持60微秒的高电平 // // 写“0”时隙: // 保持总线在低电平15微秒到60微秒之间 // 然后再保持总线在高电平1微秒到15微秒之间 // 理想状态: 60微秒的低电平然后跳变再保持1微秒的高电平 */ for(i=0;i<8;i++){ if(b&1){ds18b20_set_output(LOW);udelay(8);ds18b20_set_output(HIGH);udelay(55);}else{ds18b20_set_output(LOW);udelay(55);ds18b20_set_output(HIGH);udelay(8);}
b>>=1;}
return b; }/** ds18b20_read_byte:** @action: read data value(byte) form register** @index: sensor select** @return: data value*/static unsigned char ds18b20_read_byte(void){unsigned char i=0,byte=0;for(i=0;i<8;i++){byte>>=1;ds18b20_set_output(LOW);udelay(1);
ds18b20_set_output(HIGH);udelay(1);
ds18s20_set_input(HIGH); if(ds18b20_get_io())byte|=0x80;udelay(60);}
return byte; // 读“1”时隙: // 若总线状态保持在低电平状态1微秒到15微秒之间 // 然后跳变到高电平状态且保持在15微秒到60微秒之间 // 就认为从DS18B20读到一个“1”信号 // 理想情况: 1微秒的低电平然后跳变再保持60微秒的高电平 // // 读“0”时隙: // 若总线状态保持在低电平状态15微秒到30微秒之间 // 然后跳变到高电平状态且保持在15微秒到60微秒之间 // 就认为从DS18B20读到一个“0”信号 // 理想情况: 15微秒的低电平然后跳变再保持46微秒的高电平}/** ds18b20_reset:** @action: reset ds18b20** @index: sensor select** @return: 1 for success* 0 for failure */static int ds18b20_reset(void){ ds18b20_set_output(HIGH);ds18b20_set_output(LOW);//udelay(500);ds18b20_set_output(HIGH); ds18s20_set_input(HIGH);//set input modeudelay(15);//wait 15-60us DS18b20 will respondds18b20_get_io();//if answer is 0printk("DS18b20 respond 0
");//ds18b20_set_output(HIGH);udelay(800);
return 0;}/** ds18b20_reset:** @action: read temperature** @index: sensor select** @return: current temperature */static int ds18b20_read_temp(void){ ds18b20_reset();////ds18b20_get_io(index);
ds18b20_write_byte(SKIP_ROM); /*skip ROM operation*/ds18b20_write_byte(TEMP_CONVET); /*start temperature convertion*/
//mdelay(1);//ds18b20_set_input(index);//mdelay(1);mdelay(800);
ds18b20_reset();ds18b20_write_byte(SKIP_ROM); /*skip ROM operation*/ds18b20_write_byte(READ_TEMP); /*start read temperature*/data[0]=ds18b20_read_byte();data[1]=ds18b20_read_byte();printk("%x,%x
",data[1],data[0]);ds18b20_set_output(HIGH);return 0;}static int ds18b20_open(struct inode * s_node,struct file * s_file){return 0;}static ssize_t ds18b20_read(struct file *DS1820_file,char * buf, size_t count, loff_t * l){ds18b20_read_temp(); buf[0] = data[0];buf[1] = data[1];
return 0;}struct file_operations ds18b20_fops ={.owner = THIS_MODULE,.open=ds18b20_open, .read=ds18b20_read,};struct class *myclass ;static int __init ds18b20_init(void){int ret;ret = register_chrdev(char_major,DEV_NAME, &ds18b20_fops);myclass = class_create(THIS_MODULE,DEV_NAME);device_create(myclass, NULL, MKDEV(char_major, 0), NULL, DEV_NAME);
if(ret<0){printk(KERN_ALERT "DS18b20 REG FAIL!
");}else{printk(KERN_ALERT "MAJOR = %d
",char_major);}printk(KERN_INFO "Temperature Sensor Driver For ds18b20
");ds18b20_reset();
return ret;}static void __exit ds18b20_exit(void){unregister_chrdev(char_major,DEV_NAME);class_destroy(myclass);printk(KERN_INFO PFX "ds18b20 dirver removed
");}module_init(ds18b20_init);module_exit(ds18b20_exit);MODULE_AUTHOR("St.Dickens");MODULE_DESCRIPTION("temperature sensor driver for ds18b20");MODULE_LICENSE("Dual BSD/GPL");===================================makefile========================================# Makefile2.6ifneq ($(KERNELRELEASE),)#kbuild syntax. dependency relationshsip of files and target modules are listed here.obj-m := ds18b20.o elsePWD := $(shell pwd)KVER = 2.6.27KDIR := /home/dickens/linux-2.6.27all:$(MAKE) -C $(KDIR) M=$(PWD) modulesclean:rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versionsendif==============================随便写了个测试程序=======================================#include "stdio.h"#include "sys/types.h"#include "sys/ioctl.h"#include "stdlib.h"#include "termios.h"#include "sys/stat.h"#include "fcntl.h"#include "sys/time.h"#define DEV_NAME "/dev/ds18b20"void delay(unsigned int time){while(time>0)time--;}int main(){int fd; unsigned char buf[2]; float result;int times=5; //打开设备文件fd=open(DEV_NAME,O_RDWR | O_NDELAY | O_NOCTTY);if(fd<0){printf("Open Device Fail!
");return -1;} //读取当前设备数值else{printf("OPEND!
");}while(times>0) { read(fd, buf, 1); result = (float)buf[0]; result /= 16; result += ((float)buf[1] * 16); printf("%.1f `C
", result);times--; sleep(5); } close(fd);}