ds18b20程序在mini2440下的移植(linux)
在网上搜过大量的基于18b20的程序,但大多版本问题不兼容。
以下代码是基于linux-2.6.32.2 内 核代码
能够正常编译通过。
/************************************************************/
//文件名:ds18b20.c
//功能:linux下的ds18b20驱动程序
//使用说明: (1)
//包含头文件
#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>
//DS18B20端口的定义
/* 相关引脚定义,方便以后移植 */
#define DQ S3C2410_GPF(3)
#define CFG_IN S3C2410_GPIO_INPUT
#define CFG_OUT S3C2410_GPIO_OUTPUT
// ds18b20主次设备号(动态分配)
static int ds18b20_major = 0;
static int ds18b20_minor = 0;
static int ds18b20_nr_devs = 1;
// 定义设备类型
static struct ds18b20_device
{
struct cdev cdev;
};
struct ds18b20_device *ds18b20_devp; /*设备结构体指针 */
static struct class *ds18b20_class;
static struct class_device *ds18b20_class_dev;
/* 函数声明 */
static int ds18b20_open(struct inode *inode, struct file *filp);
static int ds18b20_init(void);
static void write_byte(unsigned char data);
static unsigned char read_byte(void);
static ssize_t ds18b20_read(struct file *filp, char __user * buf, size_t count, loff_t * f_pos);
void ds18b20_setup_cdev(struct ds18b20_device *dev, int index);
static int ds18b20_open(struct inode *inode, struct file *filp)
{
int flag = 0;
flag = ds18b20_init();
if (flag & 0x01)
{
printk(KERN_WARNING "open ds18b20 failed\n");
return -1;
}
printk(KERN_NOTICE "open ds18b20 successful\n");
return 0;
}
static int ds18b20_init(void)
{
int retval = 0;
s3c2410_gpio_cfgpin(DQ, CFG_OUT);
s3c2410_gpio_pullup(DQ, 0);
s3c2410_gpio_setpin(DQ, 1);
udelay(2);
s3c2410_gpio_setpin(DQ, 0); // 拉低ds18b20总线,复位ds18b20
udelay(500); // 保持复位电平500us
s3c2410_gpio_setpin(DQ, 1); // 释放ds18b20总线
udelay(60);
// 若复位成功,ds18b20发出存在脉冲(低电平,持续60~240us)
s3c2410_gpio_cfgpin(DQ, CFG_IN);
retval = s3c2410_gpio_getpin(DQ);
udelay(500);
s3c2410_gpio_cfgpin(DQ, CFG_OUT);
s3c2410_gpio_pullup(DQ, 0);
s3c2410_gpio_setpin(DQ, 1); // 释放总线
return retval;
}
static void write_byte(unsigned char data)
{
int i = 0;
s3c2410_gpio_cfgpin(DQ, CFG_OUT);
s3c2410_gpio_pullup(DQ, 1);
for (i = 0; i < 8; i++)
{
// 总线从高拉至低电平时,就产生写时隙
s3c2410_gpio_setpin(DQ, 1);
udelay(2);
s3c2410_gpio_setpin(DQ, 0);
s3c2410_gpio_setpin(DQ, data & 0x01);
udelay(60);
data >>= 1;
}
s3c2410_gpio_setpin(DQ, 1); // 重新释放ds18b20总线
}
static unsigned char read_byte(void)
{
int i;
unsigned char data = 0;
for (i = 0; i < 8; i++)
{
// 总线从高拉至低,只需维持低电平17ts,再把总线拉高,就产生读时隙
s3c2410_gpio_cfgpin(DQ, CFG_OUT);
s3c2410_gpio_pullup(DQ, 0);
s3c2410_gpio_setpin(DQ, 1);
udelay(2);
s3c2410_gpio_setpin(DQ, 0);
udelay(2);
s3c2410_gpio_setpin(DQ, 1);
udelay(8);
data >>= 1;
s3c2410_gpio_cfgpin(DQ, CFG_IN);
if (s3c2410_gpio_getpin(DQ))
data |= 0x80;
udelay(50);
}
s3c2410_gpio_cfgpin(DQ, CFG_OUT);
s3c2410_gpio_pullup(DQ, 0);
s3c2410_gpio_setpin(DQ, 1); // 释放ds18b20总线
return data;
}
static ssize_t ds18b20_read(struct file *filp, char __user * buf, size_t count, loff_t * f_pos)
{
int flag;
unsigned long err;
unsigned char result[2] = { 0x00, 0x00 };
//struct ds18b20_device *dev = filp->private_data;
flag = ds18b20_init();
if (flag & 0x01)
{
printk(KERN_WARNING "ds18b20 init failed\n");
return -1;
}
write_byte(0xcc);
write_byte(0x44);
flag = ds18b20_init();
if (flag & 0x01)
return -1;
write_byte(0xcc);
write_byte(0xbe);
result[0] = read_byte(); // 温度低八位
result[1] = read_byte(); // 温度高八位
err = copy_to_user(buf, &result, sizeof(result));
return err ? -EFAULT : min(sizeof(result), count);
}
static struct file_operations ds18b20_dev_fops = {
.owner = THIS_MODULE,
.open = ds18b20_open,
.read = ds18b20_read,
};
void ds18b20_setup_cdev(struct ds18b20_device *dev, int index)
{
int err, devno = MKDEV(ds18b20_major, ds18b20_minor + index);
cdev_init(&dev->cdev, &ds18b20_dev_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&(dev->cdev), devno, 1);
if (err)
{
printk(KERN_NOTICE "ERROR %d add ds18b20\n", err);
}
}
static int __init ds18b20_dev_init(void)
{
int result;
dev_t dev = 0;
dev = MKDEV(ds18b20_major, ds18b20_minor);
if (ds18b20_major)
{
result = register_chrdev_region(dev, ds18b20_nr_devs, "ds18b20");
}
else
{
result = alloc_chrdev_region(&dev, ds18b20_minor, ds18b20_nr_devs, "ds18b20");
ds18b20_major = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "ds18b20: failed to get major\n");
return result;
}
/* 为新设备分配内存和初始化 */
ds18b20_devp = kmalloc(sizeof(struct ds18b20_device), GFP_KERNEL);
if (!ds18b20_devp)
{ /*申请失败 */
result = -ENOMEM;
goto fail_malloc;
}
memset(ds18b20_devp, 0, sizeof(struct ds18b20_device));
ds18b20_setup_cdev(ds18b20_devp, 0);
/* 自动创建设备节点 */
ds18b20_class = class_create(THIS_MODULE, "ds18b20_sys_class");
if (IS_ERR(ds18b20_class))
return PTR_ERR(ds18b20_class);
ds18b20_class_dev =
device_create(ds18b20_class, NULL, MKDEV(ds18b20_major, 0), NULL, "ds18b20");
if (unlikely(IS_ERR(ds18b20_class_dev)))
return PTR_ERR(ds18b20_class_dev);
return 0;
fail_malloc:
unregister_chrdev_region(dev, 1);
return result;
}
static void __exit ds18b20_dev_exit(void)
{
cdev_del(&ds18b20_devp->cdev); /*注销cdev */
kfree(ds18b20_devp); /*释放设备结构体内存 */
unregister_chrdev_region(MKDEV(ds18b20_major, 0), ds18b20_nr_devs); /*释放设备号 */
device_unregister(ds18b20_class_dev);
class_destroy(ds18b20_class);
}
module_init(ds18b20_dev_init);
module_exit(ds18b20_dev_exit);
MODULE_LICENSE("Dual BSD/GPL");
Makefile 如下
# This is the makefile of ds18b20
KERN_DIR = /home/d/work/linux_core/linux-2.6.32.2
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m :=ds18b20.o
编译结果
include/linux/device.h:481: note: expected 'struct device *' but argument is of type 'struct class_device *'
Building modules, stage 2.
MODPOST 1 modules
CC /home/d/share/ds18b20/ds18b20.mod.o
LD [M] /home/d/share/ds18b20/ds18b20.ko
make[1]: Leaving directory `/home/d/work/linux_core/linux-2.6.32.2'
密码: