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  0

static 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 mode

udelay(15);//wait 15-60us DS18b20 will respond

ds18b20_get_io();//if answer is 0

printk("DS18b20 respond 0\n");

//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  \n",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!\n");

}

else

{

printk(KERN_ALERT "MAJOR = %d\n",char_major);

}

printk(KERN_INFO "Temperature Sensor Driver For ds18b20\n");

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\n");

}

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.6

ifneq ($(KERNELRELEASE),)

#kbuild syntax. dependency relationshsip of files and target modules are listed here.

obj-m := ds18b20.o

else

PWD  := $(shell pwd)

KVER = 2.6.27

KDIR := /home/dickens/linux-2.6.27

all:

$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:

rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions

endif

==============================随便写了个测试程序=======================================

#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!\n");

return -1;

}

        //读取当前设备数值

else

{

printf("OPEND!\n");

}

while(times>0)

        {

            read(fd, buf, 1);

            result = (float)buf[0];

            result /= 16;

            result += ((float)buf[1] * 16);

            printf("%.1f `C\r\n", result);

times--;

            sleep(5);

        }

        close(fd);

}