#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h> //定义module_init和module_exit宏
#include <linux/fs.h> //定义file_opera
tions结构体和register_chrdev_region等函数
#include <linux/cdev.h> //定义cdev_init cdev_add cdev_del函数
#include <asm/uaccess.h> //定义copy_to_user和copy_from_user函数
#include <asm/io.h> //定义inl和outl、__raw_readl和__raw_writel等IO口读写宏
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-n.h>
#include <mach/map.h>
#include<linux/delay.h>
#define DS18B20_DEVICE_NAME "DS18B20"
#define DS18B20_DEVICE_FILENAME "/dev/DS18B20"
typedef unsigned char uchar ;
//////////////////////设定寄存器使io为输入状态/////////////
void shuru(void )
{
uint tmp;
tmp=readl(S3C64XX_GPNCON); //设置GPN寄存器,使用GPN的io口可以输入输出,读出GPNCON内部存的值
tmp &= 0xFFFCFFFF; //设置寄存器的16口为0,17口为0使其为输入状态
writel(tmp,S3C64XX_GPNCON); //在写入回到GPNCON中,设定为输入io
}
///////////////////////设定寄存器使io为输出状态/////////////////////////////
void shuchu(void)
{
uint tmp;
tmp=readl(S3C64XX_GPNCON); //设置GPN寄存器,使用GPN的io口可以输入输出,读出GPNCON内部存的值
tmp |= 0x00010000; //设置寄存器的16口为1,17口为0
writel(tmp,S3C64XX_GPNCON); //在写入回到GPNCON中,设定为输出io
}
//////////////////////////把io口拉高////////////////////
void tmph(void)
{
uint tmp;
tmp=readl(S3C64XX_GPNDAT); //读取p1.30口的值
tmp|=0x00000100; //把io口电平拉高
writel(tmp,S3C64XX_GPNDAT); //写入到18b20
}
//////////////////////////把io口拉低////////////////////
void tmpl(void)
{
uint tmp;
tmp=readl(S3C64XX_GPNDAT); //读取p1.30口的值
tmp&=0xFFFFFEFF; //把io口电平拉低
writel(tmp,S3C64XX_GPNDAT); //写入到18b20
}
///////////////////////////////初始化18b20/////////////////////////
uchar reset(void)
{
uint tmp;
uchar fuwei;
shuchu(); //设置为输出状态
tmph(); //拉高io口
tmpl(); //拉低io口
udelay(400); //延迟400us
tmph(); //拉高io口
udelay(80); //延迟80us
tmp=readl(S3C64XX_GPNDAT); //读出GPNSAT内部存的值
udelay(150); //延迟150us
tmp&=0x00000100;
tmp>>=8;
fuwei=tmp;
tmph();
return fuwei; //返回存在信号
}
////////////////////写一个位进去////////////////////
void wrbt(uchar bite)
{
shuchu();
tmpl(); //把io口拉低
if(bite==1)
tmph(); //把io拉高
udelay(30); //延迟30us
tmph(); //释放总线
udelay(15); //稍作延迟
}
/////////////////读一个位出来////////////////////////
uchar rdbt(void)
{
uint i=0;
uchar m=0;
shuru();
tmpl(); //拉低
udelay(1);
tmph(); //拉高
udelay(10); //延时不得超过4us
i=readl(S3C64XX_GPNDAT); //读取io口的值
udelay(10);
i=(i>>8); //读出的值(第一次为最低位)
m=(i&0x01);
printk("%daaaaa
",m);
return m; //返回读出的值
}
//////////////////写一个字节/////////////////////////
void wrbyte(uchar k)
{
uchar i=0,tmp=0;
for(i=0;i<8;i++)
{
tmp=(k>>i); //先写第一位数值
tmp=tmp&0x01;
wrbt(tmp); //调用函数写入值
udelay(100); //延时保证写入
}
}
///////////////////读一个字节//////////////////////////
uchar rdbyte(void)
{
uchar i=0,n=0,tmp=0;
for(i=0;i<8;i++)
{
n=rdbt();
n=(n<<i);
tmp=tmp+n;
udelay(100);
}
return tmp;
}
int DS18B20status=0;
////////////////////////////////////////////////////////////////////////////////////////////
// 实际工作部分 ///
///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////打开设备文件,并初始化设备文件//////////////////////////
int DS18B20_open(struct inode *inode,struct file *file)
{
uchar fuwei;
printk("DS18B20 open
");
fuwei=reset();
udelay(20);
if(fuwei)
printk("no node at here
");
else
printk("There is a node
");
return 0;
}
//////////////////////////////////关闭文件操作///////////////////////////////////
int DS18B20_release(struct inode *inode,struct file *file)
{
uint tmp;
shuru();
tmp=readl(S3C64XX_GPNDAT);
tmp &= 0xFFFFFEFF;
writel(tmp,S3C64XX_GPNDAT);
printk("DS18B20 close
");
return 0;
}
///////////////////////////////////////读温度传感器并转还为温度值///////////////////////////////////////
static ssize_t DS18B20_read(struct file *filp,unsigned char __user *buf,size_t count,loff_t *ppos)
{
uchar arry[2]={0};
reset();
udelay(420);//////////////////////////////////////////
wrbyte(0xcc); //给传感器写一个skipROM命令
wrbyte(0x44); //写一个温度转换命令convertT
mdelay(1000);/////////////////////////////////////////////
reset(); //等待转换成功
udelay(400);//////////////////////////////////////////
wrbyte(0xcc); //一个skipROM命令
wrbyte(0xbe); //写一个读取命令
arry[0]=rdbyte(); //读取低八位
arry[1]=rdbyte(); //读取高八位
// buf[0]=arry[0];
// buf[1]=arry[1];
/* if(arry[1]>>8!=0) //如果高八位不为0则为负摄氏温度
{
arry[1]=~arry[1]; //
arry[0]=~arry[0];
arry[0]+=1; //取反加一,求出原码
}
*/ *buf=arry[0]/16+arry[1]*16; //
*(buf+1)=(arry[0]&0x0f)*10/16+(arry[1]&0x0f)*100/16%10;
//copy_to_user(buf,&DS18B20status,1);
printk("DS18B20 read
");
printk("%d %d
",arry[0],arry[1]);
printk("bufaaaaaaddddddddddddddd = %d
",*(buf+1));
return 0;
}
////////////////////////////////////////写温度值////////////////////////////////////////////////////
static ssize_t DS18B20_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
reset();
wrbyte(0xCC);
wrbyte(0x4E);
wrbyte(buf[0]); // 写入上限值
wrbyte(buf[1]); //写入下限值
wrbyte(0x48); //把暂存器的值复制到E2存储器
printk("DS18B20 write
");
return 0;
}
long int DS18B20_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) //IO口控制函数,操作的时寄存器,cmd微操作命令,传递一个参数arg
{
//uint tmp;
printk("DS18B20 ioctl
");
/*switch(cmd)
{
case 0: tmp=readl(S3C64XX_GPNDAT);
tmp &= 0xFFFFBFFF;
writel(tmp,S3C64XX_GPNDAT);
printk("BEEP1 OFF
");
return 0;
case 1: tmp=readl(S3C64XX_GPNDAT);
tmp |= 0x00004000;
writel(tmp,S3C64XX_GPNDAT);
printk("BEEP1 ON
");
return 0;
default: printk("unsupported command
");
return -EINVAL;
}*/
return 0;
}
static struct file_operations DS18B20_fops=
{
.owner = THIS_MODULE, //拥有该结构模块的指针,避免在操作时被卸载,一般初始化为THIS_MODULE
.open = DS18B20_open, //对外提供打开操作
.release = DS18B20_release, //当file结构指针释放时,调用次函数,即:当最后一个打开该设备文件的用户调用close时,将调用此函数
//release 函数的主要任务是清理未结束的输入/输出操作、释放资源、用户自定义排他标志的复位等
.read = DS18B20_read, //对外提供读操作
.write = DS18B20_write, //对外提供写操作
.unlocked_ioctl = DS18B20_ioctl, //该函数是特殊的控制函数,可以通过它向设备传递控制信息或从设备取得状态信息,即为io控制函数
};
static struct cdev DS18B20_devs;
int major=0;
static void DS18B20_setup_cdev(struct cdev *dev,int minor,struct file_operations *fops)
{
int err,devno=MKDEV(major,minor);//把0和原来生成的设备号再合并到一块去 ,再生成一个设备号,表示有一个设备
cdev_init(dev,fops);
dev->owner=THIS_MODULE;
dev->ops=fops; //把dev的ops设置成为fops
err=cdev_add(dev,devno,1); //向内核注册新生成的devno信息,1表示和设备关联的的设备书目
if(err) //判断设备是否存活,如果cdev_add()调用成功的话,设备就可以使用了,外部的应用程序对它的操作,内核就会允许了
{
printk("Error %s adding DS18B20 %d
",KERN_ALERT,minor);
printk("Error %d adding DS18B20 %d
",err,minor);
}
}
static int DS18B20_init(void)
{
int result;
dev_t dev=MKDEV(major,0); //申请设备,major为主设备号,0为次设备号,表示自动分配设备号
if(major) //表示如果已经有了主设备号,就直接注册设备号
{
result=register_chrdev_region(dev,1,DS18B20_DEVICE_NAME);
}
else //如果没有主设备号,
{
result=alloc_chrdev_region(&dev,0,1,DS18B20_DEVICE_NAME);//自动申请主设备号
major=MAJOR(dev); //通过访问设备号,获得主设备号
}
if(result<0)
{
printk("DS18B20:unable to get major %s
",KERN_ALERT);//报告错误,立即采取措施宏为1
printk("DS18B20:unable to get major %d
",major);
return result;
}
DS18B20_setup_cdev(&DS18B20_devs,0,&DS18B20_fops);//这里的0表示的是第一个设备,因为咱们就有一个设备,以后在使用中,不一定是一个,拿着就是变量两
printk(KERN_ALERT"The major of DS18B20 device is %d
",major);
printk("The major of DS18B20 device is %d
",major);
return 0;
}
static void DS18B20_cleanup(void)
{
cdev_del(&DS18B20_devs);
unregister_chrdev_region(MKDEV(major,0),1);
printk("DS18B20 device uninstalDS18B20
");
printk(KERN_ALERT"DS18B20 device uninstall
");
}
module_init(DS18B20_init);
module_exit(DS18B20_cleanup);
MODULE_LICENSE("Dual BSD/GPL");
一周热门 更多>