{嵌入式}之DS18B20

转载1  http://blog.chinaunix.net/uid-24515821-id-2129103.html

友善之臂Tiny6410 开发板下的DS18B20驱动程序,参考了http://hi.baidu.com/ppln/blog/item/7e3991f57c308067dcc47476.html的代码,在此表示感谢。

//驱动程序
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>

#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <mach/s3c6410.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <plat/cpu.h>
#include <plat/devs.h>

#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-l.h>

#define DEVICE_NAME     "Digital Thermometer DS18B20"

static char data[2];

static int reset(void)
{
    gpio_direction_output(S3C64XX_GPN(8), 0);
    gpio_set_value(S3C64XX_GPN(8),1);    
    udelay(100);
    gpio_set_value(S3C64XX_GPN(8),0);    
    udelay(600);
    gpio_set_value(S3C64XX_GPN(8),1);
    udelay(100);    
    gpio_direction_output(S3C64XX_GPN(8), 1);

    if(gpio_get_value(S3C64XX_GPN(8)))
    {
    //    printk("kernel: DS18B20 initilize failed!\n");
        return 0;
    }
    return 1;
}

void write_byte(unsigned char byte)
{
    unsigned char i;

    gpio_direction_output(S3C64XX_GPN(8), 0);
    for(i=0; i<8; i++)
    {
        gpio_set_value(S3C64XX_GPN(8),0);
        udelay(1);
        if(byte & 0x01)
        {
            gpio_set_value(S3C64XX_GPN(8),1);
        }
        udelay(60);
        gpio_set_value(S3C64XX_GPN(8),1);
        udelay(15);
        byte >>= 1;
    }
    gpio_set_value(S3C64XX_GPN(8),1);    
}

unsigned char read_byte(void)
{
    unsigned char i=0;
    unsigned char byte=0;

    for(i=0; i<8; i++)
    {
        gpio_direction_output(S3C64XX_GPN(8), 0);
        gpio_set_value(S3C64XX_GPN(8),0);
        udelay(1);
        byte >>=1;
        gpio_set_value(S3C64XX_GPN(8),1);
        gpio_direction_output(S3C64XX_GPN(8), 1);
        if(gpio_get_value(S3C64XX_GPN(8)))
            byte |= 0x80;
        udelay(60);
    }

    return byte;
}

static void proc(void)
{
    while(reset());
    udelay(120);

    write_byte(0xcc);
    write_byte(0x44);
    udelay(5);

    while(reset());
    udelay(200);
    write_byte(0xcc);
    write_byte(0xbe);
    
    data[0] =  read_byte();
    data[1] =  read_byte();    
}

static int ds18b20_open(struct inode *inode, struct file *file)
{    
    printk("open DS18B20.\n");
    if(gpio_request(S3C64XX_GPN(8), "GPN") < 0)
    {
        return -1;
    }
    return 0;
}


static int ds18b20_close(struct inode *inode, struct file *file)
{
   printk("close DS18B20.\n");
   return 0;
}

static ssize_t ds18b20_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
    return 0;
}

static int ds18b20_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
    proc();
    
    buff[0] = data[0];
    buff[1] = data[1];

    return 1;
}


static struct file_operations dev_fops = {
    .owner   =   THIS_MODULE,    
    .open    =   ds18b20_open,
    .release =   ds18b20_close, 
    .read    =   ds18b20_read,    
    .write      =   ds18b20_write,    
};

static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &dev_fops,
};

static int __init dev_init(void)
{
    int ret;    

    ret = misc_register(&misc);    

    printk (DEVICE_NAME " initialized\n");    

    return ret;
}

static void __exit dev_exit(void)
{
    printk("DS18B20 module exit.\n");
    misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("centaur");

//测试程序
#include    <unistd.h>
#include    <signal.h>
#include    <stdlib.h>
#include    <sys/types.h>
#include    <sys/stat.h>
#include    <fcntl.h>
#include    <stdio.h>
#include    <string.h>
#include     <time.h>
#include     <sys/time.h>
#include     <sys/mman.h>

int main()
{
    int fd,t=0;
    unsigned char buf[2]={0,0};
    float result=0;
    if ((fd=open("/dev/ds18b20",O_RDWR)) < 0)
    {
        printf("Open Device DS18B20 failed.\r\n");
        exit(1);
    }
    
    while(1)
    {
        read(fd, buf, 1);
        t=(int)buf[1];
        t<<=8;
        t=t|buf[0];
        result=t*0.0625;
        printf("%.1f \n", result);

        sleep(1);
    }

    close(fd);

    return 0;
}

注意事项:
操作GPIO前如果没有使用gpio_request(S3C64XX_GPN(8), "GPN")函数申请资源,系统会打印出如下信息。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

相信玩过51的童鞋应该都玩过DS18B20吧,虽然用在ARM11上面,但是操作还是一样,多了一点就是读写IO前需要切换IO方向,其实51在读取之前需要切换到高电平的,这个一般由编译器完成的,

[cpp]  view plain copy
  1. /************************************************************************************************************* 
  2.  * 文件名: ds18b20.c 
  3.  * 功能:      S3C6410 DS18B20驱动 
  4.  * 作者:      cp1300@139.com 
  5.  * 创建时间:    2012年9月17日22:45 
  6.  * 最后修改时间:2012年9月17日 
  7.  * 详细:      需要延时函数支持 
  8.  *          注意延时精度尽可能的高 
  9.  *          读取的时候不要长时间的被中断,因为1wire对时间要求很严格 
  10. *************************************************************************************************************/  
  11. #include "system.h"  
  12. #include "timer.h"  
  13. #include "delay.h"  
  14. #include "ds18b20.h"  
  15.   
  16.   
  17. //DS18B20使用的是GPIOE0  
  18. #define Set18b20IOout()     (rGPECON |= 1)                          //设置DS18B20 IO为输出,  
  19. #define Set18b20IOin()      (rGPECON &= (~0xf)) //设置DS18B20 IO为浮空输入,  
  20. #define Read18b20IO()       ((rGPEDAT & BIT0) ? 1 : 0)              //读取DS18B20 IO  
  21. #define Write18b20IO(x)     (x ? (rGPEDAT |= BIT0) : (rGPEDAT &= ~BIT0))    //写DS18B20 IO  
  22.   
  23. /************************************************************************************************************************* 
  24. *函数        :    u8 DS18B20_Reset(void) 
  25. *功能        :    复位DS18B20 
  26. *参数        :    无 
  27. *返回        :    0:成功;1:失败 
  28. *依赖 :   底层宏定义 
  29. *作者        :    cp1300@139.com 
  30. *时间     :   20120917 
  31. *最后修改时间:    20120917 
  32. *说明        :无 
  33. *************************************************************************************************************************/  
  34. u8 DS18B20_Reset(void)  
  35. {  
  36.     u8 i = 0;  
  37.       
  38.     Set18b20IOout();    //主机端口推挽输出模式  
  39.     Write18b20IO(1);  
  40.     Delay_US(1);  
  41.     Write18b20IO(0);    //拉低总线480us~240us  
  42.     Delay_US(500);      //>480US延时  
  43.     Write18b20IO(1);  
  44.     Delay_US(2);        //复位完成  
  45.     Set18b20IOin();     //主机端口浮空输入模式  
  46.     while(Read18b20IO())    //等待低电平应答信号  
  47.     {  
  48.         i ++;  
  49.         Delay_US(1);  
  50.         if(i > 100)  
  51.             return 1;       //等待超时,初始化失败,返回1;  
  52.     }  
  53.     Delay_US(250);          //跳过回复信号  
  54.     return 0x00;            //检测到DS18B20,并且初始化成功  
  55. }  
  56.   
  57.   
  58. /************************************************************************************************************************* 
  59. *函数        :    u8 DS18B20_ReadData(void) 
  60. *功能        :    读取DS18B20数据 
  61. *参数        :    无 
  62. *返回        :    数据 
  63. *依赖 :   底层宏定义 
  64. *作者        :    cp1300@139.com 
  65. *时间     :   20120917 
  66. *最后修改时间:    20120917 
  67. *说明        :无 
  68. *************************************************************************************************************************/  
  69. u8 DS18B20_ReadData(void)  
  70. {  
  71.     u8 i,data = 0;  
  72.       
  73.     for(i = 0;i < 8;i ++)  
  74.     {  
  75.         Set18b20IOout();    //主机端口推挽输出模式  
  76.         Write18b20IO(0);    //拉低总线10-15us  
  77.         data >>= 1;  
  78.         Delay_US(12);  
  79.         Write18b20IO(1);    //释放总线  
  80.         Set18b20IOin();     //主机端口浮空输入模式  
  81.         Delay_US(1);  
  82.         if(Read18b20IO())   //读取数据,读取后大约延时40-45us  
  83.             data |= 0x80;  
  84.         Delay_US(42);  
  85.     }  
  86.     return data;  
  87. }  
  88.   
  89.   
  90. /************************************************************************************************************************* 
  91. *函数        :    void DS18B20_WriteData(u8 data) 
  92. *功能        :    向DS18B20写数据 
  93. *参数        :    数据 
  94. *返回        :    无 
  95. *依赖 :   底层宏定义 
  96. *作者        :    cp1300@139.com 
  97. *时间     :   20120917 
  98. *最后修改时间:    20120917 
  99. *说明        :无 
  100. *************************************************************************************************************************/  
  101. void DS18B20_WriteData(u8 data)  
  102. {  
  103.     u8 i;  
  104.       
  105.     Set18b20IOout();    //主机端口推挽输出模式  
  106.     for(i = 0;i < 8;i ++)  
  107.     {  
  108.         Write18b20IO(0);        //拉低总线10-15us  
  109.         Delay_US(12);  
  110.         Write18b20IO(data & 0x01);  //写入数据位,保持20-45us  
  111.         Delay_US(30);  
  112.         Write18b20IO(1);        //释放总线  
  113.         data >>= 1;  
  114.         Delay_US(2);  
  115.     }  
  116. }  
  117.   
  118.   
  119.   
  120. /************************************************************************************************************************* 
  121. *函数        :    s16 DS18B20_ReadTemper(void) 
  122. *功能        :    读取DS18B20温度 
  123. *参数        :    无 
  124. *返回        :    温度值 
  125. *依赖 :   底层宏定义 
  126. *作者        :    cp1300@139.com 
  127. *时间     :   20120917 
  128. *最后修改时间:    20120917 
  129. *说明        :温度值扩大了100倍,温度值是个有符号数. 
  130. *************************************************************************************************************************/  
  131. s16 DS18B20_ReadTemper(void)  
  132. {  
  133.     u8 th, tl;  
  134.     s16 data;  
  135.       
  136.     if(DS18B20_Reset())   
  137.     {  
  138.         return 0xffff;  //返回错误  
  139.     }  
  140.     DS18B20_WriteData(0xcc);    //跳过读序列号  
  141.     DS18B20_WriteData(0x44);    //启动温度转换  
  142.     DS18B20_Reset();  
  143.     DS18B20_WriteData(0xcc);    //跳过读序列号  
  144.     DS18B20_WriteData(0xbe);    //读取温度  
  145.     tl = DS18B20_ReadData();    //读取低八位  
  146.     th = DS18B20_ReadData();    //读取高八位  
  147.     data = th;  
  148.     data <<= 8;  
  149.     data |= tl;  
  150.     data *= 6.25;               //温度值扩大100倍,精确到2位小数  
  151.       
  152.     return data;  
  153. }  

[cpp]  view plain copy
  1.   
[cpp]  view plain copy
  1. DS18B20.H  
[cpp]  view plain copy
  1. #ifndef DS18B20_H_  
  2. #define DS18B20_H_  
  3.   
  4.   
  5. s16 DS18B20_ReadTemper(void);   //读取DS18B20温度  
  6.   
  7. #endif /*DS18B20_H_*/  



DELAY.C

[cpp]  view plain copy
  1. /************************************************************************************************************* 
  2.  * 文件名: delay.c 
  3.  * 功能:      延时函数,调用定时器1进行延时的 
  4.  * 作者:      cp1300@139.com 
  5.  * 创建时间:    2012年9月17日22:32 
  6.  * 最后修改时间:2012年9月17日 
  7.  * 详细:      延时误差1-2us,使用定时器1 
  8.  *          不能在中断服务程序中使用 
  9. *************************************************************************************************************/  
  10. #include "system.h"  
  11. #include "timer.h"  
  12. #include "delay.h"  
  13.   
  14.   
  15. /************************************************************************************************************************* 
  16. *函数        :    void Delay_US(u32 Delay) 
  17. *功能        :    US延时 
  18. *参数        :    Delay:延时时间,单位US 
  19. *返回        :    无 
  20. *依赖 :   底层宏定义 
  21. *作者        :    cp1300@139.com 
  22. *时间     :   20120917 
  23. *最后修改时间:    20120917 
  24. *说明        :调用定时器0进行延时的,那么定时器0就不能使用了,延时误差1US 
  25. *************************************************************************************************************************/  
  26. void Delay_US(u32 Delay)  
  27. {  
  28.     rTCFG0 |= 65;           //定时器0预分频65+1,由PCLK=66提供时钟,66分频产生1MHz的定时器时钟  
  29.     rTCON &= (~0xff);       //清除设置  
  30.     rTCON |= BIT3;          //定时器0自动更新使能  
  31.     rTCNTB0 = Delay;        //重装值  
  32.     rTINT_CSTAT |= BIT5;    //清除中断标志  
  33.     rTINT_CSTAT &= ~BIT0;   //关闭定时器0中断  
  34.     //以下操作启动定时器0  
  35.     rTCON |= BIT1;          //手动更新  
  36.     rTCON &= ~BIT1;         //结束手动更新  
  37.     rTCON |= BIT0;          //启动定时器0      
  38.     while(!(rTINT_CSTAT & BIT5));   //等待延时到达  
  39.     rTINT_CSTAT |= BIT5;    //清除中断标志  
  40. }  
  41.   
  42.   
  43.   
  44. /************************************************************************************************************************* 
  45. *函数        :    void Delay_MS(u32 Delay) 
  46. *功能        :    MS延时 
  47. *参数        :    Delay:延时时间,单位US 
  48. *返回        :    无 
  49. *依赖 :   底层宏定义 
  50. *作者        :    cp1300@139.com 
  51. *时间     :   20120918 
  52. *最后修改时间:    20120918 
  53. *说明        :调用定时器0进行延时的,那么定时器0就不能使用了,延时误差<1ms 
  54. *************************************************************************************************************************/  
  55. void Delay_MS(u32 Delay)  
  56. {  
  57.     while(Delay --)  
  58.     {  
  59.         Delay_US(1000);  
  60.     }  
  61. }  

后面将这个程序移植到LINUX上面当做DS18B20驱动


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值