基于S3C2440芯片linux系统下的ds18b20设备驱动

本驱动用的开发板是:

飞凌公司的OK2440开发板;

Linux内核版本是:linux2.6.35;

编译器:arm-linux-gcc-4.3.2

一、驱动分析
(1).这里采用混杂设备形式注册驱动,对于设备的操作仅且只有一个:即读操作,读函数为s3c2440_18b20_read(),完成的功能主要是从DS18b20中读取温度值然后从内核中将该温度值传给应用程序使用。
当然,要读取这个温度值,首先要令ds18b20这个芯片完成温度的转换,并将转换的值保存在该芯片的RAM中,占用9位。然后内核把这9个位的数读取过来。接着上传给应用程序;读取的过程是:
由于DS18B20采用独特的单总线接口方式,每只DS18B20都有一个唯一存储在ROM中的64位编码。最前面8位是单线系列编码:28H,接着的48位是一个唯一的序列号,最后8位是以上56位的CRC编码。通过单线总线端口访问DS18B20的协议如下:
①初始化;
②发送ROM操作指令;
③发送DS18B20功能指令。
另外要用的函数还有三个,分别是读一个字节函数,写一个字节函数,复位函数;

(2).复位操作流程
①设总线为输出模式;
②向总线发送一个上升沿,保持高电平100 us;
③向总线发送一个下降沿,保持低电平800 us;
④向总线发送一个上升沿,延时100 us;
⑤设总线为输入模式;
⑥判断总线状态,如果为低电平,则复位成功。

(3).写一个字节操作流程
①设总线为输出模式,并设置8次循环;
②向总线发送一个下降沿,保持低电平;
③判断写入数据是0还是1,如果是1,则向总线发送一个上升沿,保持高电平;如果是0,则保持总线低电平不变;
④延时60 us,设总线为高电平,再延时15 us;
⑤循环操作步骤②~④;
⑥设总线为高电平。

(4).读一个字节操作流程
①设循环次数为8;
②设总线为输出,向总线发送一个下降沿,保持低电平,并延时1 us;
③向总线发送一个上升沿,并设为输入;
④读总线状态,并保存为1位,并延时60us;
⑤循环操作步骤②~④,读取1个字节数据。
二、应用程序分析
应用程序中打开设备文件后,调用系统函数read函数读取温度,并用printf函数打印出这个值。

三、驱动程序和应用程序源码
(1)驱动程序
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/configfs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <plat/regs-timer.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-nrs.h>
#include <mach/map.h>
#include <mach/regs-irq.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <mach/regs-clock.h>
#include <asm/irq.h>
#include <linux/types.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/atomic.h>
#include <asm/unistd.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>

typedef unsigned char BYTE;

#define DS18B20_PIN   S3C2410_GPG(0)
#define DS18B20_PIN_OUTP S3C2410_GPIO_OUTPUT
#define DS18B20_PIN_INP   S3C2410_GPIO_INPUT
#define HIGH 1
#define LOW 0
#define DEVICE_NAME "DS18B20"

static BYTE data[2];
BYTE DS18b20_reset (void) 
{ 
    
    s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_OUTP);      //配置GPG0输出模式    
    s3c2410_gpio_setpin(DS18B20_PIN, HIGH);   // 向18B20发送一个上升沿,并保持高电平状态约100微秒 
    udelay(100);       
    s3c2410_gpio_setpin(DS18B20_PIN, LOW);   // 向18B20发送一个下降沿,并保持低电平状态约600微秒 
    udelay(600);        
    s3c2410_gpio_setpin(DS18B20_PIN, HIGH);   // 向18B20发送一个上升沿,此时可释放DS18B20总线 
    udelay(100);     
     
    // 以上动作是给DS18B20一个复位脉冲 
    // 通过再次配置GPIG0引脚成输入状态,可以检测到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;  
    s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_OUTP);   // 配置GPG0为输出模式 
    // 写“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()); //循环判断DS18B20直到复位,延时120ms; 
    udelay(120); 
     
    DS18b20_write_byte(0xcc); //写入CCH命令,跳过读序列号过程;
    DS18b20_write_byte(0x44); //写入44H命令,开始温度转换,延时5 ms;     
    udelay(5); 
     
    while(DS18b20_reset()); //循环判断DS18B20直到复位,延时200 ms;
    udelay(200); 
     
    DS18b20_write_byte(0xcc); //写入CCH命令,跳过读序列号过程;
    DS18b20_write_byte(0xbe); //写入BEH命令,读取寄存器;
     
    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 struct miscdevice misc = {
      .minor  = MISC_DYNAMIC_MINOR,
      .name  = DEVICE_NAME,
      .fops   = &s3c2440_18b20_fops,
};

static int __init s3c2440_18b20_init(void) 
{  
	    int ret;
	    ret = misc_register(&misc);
      printk (DEVICE_NAME" initialized\n");
          
    //devfs_mk_cdev(MKDEV(DEV_MAJOR, 0),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEV_NAME); 
     
    while(DS18b20_reset());
    return ret;    
} 

static void __exit s3c2440_18b20_exit(void) 
{ 
   
    misc_deregister(&misc);
   
} 
module_init(s3c2440_18b20_init); 
module_exit(s3c2440_18b20_exit); 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("luo");
MODULE_DESCRIPTION("DS18b20 Drivers for ok2440 Board");

(2)应用程序
#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, sizeof(buf)); 
					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("temperature is %4f \r\n", result); 
					sleep(2); 
        } 
        close(fd); 
    } 
} 

感谢网上的各位大牛,本博文主要参考:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值