鹿鼎记txt下载:DS18B20在linux下跑起来 - jammy
来源:百度文库 编辑:九乡新闻网 时间:2024/05/06 12:31:37
DS18B20在linux下跑起来
上次的让LED在linux下闪烁起来可算是困难重重,毕竟是刚入手。这次的DS18B20加载到linux同样是个探险之旅。在不断的摸索、尝试,最后还是有点小成果。现在写下笔记,希望能与同路人分享交流。
在加载到linux之前,我先确保DS18B20在无OS的环境下能正常工作,即“裸奔”。这个阶段也不是一路顺利,虽然以前有在单片机下驱动DS18B20的经验,但是在ARM延时确实是个问题。上网搜索一下,有的人用定时器延时,有的就直接程序耗时的方式延时。急于求成的我,为了避免使用定时器又出现新的麻烦,唯有使用后者的方法。好了,解决延时问题,DS18B20也自然运行起来,没有辜负我!哈~
“裸奔”成功之后,现在就要给DS18B20披上linux的大衣。这次同样是将它以字符型设备驱动。按上次驱动LED的过程照葫芦画瓢,一个驱动程序,一个测试程序。
驱动程序
驱动程序对比上次有所加深,多使用了几个系统调用函数。
open()函数,对设备特殊文件进行open()系统调用时,将调用驱动程序的open () 函数:
int (*open)(struct inode * ,struct file *);
其中参数inode为设备特殊文件的inode (索引结点) 结构的指针,参数file是指向这一设备的文件结构的指针。open()的主要任务是确定硬件处在就绪状态、验证次设备号的合法性(次设备号可以用MINOR(inode-> i - rdev) 取得)、控制使用设备的进程数、根据执行情况返回状态码(0表示成功,负数表示存在错误) 等。
read()函数。当对设备特殊文件进行read() 系统调用时,将调用驱动程序read() 函数:
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
来从设备中读取数据。当该函数指针被赋为NULL 值时,将导致read 系统调用出错并返回-EINVAL("Invalid argument,非法参数")。函数返回非负值表示成功读取的字节数(返回值为"signed size"数据类型,通常就是目标平台上的固有整数类型)。
release()函数,当最后一个打开设备的用户进程执行close ()系统调用时,内核将调用驱动程序的release () 函数:
void (*release) (struct inode * ,struct file *) ;
release 函数的主要任务是清理未结束的输入/输出操作、释放资源、用户自定义排他标志的复位等。
程序如下:
/************************************************************/
//文件名:ds18b20.c
//功能:linux下的ds18b20驱动程序
//使用说明: (1)
// (2)
// (3)
// (4)
//作者:jammy-lee
//日期:2009-03-31
/************************************************************/
//包含头文件
#include
#include
#include
#include
#include
#include
#include
#include
#inculde
#include
#include
#include
#include
#include
//DS18B20端口的定义
#define DQ_PIN S3C2410_GPG14
#define DQ_IN S3C2410_GPG14_INP
#define DQ_OUT S3C2410_GPG14_OUTP
#define DEVICE_NAME "DS18B20" //驱动设备的名称,可以使用命令 cat /proc/devices
#define DS18B20_MAJOR 182 //主设备号
//定义DS18B20端口控制
#define GPG_UP s3c2410_gpio_pullup(DQ_PIN, 1) //打开上拉电阻
#define GPG_DOWN s3c2410_gpio_pullup(DQ_PIN, 0) //关闭上拉电阻
#define DS18B20_L s3c2410_gpio_setpin(DQ_PIN, 0) //拉低数据线电平?
#define DS18B20_H s3c2410_gpio_setpin(DQ_PIN, 1) //拉高数据线电平
#define DS18B20_OUT s3c2410_gpio_cfgpin(DQ_PIN, DQ_OUT) //数据线设置为输出
#define DS18B20_IN s3c2410_gpio_cfgpin(DQ_PIN, DQ_IN) //数据线设置为输入
#define DS18B20_STU s3c2410_gpio_getpin(DQ_PIN) //数据状态
//定义DS18B20ROM指令
#define DS18B20_ReadROM 0x33 //读ROM
#define DS18B20_MatchROM 0x55 //匹配ROM
#define DS18B20_SkipROM 0xCC //跳过ROM
#define DS18B20_SearchROM 0xF0 //搜索ROM
#define DS18B20_AlarmROM 0xEC //报警搜索
//定义DS18B20存储器操作命令
#define DS18B20_WriteSCR 0x4E //写暂存存储器
#define DS18B20_ReadSCR 0xBE //读暂存存储器
#define DS18B20_CopySCR 0x48 //复制暂存存储器
#define DS18B20_ConvertTemp 0x44 //温度变换
#define DS18B20_RecallEP 0xB8 //重新调出
#define DS18B20_ReadPower 0xB4 //读电源
//定义类型
typedef unsigned char uint8 ;
typedef unsigned int uint16 ;
//全局变量
uint8 opencount = 0;
//函数声明
uint8 Init_DS18B20(void); //初始化DS18B20
uint8 DS18B20_ReadByte(void); //读取DS18B20一字节
void DS18B20_WriteByte(uint8 Da
void DS18B20_ReadID(void); //读取DS18B20的ID
void DS18B20_Match(void); //匹配DS18B20
uint16 DS18B20_Temperature(void); //单个DS18B20温度读取
uint16 nDS18B20_Temperature(void); //读取多个DS18B20的温度?
uint8 DS18B20_ID[8] = {0};
//初始化DS18B20
uint8 Init_DS18B20(void)
{
uint8 errTime;
DS18B20_OUT;
DS18B20_H;
DS18B20_L; //初始化发送一复位脉冲
udelay(500); //脉冲时间大于480us
DS18B20_H;
DS18B20_IN;
udelay(80);
while(DS18B20_STU)
{
udelay(6); //5.15us
errTime++;
if(errTime>20)
return 0; ///如果等带大于约 5.15us*20就返回0x00,报告复位失败(实际上只要等待15-60us)
}
errTime=0;
while(!(DS18B20_STU))
{
udelay(6); //5.15us
errTime++;
if(errTime>50)
return 0; //如果等带大于约 5.15us*50就返回0x00,报告复位失败(实际上只要等待60-240us)
}
return 0xff;
}
//读取DS18B20一字节
uint8 DS18B20_ReadByte(void)
{
uint8 i;
uint8 temp = 0;
DS18B20_IN;
//asm("nop");
for(i=0;i<8;i++)
{
temp >>= 1; //向右移动一位;
DS18B20_OUT;
DS18B20_L;
udelay(8);
DS18B20_H;
DS18B20_IN; //释放总线
if(DS18B20_STU)
temp |= 0x80;
udelay(32);
DS18B20_OUT;
DS18B20_H;
//delay_nus(32);
}
udelay(5);
return (temp);
}
//写入DS18B20一字节
void DS18B20_WriteByte(uint8 Da
{
uint8 i;
uint8 temp;
DS18B20_IN;
//asm("nop");
for(i=0;i<8;i++)
{
DS18B20_OUT;
DS18B20_L;
udelay(4);
temp = Da
temp &= 0x01;
if(temp)
DS18B20_H;
else
DS18B20_L;
udelay(50);
DS18B20_H;
udelay(4);
}
//DS18B20_H;
}
//读取DS18B20的ID
void DS18B20_ReadID(void)
{
udelay(1);
Init_DS18B20();
DS18B20_WriteByte(DS18B20_ReadROM);
DS18B20_ID[0] = DS18B20_ReadByte();
DS18B20_ID[1] = DS18B20_ReadByte();
DS18B20_ID[2] = DS18B20_ReadByte();
DS18B20_ID[3] = DS18B20_ReadByte();
DS18B20_ID[4] = DS18B20_ReadByte();
DS18B20_ID[5] = DS18B20_ReadByte();
DS18B20_ID[6] = DS18B20_ReadByte();
DS18B20_ID[7] = DS18B20_ReadByte();
}
//匹配DS18B20
void DS18B20_Match(void)
{
DS18B20_WriteByte(DS18B20_MatchROM);
DS18B20_WriteByte(DS18B20_ID[0]);
DS18B20_WriteByte(DS18B20_ID[1]);
DS18B20_WriteByte(DS18B20_ID[2]);
DS18B20_WriteByte(DS18B20_ID[3]);
DS18B20_WriteByte(DS18B20_ID[4]);
DS18B20_WriteByte(DS18B20_ID[5]);
DS18B20_WriteByte(DS18B20_ID[6]);
DS18B20_WriteByte(DS18B20_ID[7]);
}
//单个DS18B20温度读取
uint16 DS18B20_Temperature(void)
{
uint8 flag = 0;
uint8 tempH = 0;
uint8 tempL = 0;
uint16 temp = 0;
flag = Init_DS18B20();
if(flag == 0x00)
return -1;
DS18B20_WriteByte(DS18B20_SkipROM);
DS18B20_WriteByte(DS18B20_ConvertTemp);
flag = Init_DS18B20();
if(flag == 0x00)
return -1;
DS18B20_WriteByte(DS18B20_SkipROM);
DS18B20_WriteByte(DS18B20_ReadSCR);
tempL = DS18B20_ReadByte();
tempH = DS18B20_ReadByte();
temp = (tempH<<8) | tempL;
temp = temp * 0.625 *10;
return temp;
}
//读取多个DS18B20的温度
uint16 nDS18B20_Temperature(void)
{
uint8 tempH = 0;
uint8 tempL = 0;
uint16 temp = 0;
udelay(1000);
Init_DS18B20();
DS18B20_Match();
udelay(30000);
DS18B20_WriteByte(DS18B20_ConvertTemp);
Init_DS18B20();
DS18B20_Match();
DS18B20_WriteByte(DS18B20_ReadSCR);
tempL = DS18B20_ReadByte();
tempH = DS18B20_ReadByte();
temp = (tempH<<8) | tempL;
temp = temp * 0.625 *10;
return temp;
}
//write()系统调用函数
static ssize_t ds18b20_write(struct file *filp, const char *buffer,
size_t count, loff_t *ppos)
{
return 1;//返回一个数
}
//read()系统调用函数
static ssize_t ds18b20_read(struct file *filp, char *buffer,
size_t count, loff_t *ppos)
{
uint16 tmp;
tmp = DS18B20_Temperature();
copy_to_user(buffer, &temp, 1); //将读取得的DS18B20数值复制到用户区
return 1;
}
//open()系统调用函数
static int ds18b20_open(struct inode *node, struct file *file)
{
uint8 flag = 0;
if(opencount == 1)
return -EBUSY;
flag = Init_DS18B20(); //获取初始数值
if(flag == 0) //初始化失败
{
printk("uable to open device!\n");
return -1;
}
else //初始化成功
{
opencount++;
printk("device opened!\n");
return 0;
}
}
//release()系统调用函数
static int ds18b20_release(struct inode *node, struct file *file)
{
opencount--;
printk("device released!\n");
return 0;
}
// 这个结构是字符设备驱动程序的核心
//当应用程序操作设备文件时所调用的open、read、write,release等函数,
//最终会调用这个结构中指定的对应函数
static struct file_operations ds18b20_fops = {
.owner = THIS_MODULE,
.open = ds18b20_open,
.write = ds18b20_write,
.read = ds18b20_read,
.release = ds18b20_release,
};
//执行“insmod ds18b20.ko”命令时就会调用这个函数
static int __init ds18b20_init(void)
{
int ret;
printk("Initial driver for ds18b20......................\n");
ret = register_chrdev(DS18b20_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
if (ret < 0)
{
printk(DEVICE_NAME " can't register major number\n");
return ret;
}
else
{
prink("DS18B20 register success");
}
}
//执行“rmmod ds18b20.ko”命令时就会调用这个函数
void __exit ds18b20_exit(void)
{
unregister_chrdev(&DS18B20_MAJOR);
prink("DS18B20 unregister success");
}
module_init(ds18b20_init);
module_exit(ds18b20_exit);
MODULE_AUTHOR("jammy_lee@163.com");
MODULE_DESCRIPTION("DS18B20 driver for TQ2440");
MODULE_LICENSE("GPL");
程序写好了,等待着编译的成功。可以命运总是爱戏弄我!
编译代码时出现的警告,加载到linux时候也是出现同样的警告,加载失败。哭~~~
*** Warning: "__fixunsdfsi" [drivers/char/ds18b20.ko] undefined!
*** Warning: "__muldf3" [drivers/char/ds18b20.ko] undefined!
*** Warning: "__adddf3" [drivers/char/ds18b20.ko] undefined!
*** Warning: "__floatsidf" [drivers/char/ds18b20.ko] undefined!
原因是," temp = temp *0.625*10; " ,有浮点数出现。可能没有包含linux运算浮点数的头文件,又或者其它原因,当务之急还是先走走捷径。
改为:
" temp = temp * 10 / 16 * 10 "
编译没有出现警告。
Yeah,成功了!!
测试程序
/************************************************************/
//文件名:test_ds18b20.c
//功能:测试linux下的ds18b20程序
//使用说明: (1)
// (2)
// (3)
// (4)
//作者:jammy-lee
//日期:2008-03-31
/************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd = -1;
char count = 5;
unsigned int tmp = 0;
fd = open("/dev/ds18b20", 0);
if(fd < 0)
{
perror("Can't open /dev/ds18b20 \n");
exit(1);
}
printf("open ds18b20 success \n");
while(count--)
{
read(fd, &tmp , sizeof(int));
printf("the currently temperature is %d \n",tmp);
}
}
终于,DS18B20在linux下准确地报告了它测得的温度!欣喜若狂!!
若有错误,希望贵人能指出!jammy感激万分