此代码为本人原创。该代码仍有不完善之处,有可能还要再次修改!仅供参考!
若有错误、疑问和意见请留言,非常感谢!
该驱动程序基于TQ2440开发板,内核2.6.30。
驱动程序比较简单,使用字符设备来实现。要注意的是在模拟DS18B20的总线时序时,处理器不能抢占当前线程从而造成时序错乱,因此使用了自旋锁来禁止处理器抢占。
代码比较简单,所以代码注释也比较少。如果有不明白的请参考DS18B20的datasheet以及<<Linux设备驱动程序>>的第三章。
1. 驱动代码一
NOTE:请使用驱动代码二,代码一不支持多进程访问。
- //using cdev to create device
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <asm/irq.h>
- #include <mach/regs-gpio.h>
- #include <mach/hardware.h>
- #include <linux/device.h>
- #include <linux/kdev_t.h>
- #include <linux/cdev.h>
- #include <linux/spinlock.h>
- #include <linux/mutex.h>
- #include <asm/uaccess.h>
- #define DEVICE_NAME "ds18b20"
- #define SKIP_ROM 0xcc
- #define CONVERT_T 0x44
- #define READ_SCRATCHPAD 0xbe
- #define DQ S3C2410_GPB5
- MODULE_LICENSE("GPL");
- static struct ds18b20_info
- {
- struct mutex ds18b20_mutex;
- spinlock_t ds18b20_spinlock;
- };
- static int ds18b20_init_work(struct ds18b20_info *dsin)
- {
- char n;
- unsigned long flag;
- spin_lock_irqsave(&dsin->ds18b20_spinlock,flag);
- s3c2410_gpio_setpin(DQ, 1);
- udelay(70);
- s3c2410_gpio_setpin(DQ, 0);
- udelay(500);
- s3c2410_gpio_setpin(DQ, 1);
- udelay(70);
- n = s3c2410_gpio_getpin(DQ);
- if(n == 1)
- n = -1;
- udelay(80);
- spin_unlock_irqrestore(&dsin->ds18b20_spinlock, flag);
- return n;
- }
- static void ds18b20_write_byte(unsigned char data, struct ds18b20_info *dsin){
- unsigned char i;
- unsigned long flag;
- spin_lock_irqsave(&dsin->ds18b20_spinlock,flag);
- for (i = 0; i < 8; i++){
- s3c2410_gpio_setpin(DQ, 0);
- udelay(10);
- s3c2410_gpio_setpin(DQ, (data&0x01)? 1:0);
- udelay(40);
- s3c2410_gpio_setpin(DQ, 1);
- data >>= 1;
- udelay(1);
- }
- spin_unlock_irqrestore(&dsin->ds18b20_spinlock, flag);
- }
- static unsigned char ds18b20_read_byte(struct ds18b20_info *dsin){
- unsigned char i, value= 0;
- unsigned long flag;
- spin_lock_irqsave(&dsin->ds18b20_spinlock,flag);
- for(i = 0; i < 8; i++){
- value >>= 1;
- s3c2410_gpio_setpin(DQ, 0); //pull low
- s3c2410_gpio_setpin(DQ, 1); //pull high
- if (s3c2410_gpio_getpin(DQ)) //read
- {
- value |= 0x80;
- }
- udelay(40);
- }
- spin_unlock_irqrestore(&dsin->ds18b20_spinlock, flag);
- return value;
- }
- static int ds18b20_open(struct inode *inode, struct file *file)
- {
- struct ds18b20_info *dsin = kmalloc(sizeof(* dsin), GFP_KERNEL);
- if(dsin == NULL){
- printk("No memory for ds18b20\n");
- return -ENOENT;
- }
- memset(dsin, 0, sizeof(*dsin));
- file->private_data = dsin;
- spin_lock_init(&dsin->ds18b20_spinlock);
- mutex_init(&ds