mini2440 驱动ds18b20

来源:互联网 发布:php去除重复数组值 编辑:程序博客网 时间:2024/05/22 18:20

http://blog.csdn.net/xgg0602/article/details/7058071

今天下午闲着蛋疼,看鸟哥实在看不进去,想着有个ds18b20,于是就写了一个18b20的驱动。是在mini2440上面实现的。

         ldd3的大师说得好,linux驱动应该尽可能多的提供机制,而不是提供策略。我觉得说得太有道理了。驱动本身就不应该涉及到太多策略问题,策略问题应该尽可能多的由应用程序去提供。作为驱动,应该尽可能多得去实现提供硬件的功能,然后留出接口给上面的应用程序调用。

         其实ds18b20驱动比较简单,无非就是在单片机驱动18b20的基础上,家里一个字符驱动设备的外套。下面直接上代码吧。

         

         驱动代码:

[cpp] view plaincopyprint?
  1. #include <linux/init.h>  
  2. #include <linux/module.h>  
  3. #include <linux/delay.h>  
  4. #include <linux/kernel.h>  
  5. #include <linux/moduleparam.h>  
  6. #include <linux/init.h>  
  7. #include <linux/types.h>  
  8. #include <linux/fs.h>  
  9. #include <mach/regs-gpio.h>  
  10. #include <mach/hardware.h>  
  11. #include <linux/cdev.h>  
  12. #include <asm/uaccess.h>  
  13. #include <linux/errno.h>  
  14. #include <linux/gpio.h>  
  15. #include <linux/device.h> //自动创建设备需要此头文件  
  16.   
  17. #define DQ     S3C2410_GPF(3)      //mini2440里面是这样定义GPIO的  
  18. #define DQ_IN  S3C2410_GPIO_INPUT  //设置DQ为输入  
  19. #define DQ_OUT S3C2410_GPIO_OUTPUT //设置DQ为输入  
  20.   
  21. #define D_MAJOR 0                  //定义主设备号  
  22. #define D_MINOR 0                  //定义从设备号  
  23. #define DEV_NAME "ds18b20"         //定义设备名  
  24.   
  25. static int ds18b20_major = D_MAJOR;//ds18b20主设备号  
  26. static int ds18b20_minor = D_MINOR;//ds18b20从设备号  
  27. static struct class *my_class;     //定义class,用于自动挂载设备  
  28. static struct class_device *my_device; //自动挂载设备  
  29.   
  30. static struct ds18b20_dev{           //放在一个结构体中           
  31.     struct cdev cdev;                //这个结构体比较简单,但是建议以后将用户的东西都放在一个结构体中  
  32. };  
  33.   
  34. struct ds18b20_dev *ds18b20_devp;  
  35.   
  36. void ds18b20_reset(void)             //重启ds18b20  
  37. {  
  38.     s3c2410_gpio_cfgpin(DQ, DQ_OUT); //设置为输出  
  39.     s3c2410_gpio_pullup(DQ, 0);      //设置下拉  
  40.     s3c2410_gpio_setpin(DQ, 0);      //拉低总线  
  41.     udelay(500);                     //需要将总线拉低480~950us  
  42.     s3c2410_gpio_setpin(DQ, 1);      //释放总线  
  43.     udelay(60);                      //DS18B20拉低信号,60~240us表示应答  
  44.     s3c2410_gpio_cfgpin(DQ, DQ_IN);  //读入DS18B20拉低信号  
  45.     while(s3c2410_gpio_getpin(DQ));  //等待DS18B20应答  
  46.     while(!s3c2410_gpio_getpin(DQ)); //等待DS18B20释放总线      
  47. }  
  48.   
  49. void write_ds18b20(unsigned char Data)           //写命令到ds18b20  
  50. {     
  51.     unsigned char i;  
  52.     s3c2410_gpio_cfgpin(DQ, DQ_OUT);              //设置为输出  
  53.     s3c2410_gpio_pullup(DQ, 1);                   //上拉      
  54.     for(i=0;i<8;i++){  
  55.         s3c2410_gpio_setpin(DQ, 0);              //拉低总线  
  56.         udelay(10);                              //需要拉低10~15us  
  57.    
  58.         if(Data&0x01)  
  59.             s3c2410_gpio_setpin(DQ, 1);  
  60.         else  
  61.             s3c2410_gpio_setpin(DQ, 0);  
  62.         udelay(40);                             //需要拉低20~40us来写0  
  63.         s3c2410_gpio_setpin(DQ, 1);            //释放总线  
  64.         udelay(1);                            //稍微延时  
  65.         Data >>= 1;          
  66.     }  
  67. }  
  68.   
  69. static unsigned char read_ds18b20(void)    //读ds18b20  
  70. {  
  71.     unsigned char Temp=0,i;  
  72.     for(i=0;i<8;i++){  
  73.         Temp >>= 1;  
  74.         s3c2410_gpio_cfgpin(DQ, DQ_OUT);  //DQ为输出状态  
  75.         s3c2410_gpio_setpin(DQ, 0);       //拉低总线,启动输入  
  76.         udelay(1);                        //拉低总线约1us  
  77.         s3c2410_gpio_setpin(DQ, 1);       //释放总线  
  78.         s3c2410_gpio_cfgpin(DQ, DQ_IN);   //DQ为输入状态  
  79.         if(s3c2410_gpio_getpin(DQ))  
  80.           Temp |= 0x80;  
  81.         udelay(45);      //延时45us  
  82.     }  
  83.     return Temp;  
  84. }  
  85.   
  86. static int ds18b20_open(struct inode *inode,struct file *filp)  
  87. {  
  88.     filp->private_data = ds18b20_devp;  
  89.     ds18b20_reset();  
  90.     printk(KERN_NOTICE "open ds18b20 successful\n");  
  91.     return 0;  
  92. }  
  93.   
  94. static ssize_t ds18b20_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos)  
  95. {  
  96.     unsigned long err;  
  97.     struct ds18b20_dev *dev = filp->private_data;  
  98.     unsigned char result[2] = {0x00, 0x00};       //这个是用来存放从ds18b20读到的值  
  99.     ds18b20_reset();                              //reset ds18b20  
  100.     write_ds18b20(0xCC);                          //跳过ROM  
  101.     write_ds18b20(0x44);                          //温度转换  
  102.     ds18b20_reset();                              //reset ds18b20  
  103.     write_ds18b20(0xCC);                          //跳过ROM  
  104.        write_ds18b20(0xbe);                          //读取RAM  
  105.     result[0] = read_ds18b20();                   //读低8位,存放在result[0]  
  106.     result[1] = read_ds18b20();                   //读高8位,存放在result[1]  
  107.     ds18b20_reset();  
  108.     err = copy_to_user(buf, &result, sizeof(result));  
  109.     return err ? -EFAULT : min(sizeof(result), size);  
  110. }  
  111.   
  112. static int ds18b20_release(struct inode *inode,struct file *filp)  
  113.   
  114. {  
  115.     return 0;  
  116. }  
  117.   
  118. static const struct file_operations ds18b20_fops={  
  119.     .owner=THIS_MODULE,   
  120.     .read=ds18b20_read,  
  121.     .open=ds18b20_open,  
  122.     .release=ds18b20_release,  
  123.   
  124. };  
  125. void ds18b20_setup_dev(struct ds18b20_dev *dev,int minor)  
  126. {  
  127.     int err;  
  128.     int devno;  
  129.     devno = MKDEV(ds18b20_major,minor);  
  130.     cdev_init(&dev->cdev,&ds18b20_fops);  
  131.     dev->cdev.owner=THIS_MODULE;  
  132.     dev->cdev.ops=&ds18b20_fops;  
  133.     err=cdev_add(&dev->cdev,devno,1);  
  134.     if(err)  
  135.         printk(KERN_NOTICE "Error %d adding %d\n",err,minor);  
  136. }  
  137.   
  138. static int  __init ds18b20_init(void)  
  139. {  
  140.     int result;  
  141.     dev_t devno = 0;  
  142.       
  143.     if(ds18b20_major){  
  144.         devno = MKDEV(ds18b20_major,ds18b20_minor);  
  145.         result = register_chrdev_region(devno,1,DEV_NAME);  
  146.     }  
  147.     else{  
  148.         result = alloc_chrdev_region(&devno,0,1,DEV_NAME);  
  149.         ds18b20_major = MAJOR(devno);  
  150.     }  
  151.     if(result < 0)  
  152.         return result;  
  153.     ds18b20_devp = kmalloc(sizeof(struct ds18b20_dev),GFP_KERNEL);  
  154.     if(ds18b20_devp){  
  155.         result = -ENOMEM;  
  156.         goto fail_malloc;  
  157.     }  
  158.     memset(ds18b20_devp,0,sizeof(struct ds18b20_dev));  
  159.     ds18b20_setup_dev(ds18b20_devp,0);  
  160.     my_class = class_create(THIS_MODULE,"ds18b20_class");  
  161.     /*在linux 2.6.27之前是:class_device_create*/  
  162.     my_device = device_create(my_class,NULL,MKDEV(ds18b20_major, ds18b20_minor),NULL,"ds18b20");  
  163.     return 0;  
  164.     fail_malloc:  
  165.         unregister_chrdev_region(devno,1);  
  166.         return result;  
  167. }  
  168.   
  169. static void __exit ds18b20_exit(void)  
  170. {  
  171.     cdev_del(&ds18b20_devp->cdev);  
  172.     kfree(ds18b20_devp);  
  173.     device_destroy(my_class, MKDEV(ds18b20_major, ds18b20_minor));//删除设备文件 /dev/ds18b20   
  174.     class_destroy(my_class);   //删除创建的bus  
  175.     unregister_chrdev_region(MKDEV(ds18b20_major,ds18b20_minor),1);  
  176. }  
  177.   
  178. module_init(ds18b20_init);  
  179. module_exit(ds18b20_exit);  
  180.   
  181. MODULE_LICENSE("GPL");  
  182. MODULE_AUTHOR("WIOT");  
  183.    
#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/kernel.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/types.h>#include <linux/fs.h>#include <mach/regs-gpio.h>#include <mach/hardware.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/errno.h>#include <linux/gpio.h>#include <linux/device.h> //自动创建设备需要此头文件#define DQ     S3C2410_GPF(3)      //mini2440里面是这样定义GPIO的#define DQ_IN  S3C2410_GPIO_INPUT  //设置DQ为输入#define DQ_OUT S3C2410_GPIO_OUTPUT //设置DQ为输入#define D_MAJOR 0                  //定义主设备号#define D_MINOR 0                  //定义从设备号#define DEV_NAME "ds18b20"         //定义设备名static int ds18b20_major = D_MAJOR;//ds18b20主设备号static int ds18b20_minor = D_MINOR;//ds18b20从设备号static struct class *my_class;     //定义class,用于自动挂载设备static struct class_device *my_device; //自动挂载设备static struct ds18b20_dev{           //放在一个结构体中         struct cdev cdev;                //这个结构体比较简单,但是建议以后将用户的东西都放在一个结构体中};struct ds18b20_dev *ds18b20_devp;void ds18b20_reset(void)             //重启ds18b20{s3c2410_gpio_cfgpin(DQ, DQ_OUT); //设置为输出s3c2410_gpio_pullup(DQ, 0);      //设置下拉s3c2410_gpio_setpin(DQ, 0);      //拉低总线udelay(500);                     //需要将总线拉低480~950uss3c2410_gpio_setpin(DQ, 1);      //释放总线udelay(60);                      //DS18B20拉低信号,60~240us表示应答s3c2410_gpio_cfgpin(DQ, DQ_IN);  //读入DS18B20拉低信号while(s3c2410_gpio_getpin(DQ));  //等待DS18B20应答    while(!s3c2410_gpio_getpin(DQ)); //等待DS18B20释放总线}void write_ds18b20(unsigned char Data)           //写命令到ds18b20{unsigned char i;s3c2410_gpio_cfgpin(DQ, DQ_OUT);              //设置为输出s3c2410_gpio_pullup(DQ, 1);                   //上拉    for(i=0;i<8;i++){        s3c2410_gpio_setpin(DQ, 0);              //拉低总线        udelay(10);                              //需要拉低10~15us         if(Data&0x01)            s3c2410_gpio_setpin(DQ, 1);        else            s3c2410_gpio_setpin(DQ, 0);        udelay(40);                             //需要拉低20~40us来写0        s3c2410_gpio_setpin(DQ, 1);            //释放总线        udelay(1);                            //稍微延时        Data >>= 1;            }}static unsigned char read_ds18b20(void)    //读ds18b20{unsigned char Temp=0,i;for(i=0;i<8;i++){        Temp >>= 1;        s3c2410_gpio_cfgpin(DQ, DQ_OUT);  //DQ为输出状态        s3c2410_gpio_setpin(DQ, 0);       //拉低总线,启动输入        udelay(1);                        //拉低总线约1us        s3c2410_gpio_setpin(DQ, 1);       //释放总线        s3c2410_gpio_cfgpin(DQ, DQ_IN);   //DQ为输入状态        if(s3c2410_gpio_getpin(DQ))          Temp |= 0x80;        udelay(45);      //延时45us    }    return Temp;}static int ds18b20_open(struct inode *inode,struct file *filp){filp->private_data = ds18b20_devp;ds18b20_reset();printk(KERN_NOTICE "open ds18b20 successful\n");return 0;}static ssize_t ds18b20_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos){unsigned long err;struct ds18b20_dev *dev = filp->private_data;unsigned char result[2] = {0x00, 0x00};       //这个是用来存放从ds18b20读到的值ds18b20_reset();                              //reset ds18b20write_ds18b20(0xCC);                          //跳过ROMwrite_ds18b20(0x44);                          //温度转换ds18b20_reset();                              //reset ds18b20write_ds18b20(0xCC);                          //跳过ROM       write_ds18b20(0xbe);                          //读取RAMresult[0] = read_ds18b20();                   //读低8位,存放在result[0]result[1] = read_ds18b20();                   //读高8位,存放在result[1]ds18b20_reset();err = copy_to_user(buf, &result, sizeof(result));    return err ? -EFAULT : min(sizeof(result), size);}static int ds18b20_release(struct inode *inode,struct file *filp){return 0;}static const struct file_operations ds18b20_fops={.owner=THIS_MODULE,.read=ds18b20_read,.open=ds18b20_open,.release=ds18b20_release,};void ds18b20_setup_dev(struct ds18b20_dev *dev,int minor){int err;int devno;devno = MKDEV(ds18b20_major,minor);cdev_init(&dev->cdev,&ds18b20_fops);dev->cdev.owner=THIS_MODULE;dev->cdev.ops=&ds18b20_fops;err=cdev_add(&dev->cdev,devno,1);if(err)printk(KERN_NOTICE "Error %d adding %d\n",err,minor);}static int  __init ds18b20_init(void){int result;dev_t devno = 0;if(ds18b20_major){devno = MKDEV(ds18b20_major,ds18b20_minor);result = register_chrdev_region(devno,1,DEV_NAME);}else{result = alloc_chrdev_region(&devno,0,1,DEV_NAME);ds18b20_major = MAJOR(devno);}if(result < 0)return result;ds18b20_devp = kmalloc(sizeof(struct ds18b20_dev),GFP_KERNEL);if(ds18b20_devp){result = -ENOMEM;goto fail_malloc;}memset(ds18b20_devp,0,sizeof(struct ds18b20_dev));ds18b20_setup_dev(ds18b20_devp,0);my_class = class_create(THIS_MODULE,"ds18b20_class");/*在linux 2.6.27之前是:class_device_create*/    my_device = device_create(my_class,NULL,MKDEV(ds18b20_major, ds18b20_minor),NULL,"ds18b20");return 0;fail_malloc:unregister_chrdev_region(devno,1);return result;}static void __exit ds18b20_exit(void){cdev_del(&ds18b20_devp->cdev);kfree(ds18b20_devp);device_destroy(my_class, MKDEV(ds18b20_major, ds18b20_minor));//删除设备文件 /dev/ds18b20     class_destroy(my_class);   //删除创建的busunregister_chrdev_region(MKDEV(ds18b20_major,ds18b20_minor),1);}module_init(ds18b20_init);module_exit(ds18b20_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("WIOT"); 

应用程序代码:

[cpp] view plaincopyprint?
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <linux/ioctl.h>  
  5.   
  6. void ds18b20_delay(int i)  
  7. {  
  8.     int j, k;  
  9.     for (j = 0; j < i; j++)  
  10.         for(k = 0; k < 50000; k++);  
  11. }  
  12.   
  13.   
  14.   
  15. int main(int argc,char **argv)  
  16. {  
  17.     int fd, i;  
  18.     unsigned char result[2];  
  19.     unsigned int Temp;  
  20.     unsigned char Temperature[7];         //显示温度用的buffer  
  21.     fd = open("/dev/ds18b20",0);       
  22.     if(fd < 0){  
  23.         perror("open device failed!\n");  
  24.         exit(1);  
  25.     }  
  26.     while(1){  
  27.         read(fd,&result,sizeof(result));  
  28.         Temp = ((result[1]<<8)|result[0])*6.25; //这个是为了让温度后面有两位小数  
  29.         Temperature[0] = Temp/1000+48;      
  30.         Temperature[1] = Temp%1000/100+48;  
  31.         Temperature[2] = '.';  
  32.         Temperature[3] = Temp%100/10+48;  
  33.         Temperature[4] = Temp%10+48;  
  34.         Temperature[5] = ' ';  
  35.         Temperature[6] = 'C';  
  36.         printf("The temperature is:%s\n",Temperature);  
  37.         ds18b20_delay(1000);  
  38.     }  
  39.     return 0;  
  40. }    
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <linux/ioctl.h>void ds18b20_delay(int i){    int j, k;    for (j = 0; j < i; j++)        for(k = 0; k < 50000; k++);}int main(int argc,char **argv){int fd, i;unsigned char result[2];unsigned int Temp;unsigned char Temperature[7];         //显示温度用的bufferfd = open("/dev/ds18b20",0);     if(fd < 0){perror("open device failed!\n");exit(1);}while(1){read(fd,&result,sizeof(result));Temp = ((result[1]<<8)|result[0])*6.25; //这个是为了让温度后面有两位小数Temperature[0] = Temp/1000+48;    Temperature[1] = Temp%1000/100+48;Temperature[2] = '.';Temperature[3] = Temp%100/10+48;Temperature[4] = Temp%10+48;Temperature[5] = ' ';Temperature[6] = 'C';printf("The temperature is:%s\n",Temperature);ds18b20_delay(1000);}return 0;}  
[cpp] view plaincopyprint?
  1. 驱动放弃了好长时间了啊,要捡起来,并且深入。以后还是要坚定自己的选择。既然对这个感兴趣,就要经常的去折腾。  
     驱动放弃了好长时间了啊,要捡起来,并且深入。以后还是要坚定自己的选择。既然对这个感兴趣,就要经常的去折腾。
[cpp] view plaincopyprint?
  1. 年轻,就是应该多折腾一下,多做自己感兴趣的事情。
原创粉丝点击