ds18b20驱动及应用程序
------------------------------------------------------------------------------------------------------------------------------
交叉编译器:arm-linux-gcc-4.5.4
Linux内核版本:Linux-3.0
主机操作系统:Centos 6.5
开发板:FL2440
温度传感器:ds18b20
------------------------------------------------------------------------------------------------------------------------------
之前看过led的,platform_led的,platform_button的。当时以为看懂了,可是真的拿到一个模块要去写他的驱动的时候发现有些无从下手。于是借鉴了朋友的一篇混杂设备驱动,半抄半写的写出来了一个miscdevice类型的驱动。之后又在miscdevice与led的基础上写出来了cdev类型的驱动。并附上一个小小的测试程序。
一、miscdevice驱动
1 #include <linux/interrupt.h> 2 #include <linux/poll.h> 3 #include <linux/configfs.h> 4 #include <linux/module.h> 5 #include <linux/kernel.h> 6 #include <linux/fs.h> 7 #include <linux/clk.h> 8 #include <linux/init.h> 9 #include <linux/device.h> 10 #include <linux/miscdevice.h> 11 #include <linux/delay.h> 12 #include <linux/mm.h> 13 #include <plat/regs-timer.h> 14 #include <mach/regs-gpio.h> 15 #include <mach/map.h> 16 #include <mach/gpio-nrs.h> 17 #include <mach/regs-irq.h> 18 #include <asm/io.h> 19 #include <mach/hardware.h> 20 #include <asm/uaccess.h> 21 #include <asm/system.h> 22 #include <mach/regs-clock.h> 23 #include <asm/irq.h> 24 #include <linux/types.h> 25 #include <linux/moduleparam.h> 26 #include <linux/slab.h> 27 #include <linux/errno.h> 28 #include <linux/ioctl.h> 29 #include <linux/cdev.h> 30 #include <linux/string.h> 31 #include <linux/list.h> 32 #include <linux/pci.h> 33 #include <asm/atomic.h> 34 #include <asm/unistd.h> 35 #include <linux/miscdevice.h> 36 #include <linux/gpio.h> 37 38 /********************************************************************************* 39 * Copyright: (C) 2016 2013dianxin_3 40 * All rights reserved. 41 * 42 * Filename: ds18b20.c 43 * Description: This file 44 * 45 * Version: 1.0.0(08/07/2016) 46 * Author: xiaohexiansheng <1392195453@qq.com> 47 * ChangeLog: 1, Release initial version on "08/07/2016 02:21:17 PM" 48 * 49 ********************************************************************************/ 50 #define DRV_AUTHOR "xiaohexiansheng <wcchz@hotmail.com>" 51 #define DRV_DESC "s3c2440 ds18b20 driver" 52 #define DEVICE_NAME "ds18b20" 53 54 #define LOW 0 55 #define HIGH 1 56 typedef unsigned char BYTE; 57 58 static BYTE data[2]; 59 60 BYTE ds18b20_reset(void) 61 { 62 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); //配置GP0输出模式 63 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); //向ds18b20发送一个下降沿,并保持480us 64 udelay(480); 65 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); //向ds18b20发送一个上升沿,此时可释放ds18b20总线 66 udelay(60); 67 68 //以上动作是给ds18b20一个复位脉冲,通过配置GPIO引脚为输入模式可检测ds18b20是否复位成功 69 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_INPUT); 70 //若总线在释放后为高电平,则复位失败 71 if(s3c2410_gpio_getpin(S3C2410_GPG(0))) 72 { 73 printk("ds18b20 reset failed.\r\n"); 74 return 1; 75 } 76 udelay(240); 77 return 0; 78 } 79 80 BYTE ds18b20_read_byte(void) 81 { 82 BYTE i = 0; 83 BYTE byte = 0; 84 // 读“1”时隙: 85 // 若总线状态保持在低电平状态1微秒到15微秒之间 86 // 然后跳变到高电平状态且保持在15微秒到60微秒之间 87 // 就认为从DS18B20读到一个“1”信号 88 // 理想情况: 1微秒的低电平然后跳变再保持60微秒的高电平 89 // 读“0”时隙: 90 // 若总线状态保持在低电平状态15微秒到30微秒之间 91 // 然后跳变到高电平状态且保持在15微秒到60微秒之间 92 // 就认为从DS18B20读到一个“0”信号 93 // 理想情况: 15微秒的低电平然后跳变再保持46微秒的高电平 94 for(i = 0; i < 8; i++) 95 { 96 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); 97 98 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); 99 udelay(1); 100 byte >>= 1; 101 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); 102 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_INPUT); 103 // 若总线在我们设它为低电平之后若1微秒之内变为高 104 // 则认为从DS18B20处收到一个“1”信号 105 // 因此把byte的D7为置“1” 106 if(s3c2410_gpio_getpin(S3C2410_GPG(0))) 107 byte |= 0x80; 108 udelay(50); 109 } 110 return byte; 111 } 112 113 BYTE ds18b20_write_byte(BYTE byte) 114 { 115 BYTE i; 116 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); // 配置GPG0为输出模式 117 // 写“1”时隙: 118 // 保持总线在低电平1微秒到15微秒之间 119 // 然后再保持总线在高电平15微秒到60微秒之间 120 // 理想状态: 1微秒的低电平然后跳变再保持60微秒的高电平 121 // 写“0”时隙: 122 // 保持总线在低电平15微秒到60微秒之间 123 // 然后再保持总线在高电平1微秒到15微秒之间 124 // 理想状态: 60微秒的低电平然后跳变再保持1微秒的高电平 125 for(i = 0; i < 8; i++) 126 { 127 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); 128 udelay(15); 129 if(byte & HIGH) 130 { 131 // 若byte变量的D0位是1,则需向总线上写“1” 132 // 根据写“1”时隙规则,电平在此处翻转为高 133 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); 134 } 135 else 136 { 137 // 若byte变量的D0位是0,则需向总线上写“0” 138 // 根据写“0”时隙规则,电平在保持为低 139 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); 140 } 141 // 电平状态保持60微秒 142 udelay(45); 143 144 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); //释放总线 145 udelay(1); 146 byte >>= 1; 147 } 148 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); //释放总线 149 } 150 151 void ds18b20_proc(void) //读取温度 152 { 153 while(ds18b20_reset()); //循环判断DS18B20直到复位,延时120ms; 154 udelay(120); 155 ds18b20_write_byte(0xcc); //写入CCH命令,跳过读序列号过程; 156 ds18b20_write_byte(0x44); //写入44H命令,开始温度转换,延时5 ms; 157 udelay(5); 158 159 while(ds18b20_reset()); //循环判断DS18B20直到复位,延时200 ms; 160 udelay(200); 161 ds18b20_write_byte(0xcc); //写入CCH命令,跳过读序列号过程; 162 ds18b20_write_byte(0xbe); //写入BEH命令,读取寄存器; 163 164 data[0] = ds18b20_read_byte(); //读温度整数部分; 165 data[1] = ds18b20_read_byte(); //读温度小数部分 166 } 167 168 static ssize_t s3c2440_ds18b20_read(struct file *filp, char *buff, size_t len, loff_t *off) 169 { 170 ds18b20_proc(); 171 172 buff[0] = data[0]; 173 buff[1] = data[1]; 174 175 return 1; 176 } 177 178 static struct file_operations s3c2440_ds18b20_fops = 179 { 180 .owner = THIS_MODULE, 181 .read = s3c2440_ds18b20_read, 182 }; 183 184 static struct miscdevice misc = 185 { 186 .minor = MISC_DYNAMIC_MINOR, 187 .name = DEVICE_NAME, 188 .fops = &s3c2440_ds18b20_fops, 189 }; 190 191 static int __init s3c2440_ds18b20_init(void) 192 { 193 int result; 194 result = misc_register(&misc); 195 printk(DEVICE_NAME "initialized.\n"); 196 197 while(ds18b20_reset()); 198 return result; 199 } 200 201 static void __exit s3c2440_ds18b20_exit(void) 202 { 203 misc_deregister(&misc); 204 } 205 206 module_init(s3c2440_ds18b20_init); 207 module_exit(s3c2440_ds18b20_exit); 208 MODULE_AUTHOR(DRV_AUTHOR); 209 MODULE_DESCRIPTION(DRV_DESC); 210 MODULE_LICENSE("GPL");
二、cdevdevice驱动
1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/kernel.h> 4 #include <linux/fs.h> 5 #include <linux/delay.h> 6 #include <asm/irq.h> 7 #include <mach/regs-gpio.h> 8 #include <mach/hardware.h> 9 #include <linux/cdev.h> 10 #include <linux/device.h> 11 #include <linux/kdev_t.h> 12 #include <asm/uaccess.h> 13 #include <linux/platform_device.h> 14 #include <linux/gpio.h> 15 16 /********************************************************************************* 17 * Copyright: (C) 2016 2013dianxin_3 18 * All rights reserved. 19 * 20 * Filename: ds18b20.c 21 * Description: This file 22 * 23 * Version: 1.0.0(08/08/2016) 24 * Author: xiaohexiansheng <1392195453@qq.com> 25 * ChangeLog: 1, Release initial version on "08/08/2016 03:44:48 PM" 26 * 27 ********************************************************************************/ 28 #define DRV_AUTHOR "xiaohexiansheng <1392195453@qq.com>" 29 #define DRV_DESC "S3C2440 ds18b20 driver" 30 31 #define DEV_NAME "ds18b20" 32 #define DISABLE 0 33 #define DRV_MAJOR_VER 1 34 #define DRV_MINOR_VER 0 35 #define DRV_REVER_VER 0 36 37 #define LOW 0 38 #define HIGH 1 39 40 #ifndef DEV_MAJOR 41 #define DEV_MAJOR 0 42 #endif 43 44 int dev_major = DEV_MAJOR; 45 int dev_minor = 0; 46 int debug = DISABLE; 47 48 static struct cdev *ds18b20_cdev; 49 50 typedef unsigned char BYTE; 51 static BYTE data[2]; 52 53 BYTE ds18b20_reset(void) 54 { 55 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); 56 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); 57 udelay(480); 58 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); 59 udelay(60); 60 61 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_INPUT); 62 if(s3c2410_gpio_getpin(S3C2410_GPG(0))) 63 { 64 printk("ds18b20 reset failed.\r\n"); 65 return 1; 66 } 67 udelay(240); 68 return 0; 69 } 70 71 BYTE ds18b20_read_byte(void) 72 { 73 BYTE i = 0; 74 BYTE byte = 0; 75 76 for(i = 0; i < 8; i++) 77 { 78 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); 79 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); 80 udelay(1); 81 byte >>= 1; 82 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); 83 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_INPUT); 84 if(s3c2410_gpio_getpin(S3C2410_GPG(0))) 85 byte |= 0x80; 86 udelay(50); 87 } 88 return byte; 89 } 90 91 BYTE ds18b20_write_byte(BYTE byte) 92 { 93 BYTE i; 94 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); 95 for(i = 0; i < 8; i++) 96 { 97 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); 98 udelay(15); 99 if(byte & HIGH) 100 { 101 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); 102 } 103 else 104 { 105 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); 106 } 107 udelay(45); 108 109 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); 110 udelay(1); 111 byte >>= 1; 112 } 113 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); 114 return 0; 115 } 116 117 void ds18b20_proc(void) 118 { 119 while(ds18b20_reset()); 120 udelay(120); 121 ds18b20_write_byte(0xcc); 122 ds18b20_write_byte(0x44); 123 udelay(5); 124 125 while(ds18b20_reset()); 126 udelay(200); 127 ds18b20_write_byte(0xcc); 128 ds18b20_write_byte(0xbe); 129 130 data[0] = ds18b20_read_byte(); 131 data[1] = ds18b20_read_byte(); 132 } 133 134 static ssize_t s3c2440_ds18b20_read(struct file *filp, char *buff, size_t len, loff_t *off) 135 { 136 ds18b20_proc(); 137 138 buff[0] = data[0]; 139 buff[1] = data[1]; 140 141 return 1; 142 } 143 144 static struct file_operations ds18b20_fops = 145 { 146 147 .owner = THIS_MODULE, 148 .read = s3c2440_ds18b20_read, 149 }; 150 151 static int __init s3c_ds18b20_init(void) 152 { 153 int result; 154 dev_t devno; 155 156 if(0 != ds18b20_reset()) 157 { 158 printk(KERN_ERR "s3c2440 ds18b20 hardware initialize failure.\n"); 159 return -ENODEV; 160 } 161 162 if(0 != dev_major) 163 { 164 devno = MKDEV(dev_major, 0); 165 result = register_chrdev_region(devno, 1, DEV_NAME); 166 } 167 else 168 { 169 result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME); 170 dev_major = MAJOR(devno); 171 } 172 173 if(result < 0) 174 { 175 printk(KERN_ERR "s3c %s driver cannot use major %d.\n", DEV_NAME, dev_major); 176 return -ENODEV; 177 } 178 printk(KERN_DEBUG "s3c %s driver use major %d.\n", DEV_NAME, dev_major); 179 180 if(NULL == (ds18b20_cdev = cdev_alloc())) 181 { 182 printk(KERN_ERR "s3c %s driver cannot register cdev: result = %d.\n", DEV_NAME, result); 183 unregister_chrdev_region(devno, 1); 184 return -ENOMEM; 185 } 186 187 ds18b20_cdev -> owner = THIS_MODULE; 188 cdev_init(ds18b20_cdev, &ds18b20_fops); 189 190 result = cdev_add(ds18b20_cdev, devno, 1); 191 if(0 != result) 192 { 193 printk(KERN_ERR "s3c %s driver cannot register cdev: result = %d.\n", DEV_NAME, result); 194 goto ERROR; 195 } 196 197 printk(KERN_ERR "s3c %s driver[major=%d] Version %d.%d.%d installed successfully.\n",DEV_NAME, dev_major, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER); 198 return 0; 199 200 ERROR: 201 printk(KERN_ERR "s3c %s driver installed failure./", DEV_NAME); 202 cdev_del(ds18b20_cdev); 203 unregister_chrdev_region(devno, 1); 204 return result; 205 } 206 207 static void __exit s3c_ds18b20_exit(void) 208 { 209 dev_t devno = MKDEV(dev_major, dev_minor); 210 211 cdev_del(ds18b20_cdev); 212 unregister_chrdev_region(devno, 1); 213 214 printk(KERN_ERR "s3c %s driver version %d.%d.%d removed!\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER); 215 return; 216 } 217 218 module_init(s3c_ds18b20_init); 219 module_exit(s3c_ds18b20_exit); 220 221 module_param(debug, int, S_IRUGO); 222 module_param(dev_major, int ,S_IRUGO); 223 224 MODULE_AUTHOR(DRV_AUTHOR); 225 MODULE_DESCRIPTION(DRV_DESC); 226 MODULE_LICENSE("GPL");
注:cdev的驱动需要手动创建设备节点,而misc不需要
三、测试程序
1 /********************************************************************************* 2 * Copyright: (C) 2016 2013dianxin_3 3 * All rights reserved. 4 * 5 * Filename: dsapp.c 6 * Description: This file 7 * 8 * Version: 1.0.0(08/08/2016) 9 * Author: xiaohexiansheng <1392195453@qq.com> 10 * ChangeLog: 1, Release initial version on "08/08/2016 10:19:25 AM" 11 * 12 ********************************************************************************/ 13 #include <stdio.h> 14 #include <sys/types.h> 15 #include <sys/ioctl.h> 16 #include <stdlib.h> 17 #include <termios.h> 18 #include <sys/stat.h> 19 #include <fcntl.h> 20 #include <sys/time.h> 21 22 /******************************************************************************** 23 * Description: 24 * Input Args: 25 * Output Args: 26 * Return Value: 27 ********************************************************************************/ 28 int main (int argc, char **argv) 29 { 30 int fd; 31 double result = 0; 32 unsigned char buff[2]; 33 unsigned short temp = 0; 34 int flag = 0; 35 36 if ((fd=open("/dev/ds18b20",O_RDWR | O_NDELAY | O_NOCTTY)) < 0) 37 { 38 perror("open device ds18b20 failed.\r\n"); 39 exit(1); 40 } 41 while(1) 42 { 43 printf("open device ds18b20 success.\r\n"); 44 read(fd, buff, sizeof(buff)); 45 temp=((unsigned short)buff[1])<<8; 46 temp|=(unsigned short)buff[0]; 47 result=0.0625*((double)temp); 48 printf("temperature is %4f \r\n", result); 49 sleep(2); 50 } 51 close(fd); 52 53 return 0; 54 } /* ----- End of main() ----- */