DS18B20 linux驱动程序 基于AT91SAM9260

    技术2022-05-19  24

    调试了很久的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);

    }

     

     


    最新回复(0)