mini2440 驱动ds18b20

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

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

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

         

         驱动代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  //自动创建设备需要此头文件

#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~950us
	s3c2410_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 ds18b20
	write_ds18b20(0xCC);                          //跳过ROM
	write_ds18b20(0x44);                          //温度转换
	ds18b20_reset();                              //reset ds18b20
	write_ds18b20(0xCC);                          //跳过ROM
       write_ds18b20(0xbe);                          //读取RAM
	result[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);   //删除创建的bus
	unregister_chrdev_region(MKDEV(ds18b20_major,ds18b20_minor),1);
}

module_init(ds18b20_init);
module_exit(ds18b20_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("WIOT");
 

应用程序代码:

#include 
#include 
#include 
#include 

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];         //显示温度用的buffer
	fd = 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;
}  
     驱动放弃了好长时间了啊,要捡起来,并且深入。以后还是要坚定自己的选择。既然对这个感兴趣,就要经常的去折腾。
     年轻,就是应该多折腾一下,多做自己感兴趣的事情。

你可能感兴趣的:(Linux驱动学习)