鹿鼎记txt下载:DS18B20在linux下跑起来 - jammy

来源:百度文库 编辑:九乡新闻网 时间:2024/05/06 12:31:37

DS18B20linux下跑起来

       上次的让LEDlinux下闪烁起来可算是困难重重,毕竟是刚入手。这次的DS18B20加载到linux同样是个探险之旅。在不断的摸索、尝试,最后还是有点小成果。现在写下笔记,希望能与同路人分享交流。

       在加载到linux之前,我先确保DS18B20在无OS的环境下能正常工作,即“裸奔”。这个阶段也不是一路顺利,虽然以前有在单片机下驱动DS18B20的经验,但是在ARM延时确实是个问题。上网搜索一下,有的人用定时器延时,有的就直接程序耗时的方式延时。急于求成的我,为了避免使用定时器又出现新的麻烦,唯有使用后者的方法。好了,解决延时问题,DS18B20也自然运行起来,没有辜负我!哈~

       “裸奔”成功之后,现在就要给DS18B20披上linux的大衣。这次同样是将它以字符型设备驱动。按上次驱动LED的过程照葫芦画瓢,一个驱动程序,一个测试程序。

 

驱动程序

       驱动程序对比上次有所加深,多使用了几个系统调用函数。

 

       open()函数,对设备特殊文件进行open()系统调用时,将调用驱动程序的open () 函数:

    int (*open)(struct inode * ,struct file *);

       其中参数inode为设备特殊文件的inode (索引结点) 结构的指针,参数file是指向这一设备的文件结构的指针。open()的主要任务是确定硬件处在就绪状态、验证次设备号的合法性(次设备号可以用MINOR(inode-> i - rdev) 取得)、控制使用设备的进程数、根据执行情况返回状态码(0表示成功,负数表示存在错误) 等。

 

       read()函数。当对设备特殊文件进行read() 系统调用时,将调用驱动程序read() 函数:

     ssize_t (*read) (struct file *, char *, size_t, loff_t *);

       来从设备中读取数据。当该函数指针被赋为NULL 值时,将导致read 系统调用出错并返回-EINVAL("Invalid argument,非法参数")。函数返回非负值表示成功读取的字节数(返回值为"signed size"数据类型,通常就是目标平台上的固有整数类型)。

 

release()函数,当最后一个打开设备的用户进程执行close ()系统调用时,内核将调用驱动程序的release () 函数:

void (*release) (struct inode * ,struct file *) ;

release 函数的主要任务是清理未结束的输入/输出操作、释放资源、用户自定义排他标志的复位等。

 

程序如下:

/************************************************************/
//文件名:ds18b20.c
//功能:linux下的ds18b20驱动程序
//使用说明: (1)
//          (2)
//          (3)
//          (4)
//作者:jammy-lee

//日期:2009-03-31
/************************************************************/

//包含头文件

#include

#include

#include

#include

#include

 

#include

#include

#include

#inculde

#include

#include

#include

#include

#include

 

//DS18B20端口的定义

#define DQ_PIN      S3C2410_GPG14

#define DQ_IN       S3C2410_GPG14_INP

#define DQ_OUT      S3C2410_GPG14_OUTP

 

#define DEVICE_NAME     "DS18B20"   //驱动设备的名称,可以使用命令 cat /proc/devices

#define DS18B20_MAJOR      182      //主设备号

 

//定义DS18B20端口控制

#define   GPG_UP       s3c2410_gpio_pullup(DQ_PIN, 1)      //打开上拉电阻

#define   GPG_DOWN   s3c2410_gpio_pullup(DQ_PIN, 0)      //关闭上拉电阻

#define   DS18B20_L    s3c2410_gpio_setpin(DQ_PIN, 0)      //拉低数据线电平?

#define   DS18B20_H    s3c2410_gpio_setpin(DQ_PIN, 1)      //拉高数据线电平

#define   DS18B20_OUT s3c2410_gpio_cfgpin(DQ_PIN, DQ_OUT) //数据线设置为输出

#define   DS18B20_IN   s3c2410_gpio_cfgpin(DQ_PIN, DQ_IN)  //数据线设置为输入

#define   DS18B20_STU  s3c2410_gpio_getpin(DQ_PIN)         //数据状态

 

//定义DS18B20ROM指令

#define    DS18B20_ReadROM        0x33    //读ROM

#define    DS18B20_MatchROM    0x55    //匹配ROM

#define    DS18B20_SkipROM        0xCC    //跳过ROM

#define    DS18B20_SearchROM    0xF0    //搜索ROM

#define    DS18B20_AlarmROM    0xEC    //报警搜索

 

//定义DS18B20存储器操作命令

#define    DS18B20_WriteSCR    0x4E    //写暂存存储器

#define    DS18B20_ReadSCR        0xBE    //读暂存存储器

#define    DS18B20_CopySCR        0x48    //复制暂存存储器

#define    DS18B20_ConvertTemp    0x44    //温度变换

#define    DS18B20_RecallEP    0xB8    //重新调出

#define    DS18B20_ReadPower    0xB4    //读电源

 

//定义类型

typedef unsigned char uint8 ;

typedef unsigned int uint16 ;

 

//全局变量

uint8 opencount = 0;

 

//函数声明

uint8 Init_DS18B20(void);            //初始化DS18B20

 

uint8 DS18B20_ReadByte(void);        //读取DS18B20一字节

 

void DS18B20_WriteByte(uint8 Data);    //写入DS18B20一字节

 

void DS18B20_ReadID(void);            //读取DS18B20的ID

 

void DS18B20_Match(void);            //匹配DS18B20

 

uint16 DS18B20_Temperature(void);    //单个DS18B20温度读取

 

uint16 nDS18B20_Temperature(void);     //读取多个DS18B20的温度?

 

uint8 DS18B20_ID[8] = {0};

 

//初始化DS18B20

uint8 Init_DS18B20(void)

{

    uint8 errTime;

 

    DS18B20_OUT;

    DS18B20_H;   

    DS18B20_L;        //初始化发送一复位脉冲

    udelay(500);      //脉冲时间大于480us

    DS18B20_H;

    DS18B20_IN;

    udelay(80);

 

    while(DS18B20_STU)

    {

      udelay(6);    //5.15us

      errTime++;

      if(errTime>20)

         return 0;     ///如果等带大于约 5.15us*20就返回0x00,报告复位失败(实际上只要等待15-60us)

    }

    errTime=0;

    while(!(DS18B20_STU))

    {

      udelay(6);    //5.15us

      errTime++;

      if(errTime>50)

         return 0;      //如果等带大于约 5.15us*50就返回0x00,报告复位失败(实际上只要等待60-240us)

    }

    return 0xff;

}

 

//读取DS18B20一字节

uint8 DS18B20_ReadByte(void)

{

    uint8 i;

    uint8 temp = 0;

    DS18B20_IN;

    //asm("nop");

    for(i=0;i<8;i++)

    {

        temp >>= 1;        //向右移动一位;

        DS18B20_OUT;

        DS18B20_L;

        udelay(8);

        DS18B20_H;

        DS18B20_IN;        //释放总线

        if(DS18B20_STU)

            temp |= 0x80;

        udelay(32);

        DS18B20_OUT;

        DS18B20_H;

        //delay_nus(32);

    }

    udelay(5);

    return (temp);

}

 

//写入DS18B20一字节

void DS18B20_WriteByte(uint8 Data)

{

    uint8 i;

    uint8 temp;

    DS18B20_IN;

    //asm("nop");

    for(i=0;i<8;i++)

    {

        DS18B20_OUT;

        DS18B20_L;

        udelay(4);

        temp = Data >> i;

        temp &= 0x01;               

        if(temp)

            DS18B20_H;

        else

            DS18B20_L;

        udelay(50);

        DS18B20_H;

        udelay(4);

    }

    //DS18B20_H;

}

 

//读取DS18B20的ID

void DS18B20_ReadID(void)

{

    udelay(1);

    Init_DS18B20();

    DS18B20_WriteByte(DS18B20_ReadROM);

    DS18B20_ID[0] = DS18B20_ReadByte();

    DS18B20_ID[1] = DS18B20_ReadByte();

    DS18B20_ID[2] = DS18B20_ReadByte();

    DS18B20_ID[3] = DS18B20_ReadByte();

    DS18B20_ID[4] = DS18B20_ReadByte();

    DS18B20_ID[5] = DS18B20_ReadByte();

    DS18B20_ID[6] = DS18B20_ReadByte();

    DS18B20_ID[7] = DS18B20_ReadByte();

}

 

//匹配DS18B20

void DS18B20_Match(void)

{

    DS18B20_WriteByte(DS18B20_MatchROM);

    DS18B20_WriteByte(DS18B20_ID[0]);

    DS18B20_WriteByte(DS18B20_ID[1]);

    DS18B20_WriteByte(DS18B20_ID[2]);

    DS18B20_WriteByte(DS18B20_ID[3]);

    DS18B20_WriteByte(DS18B20_ID[4]);

    DS18B20_WriteByte(DS18B20_ID[5]);

    DS18B20_WriteByte(DS18B20_ID[6]);

    DS18B20_WriteByte(DS18B20_ID[7]);

}

 

//单个DS18B20温度读取

uint16 DS18B20_Temperature(void)

{

    uint8 flag = 0;

    uint8 tempH = 0;

    uint8 tempL = 0;

    uint16 temp = 0;

 

    flag = Init_DS18B20();

    if(flag == 0x00)

    return -1;

    DS18B20_WriteByte(DS18B20_SkipROM);

    DS18B20_WriteByte(DS18B20_ConvertTemp);

 

    flag = Init_DS18B20();

    if(flag == 0x00)

    return -1;

 

    DS18B20_WriteByte(DS18B20_SkipROM);

    DS18B20_WriteByte(DS18B20_ReadSCR);

    tempL = DS18B20_ReadByte();

    tempH = DS18B20_ReadByte();

    temp = (tempH<<8) | tempL;

    temp = temp * 0.625 *10;

    return temp;

}

 

//读取多个DS18B20的温度

uint16 nDS18B20_Temperature(void)

{

    uint8 tempH = 0;

    uint8 tempL = 0;

    uint16 temp = 0;

    udelay(1000);

    Init_DS18B20();

    DS18B20_Match();

    udelay(30000);

    DS18B20_WriteByte(DS18B20_ConvertTemp);

    Init_DS18B20();

    DS18B20_Match();

    DS18B20_WriteByte(DS18B20_ReadSCR);

    tempL = DS18B20_ReadByte();

    tempH = DS18B20_ReadByte();

    temp = (tempH<<8) | tempL;

    temp = temp * 0.625 *10;

    return temp;

}

 

//write()系统调用函数

static ssize_t ds18b20_write(struct file *filp, const char *buffer,

             size_t count, loff_t *ppos)

{

  return 1;//返回一个数

}

 

//read()系统调用函数

static ssize_t ds18b20_read(struct file *filp, char *buffer,

             size_t count, loff_t *ppos)

{

    uint16 tmp;

 

    tmp =  DS18B20_Temperature();

    copy_to_user(buffer, &temp, 1);    //将读取得的DS18B20数值复制到用户区

 

    return 1;

}

 

//open()系统调用函数

static int ds18b20_open(struct inode *node, struct file *file)

{

  uint8 flag = 0;

  if(opencount == 1)

    return -EBUSY;

 

  flag = Init_DS18B20();  //获取初始数值

  if(flag == 0)           //初始化失败

    {

      printk("uable to open device!\n");

      return -1;

    }

  else                    //初始化成功

   {

      opencount++;

      printk("device opened!\n");

      return 0;

   }

}

 

//release()系统调用函数

static int ds18b20_release(struct inode *node, struct file *file)

{

  opencount--;

  printk("device released!\n");

  return 0;

}

 

// 这个结构是字符设备驱动程序的核心

//当应用程序操作设备文件时所调用的open、read、write,release等函数,

//最终会调用这个结构中指定的对应函数

static struct file_operations ds18b20_fops = {

  .owner = THIS_MODULE,

  .open = ds18b20_open,

  .write = ds18b20_write,

  .read = ds18b20_read,

  .release = ds18b20_release,

};

 

//执行“insmod ds18b20.ko”命令时就会调用这个函数

static int __init ds18b20_init(void)

{

    int ret;

 

    printk("Initial driver for ds18b20......................\n");

    ret = register_chrdev(DS18b20_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);

    if (ret < 0)

    {

        printk(DEVICE_NAME " can't register major number\n");

        return ret;

 

    }

    else

    {

        prink("DS18B20 register success");

    }

}

 

//执行“rmmod ds18b20.ko”命令时就会调用这个函数

void __exit ds18b20_exit(void)

{

    unregister_chrdev(&DS18B20_MAJOR);

    prink("DS18B20 unregister success");

}

 

module_init(ds18b20_init);

module_exit(ds18b20_exit);

MODULE_AUTHOR("jammy_lee@163.com");

MODULE_DESCRIPTION("DS18B20 driver for TQ2440");

MODULE_LICENSE("GPL");

 

       程序写好了,等待着编译的成功。可以命运总是爱戏弄我!

 

编译代码时出现的警告,加载到linux时候也是出现同样的警告,加载失败。哭~~~

 

*** Warning: "__fixunsdfsi" [drivers/char/ds18b20.ko] undefined!

*** Warning: "__muldf3" [drivers/char/ds18b20.ko] undefined!

*** Warning: "__adddf3" [drivers/char/ds18b20.ko] undefined!

*** Warning: "__floatsidf" [drivers/char/ds18b20.ko] undefined!

 

原因是," temp = temp *0.625*10; " ,有浮点数出现。可能没有包含linux运算浮点数的头文件,又或者其它原因,当务之急还是先走走捷径。

改为:

" temp = temp * 10 / 16 * 10 "

编译没有出现警告。

Yeah,成功了!!

 

测试程序

/************************************************************/
//文件名:test_ds18b20.c
//功能:测试linux下的ds18b20程序
//使用说明: (1)
//          (2)
//          (3)
//          (4)
//作者:jammy-lee
//日期:2008-03-31
/************************************************************/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

int main(void)

{

    int fd = -1;

    char count = 5;

    unsigned int tmp = 0;

 

    fd = open("/dev/ds18b20", 0);

    if(fd < 0)

    {

        perror("Can't open /dev/ds18b20 \n");

        exit(1);

    }

    printf("open ds18b20 success \n");

    while(count--)

    {

        read(fd, &tmp , sizeof(int));

        printf("the currently temperature is %d \n",tmp);

    }

}

 

 

       终于,DS18B20linux下准确地报告了它测得的温度!欣喜若狂!!

       若有错误,希望贵人能指出!jammy感激万分