基于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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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 
#include  
#include  
#include  
#include 
#include 
#include  
#include  

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); 
    } 
} 
基于S3C2440芯片linux系统下的ds18b20设备驱动_第1张图片


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

  • http://blog.chinaunix.net/uid-25923232-id-366019.html
  • http://www.eepw.com.cn/article/236202.htm
  • http://www.21ic.com/jichuzhishi/datasheet/DS18B20/yuanli/187677.html

你可能感兴趣的:(OK2440设备驱动)