搜索
bottom↓
回复: 3

arm linux下的DS18B20驱动和测试程序

[复制链接]

出0入0汤圆

发表于 2011-1-12 19:37:47 | 显示全部楼层 |阅读模式
这个程序是从网上找的,我只是修改了一下GPIO端口,电路连接也十分简单,直接连S3C2410_GPF4,把电源地线连好就行了,linux的驱动程序很好弄的,大家千万别被一些概念吓到
/************************* s3c2440_ds18b20.c文件开始 **************************/
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <linux/autoconf.h>
#include <linux/module.h>


typedef unsigned char BYTE;

#define DS18B20_PIN   S3C2410_GPF4
#define DS18B20_PIN_OUTP S3C2410_GPF4_OUTP
#define DS18B20_PIN_INP   S3C2410_GPF4_INP
#define HIGH 1
#define LOW 0
#define DEV_NAME "DS18B20"
#define DEV_MAJOR 232
static BYTE data[2];

MODULE_AUTHOR("sunrise");
MODULE_LICENSE("Dual BSD/GPL");

// DS18B20复位函数
BYTE DS18b20_reset (void)
{
    // 配置GPIOB0输出模式
    s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_OUTP);
   
    // 向18B20发送一个上升沿,并保持高电平状态约100微秒
    s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
    udelay(100);
   
    // 向18B20发送一个下降沿,并保持低电平状态约600微秒
    s3c2410_gpio_setpin(DS18B20_PIN, LOW);
    udelay(600);
   
    // 向18B20发送一个上升沿,此时可释放DS18B20总线
    s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
    udelay(100);
   
    // 以上动作是给DS18B20一个复位脉冲
    // 通过再次配置GPIOB1引脚成输入状态,可以检测到DS18B20是否复位成功
    s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_INP);
   
    // 若总线在释放后总线状态为高电平,则复位失败
    if(s3c2410_gpio_getpin(DS18B20_PIN)){ printk("DS18b20 reset failed.\r\n"); return 1;}

    return 0;
}


void DS18b20_write_byte (BYTE byte)
{
    BYTE i;
    // 配置GPIOB1为输出模式
    s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_OUTP);

    // 写“1”时隙:
    //     保持总线在低电平1微秒到15微秒之间
    //     然后再保持总线在高电平15微秒到60微秒之间
    //     理想状态: 1微秒的低电平然后跳变再保持60微秒的高电平
    //
    // 写“0”时隙:
    //     保持总线在低电平15微秒到60微秒之间
    //     然后再保持总线在高电平1微秒到15微秒之间
    //     理想状态: 60微秒的低电平然后跳变再保持1微秒的高电平
    for (i = 0; i < 8; i++)
    {
        s3c2410_gpio_setpin(DS18B20_PIN, LOW); udelay(1);
        if(byte & HIGH)
        {
             // 若byte变量的D0位是1,则需向总线上写“1”
             // 根据写“1”时隙规则,电平在此处翻转为高
             s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        }
        else
        {
             // 若byte变量的D0位是0,则需向总线上写“0”
             // 根据写“0”时隙规则,电平在保持为低
             // s3c2410_gpio_setpin(DS18B20_PIN, LOW);
        }
        // 电平状态保持60微秒
        udelay(60);

        s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        udelay(15);

        byte >>= 1;
    }
    s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
}

BYTE DS18b20_read_byte (void)
{
    BYTE i = 0;
    BYTE byte = 0;
    // 读“1”时隙:
    //     若总线状态保持在低电平状态1微秒到15微秒之间
    //     然后跳变到高电平状态且保持在15微秒到60微秒之间
    //      就认为从DS18B20读到一个“1”信号
    //     理想情况: 1微秒的低电平然后跳变再保持60微秒的高电平
    //
    // 读“0”时隙:
    //     若总线状态保持在低电平状态15微秒到30微秒之间
    //     然后跳变到高电平状态且保持在15微秒到60微秒之间
    //     就认为从DS18B20读到一个“0”信号
    //     理想情况: 15微秒的低电平然后跳变再保持46微秒的高电平
    for (i = 0; i < 8; i++)
    {
        s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_OUTP);
        s3c2410_gpio_setpin(DS18B20_PIN, LOW);

        udelay(1);
        byte >>= 1;

        s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_INP);

        // 若总线在我们设它为低电平之后若1微秒之内变为高
        // 则认为从DS18B20处收到一个“1”信号
        // 因此把byte的D7为置“1”
        if (s3c2410_gpio_getpin(DS18B20_PIN)) byte |= 0x80;
        udelay(60);
    }
    return byte;      
}

void DS18b20_proc(void)         
{
    while(DS18b20_reset());
   
    udelay(120);
   
    DS18b20_write_byte(0xcc);
    DS18b20_write_byte(0x44);
   
    udelay(5);
   
    while(DS18b20_reset());
    udelay(200);
   
    DS18b20_write_byte(0xcc);
    DS18b20_write_byte(0xbe);
   
    data[0] = DS18b20_read_byte();
    data[1] = DS18b20_read_byte();
}

static ssize_t s3c2440_18b20_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
    DS18b20_proc();

    buf[0] = data[0];
    buf[1] = data[1];
   
    return 1;
}

static struct file_operations s3c2440_18b20_fops =
{
    .owner = THIS_MODULE,
    .read = s3c2440_18b20_read,
};

static int __init s3c2440_18b20_init(void)
{
    if (register_chrdev(DEV_MAJOR, DEV_NAME, &s3c2440_18b20_fops) < 0)
    {
        printk(DEV_NAME ": Register major failed.\r\n");
        return -1;
    }
   
    //devfs_mk_cdev(MKDEV(DEV_MAJOR, 0),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEV_NAME);
   
    while(DS18b20_reset());   
}

static void __exit s3c2440_18b20_exit(void)
{
    //devfs_remove(DEV_NAME);
    unregister_chrdev(DEV_MAJOR, DEV_NAME);
}
module_init(s3c2440_18b20_init);
module_exit(s3c2440_18b20_exit);

/************************* s3c2440_ds18b20.c文件结束 **************************/

测试程序:
#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"

main()
{
    int fd;
    unsigned char buf[2];
    unsigned short temp=0;
        double result=0;
        int flag=0;

    if ((fd=open("/dev/DS18B20",O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
    {
        printf("Open Device DS18B20 failed.\r\n");
        exit(1);
    }
    else
    {
        printf("Open Device DS18B20 successed.\r\n");
        while(1)
        {
            read(fd, buf, 1);
                        printf("read data is 0x%02X-0x%02X\n",buf[1],buf[0]);
            temp=((unsigned short)buf[1])<<8;
                        temp|=(unsigned short)buf[0];
                        printf("no error here\n");
                        result=0.0625*((double)temp);
                        printf("%f \r\n", result);
            sleep(1);
        }
        close(fd);
    }
}

编译方法:驱动放到内核的driver/char下面,修改driver/char的Kconfig和Makefile文件,在Kconfig下添加
config GT2440_DS18B20_DRIVER
        tristate "GT2440_DS18B20_DRIVER"
        depends on ARCH_S3C2440
        default m if ARCH_S3C2440
        help
          By internet
在Makefile中添加
obj-$(CONFIG_GT2440_DS18B20_DRIVER)   +=gt2440_ds18b20.o
gt2440_ds18b20就是驱动的名字啦

测试时先insmod gt2440_ds18b20.ko
mknod /dev/DS18B20 c 232 0
./test1820

测试数据如下
11.8125
read data is 0x00-0xBD
the temp is 00BD
11.8125
read data is 0x00-0xBD
the temp is 00BD
11.8125
read data is 0x00-0xBD
the temp is 00BD
11.8125
read data is 0x00-0xBE
the temp is 00BE
11.8750
read data is 0x00-0xBD
the temp is 00BD
11.8125
read data is 0x00-0xBD
the temp is 00BD
11.8125
read data is 0x00-0xBD
the temp is 00BD
11.8125

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2011-1-12 20:14:26 | 显示全部楼层
这个...18b20对时间要求比较苛刻,不知道有其他程序同时在运行的情况下还能读到正确的温度么?

出0入0汤圆

 楼主| 发表于 2011-1-12 20:28:03 | 显示全部楼层
完全可以,驱动是工作在内核态的,优先级高,况且ARM的速度本来就快

出0入0汤圆

发表于 2011-1-12 20:46:08 | 显示全部楼层
mark一下
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 12:40

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表