基于Linux操作系统下面的驱动程序的编写
一、所用的平台:
硬件平台:Mini2440
Size of NAND:256M
linux kernel:linux-2.6.32.2
二、编写ds18b20驱动程序所需要用到的硬件资源是操作s3c2440的引脚以及该引脚所对应的一些数据寄存器,那么该驱动程序例程是用引脚是S3C2410_GPG(0)。
三、编写驱动时首先要对编写的对象的时序要了解,那么ds18b20的时序如下:
DS18B20时序详解
初始化时序:
DS18B20的所有通信都是以由复位脉冲组成的初始化序列开始的。该初始化序列由主机发出,后跟由DS18B20发出的存在脉冲(presence
pulse)。
DS18B20发出存在脉冲,以通知主机它在总线上并且准备好操作了。
在初始化时序中,总线上的主机通过拉低单总线至少480μs来发送复位脉冲。然后总线主机释放总线并进入接收模式。总线释放后,4.7kΩ的上拉电阻把单总线上的电平拉回高电平。当DS18B20检测到上升沿后等待15到60us,然后以拉低总线60-240us的方式发出存在脉冲。
如上所述,主机将总线拉低最短480us,之后释放总线。由4.7kΩ上拉电阻将总线恢复到高电平。DS18B20检测到上升沿后等待15到60us,发出存在脉冲:拉低总线60-240us。至此,初始化和存在时序完毕。
写时序: 主机在写时隙向DS18B20写入数据,在读时隙从DS18B20读取数据。在单总线上每个时隙只传送一位数据。
有两种写时隙:写“0”时间隙和写“1”时间隙。总线主机使用写“1”时间隙向DS18B20写入逻辑1,使用写“0”时间隙向DS18B20写入逻辑0.所有的写时隙必须有最少60us的持续时间,相邻两个写时隙必须要有最少1us的恢复时间。两种写时隙都通过主机拉低总线产生。
为了产生写1时隙,在拉低总线后主机必须在15μs内释放总线。在总线被释放后,由于4.7kΩ上拉电阻将总线恢复为高电平。为了产生写0时隙,在拉低总线后主机必须继续拉低总线以满足时隙持续时间的要求(至少60μs)。
在主机产生写时隙后,DS18B20会在其后的15到60us的一个时间窗口内采样单总线。在采样的时间窗口内,如果总线为高电平,主机会向DS18B20写入1;如果总线为低电平,主机会向DS18B20写入0。
如上所述,所有的写时隙必须至少有60us的持续时间。相邻两个写时隙必须要有最少1us的恢复时间。所有的写时隙(写0和写1)都由拉低总线产生。
读时序: DS18B20只有在主机发出读时隙后才会向主机发送数据。因此,在发出读暂存器命令
[BEh]或读电源命令[B4h]后,主机必须立即产生读时隙以便DS18B20提供所需数据。另外,主机可在发出温度转换命令T
[44h]或Recall命令E 2[B8h]后产生读时隙,以便了解操作的状态。
所有的读时隙必须至少有60us的持续时间。相邻两个读时隙必须要有最少1us的恢复时间。所有的读时隙都由拉低总线,持续至少1us后再释放总线(由于上拉电阻的作用,总线恢复为高电平)产生。在主机产生读时隙后,DS18B20开始发送0或1到总线上。DS18B20让总线保持高电平的方式发送1,以拉低总线的方式表示发送0.当发送0的时候,DS18B20在读时隙的末期将会释放总线,总线将会被上拉电阻拉回高电平(也是总线空闲的状态)。DS18B20输出的数据在下降沿(下降沿产生读时隙)产生后15us后有效。因此,主机释放总线和采样总线等动作要在15μs内完成。
温度转换和读温度时序:
四、驱动程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DS18B20_MAJOR 200
#define DEVICE_NAME "ds18b20"
#define DATA_IO S3C2410_GPG(0)
#define DATA_OUT S3C2410_GPIO_OUTPUT
#define DATA_IN S3C2410_GPIO_INPUT
#define LEVEL_HIGHT 1
#define LEVEL_LOW 0
#define
PULL_UP 1
#define PULL_NULL 0
#define index 0
int init_ds18b20(void);
unsigned char read_byte(void);
void write_byte(unsigned char data);
struct ds18b20_cdev{
struct cdev cdev;
};
struct ds18b20_cdev *ds18b20_char_dev;
int init_ds18b20(void)
{
int
get_data=0x01;
s3c2410_gpio_cfgpin(DATA_IO,DATA_OUT);
s3c2410_gpio_pullup(DATA_IO,PULL_UP);
s3c2410_gpio_setpin(DATA_IO,LEVEL_LOW);
udelay(520);
s3c2410_gpio_setpin(DATA_IO,LEVEL_HIGHT);
udelay(80);
s3c2410_gpio_cfgpin(DATA_IO,DATA_IN);
s3c2410_gpio_pullup(DATA_IO,PULL_NULL);
get_data=s3c2410_gpio_getpin(DATA_IO);
udelay(200);
s3c2410_gpio_cfgpin(DATA_IO,DATA_OUT);
s3c2410_gpio_pullup(DATA_IO,PULL_UP);
return
get_data;
}
void write_byte(unsigned char data)
{
unsigned
char Data,i;
Data=data;
s3c2410_gpio_pullup(DATA_IO,PULL_UP);
for(i=0;i<8;i++)
{
s3c2410_gpio_setpin(DATA_IO,LEVEL_LOW);
udelay(2);
if((Data&0x01)==0x01)
{
s3c2410_gpio_setpin(DATA_IO,LEVEL_HIGHT);
}
udelay(60);
Data= Data>>1;
s3c2410_gpio_setpin(DATA_IO,LEVEL_HIGHT);
}
}
unsigned char read_byte(void)
{
unsigned char data=0,i;
for(i=0;i<8;i++)
{
s3c2410_gpio_setpin(DATA_IO,LEVEL_LOW);
udelay(2);
s3c2410_gpio_setpin(DATA_IO,LEVEL_HIGHT);
udelay(20);
s3c2410_gpio_cfgpin(DATA_IO,DATA_IN);
s3c2410_gpio_pullup(DATA_IO,PULL_NULL);
if(s3c2410_gpio_getpin(DATA_IO))
{
data=data|0x80;
}
data=data>>1;
udelay(50);
s3c2410_gpio_cfgpin(DATA_IO,DATA_OUT);
s3c2410_gpio_pullup(DATA_IO,PULL_UP);
s3c2410_gpio_setpin(DATA_IO,LEVEL_HIGHT);
udelay(1);
}
s3c2410_gpio_cfgpin(DATA_IO,DATA_OUT);
s3c2410_gpio_pullup(DATA_IO,PULL_UP);
s3c2410_gpio_setpin(DATA_IO,LEVEL_HIGHT);
return data;
}
static ssize_t temper_read(struct file *filep,char __user
*buf,size_t count,loff_t *f_pos)
{
int
check;
char
result[2];
unsigned
long error;
check=
init_ds18b20();
if((check&0x01)==0x01)
{
printk("\n Warning : Fail the init ds18b20 ");
return -1; }
write_byte(0xcc);
write_byte(0x44);
udelay(500);
init_ds18b20();
write_byte(0xcc);
write_byte(0xbe);
result[0]= read_byte();
result[1]= read_byte();
error=copy_to_user(buf,result,sizeof(result));
if(!error)
{
return 0;
}
else
return min(sizeof(result),count);
}
static int ds18b20_open(struct inode *inode,struct file
*filep)
{
unsigned char flag;
flag=init_ds18b20();
if(flag)
{
printk("\n warning:Fail the init ds18b20 \n");
return -1; }
else
printk("\n open:successful");
return 0;
}
static struct file_operations ds18b20_fops={
.open=ds18b20_open,
.owner=THIS_MODULE,
.read=temper_read,
};
static void ds18b20_setup_cdev(void)
{
int error;
dev_t dev_num;
dev_num=MKDEV(DS18B20_MAJOR,index);
cdev_init(&ds18b20_char_dev->cdev,&ds18b20_fops);
ds18b20_char_dev->cdev.owner=THIS_MODULE;
ds18b20_char_dev->cdev.ops=&ds18b20_fops;
error=cdev_add(&ds18b20_char_dev->cdev,dev_num,1);
if(error)
{
printk("error:add the ds18b20 driver \n %d,%d",error,index);
} }
static int __init ds18b20_init(void)
{
int
error;
dev_t
dev_num;
dev_num=MKDEV(DS18B20_MAJOR,index);
if(dev_num)
{
error=register_chrdev_region(dev_num,0,DEVICE_NAME);
}
else
{
error=alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME);
}
if(error<0)
{
return -1;
}
ds18b20_char_dev=kmalloc(sizeof(struct
ds18b20_cdev),GFP_KERNEL);
if(!ds18b20_char_dev)
{
goto delete_error;
}
memset(ds18b20_char_dev,0,sizeof(struct ds18b20_cdev));
ds18b20_setup_cdev();
return 0;
delete_error:
unregister_chrdev_region(dev_num,1);
return error;
}
static void __exit ds18b20_exit(void)
{
dev_t
dev_num;
dev_num=MKDEV(DS18B20_MAJOR,index);
cdev_del(&ds18b20_char_dev->cdev);
kfree(ds18b20_char_dev);
unregister_chrdev_region(dev_num,1);
}
module_init(ds18b20_init);
module_exit(ds18b20_exit);
Makefile文件:
1 obj-m := ds18b20.o
2 CC = arm-linux-gcc
3 KDIR := /opt/linux-2.6.32.2
4 PWD := $(shell pwd)
5 default:
6 $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
7 clean:
8 rm -rf *.o
9 rm -rf *.ko
10 rm -rf .*.cmd
11 rm -rf *.mod.*
五、上层应用程序
#include
#include
#include
#include
void udelay(unsigned int time)
{
int i,j;
for(i=0;i
{
for(j=0;j<50000;j++);
}
}
int main()
{
int fd,value=0;
float temper=0;
unsigned char flag=0;
char result[2];
fd=open("/dev/ds18b20",0);
if(fd<0)
{
printf("\n error:the fail open document");
return -1;
}
while(1)
{
read(fd,result,sizeof(result));
value=result[1];
value=(value<<8)|result[0];
if((result[1]&0xf0)==0x0f)
{
value=~value+1; flag=1;
} temper=(float)value*0.0625;
printf("\n The temper is:%f",temper);
udelay(50);
}
}
Makefile:
1 CC:= arm-linux-gcc
2
3 ds18b20_app:ds18b20_app.o
4 $(CC) -o ds18b20_app ds18b20_app.c
5
6 clean:
7 rm -rf ds18b20_*.o*~