DS18B20驱动编写–杂项设备框架注册
设备驱动最通俗的解释就是“驱使硬件设备行动”。驱动与底层硬件直接打交道,按照硬件设备的具体工作方式,读写设备的寄存器,完成设备的轮询、中断处理、DMA通信,进行物理内存向虚拟内存的映射等,最终让通信设备能收发数据,让显示设备能显示文字和画面,让存储设备能记录文件和数据。
驱动程序是应用层和硬件层的连接桥梁,应用层只管完成应用逻辑开发和界面设计,驱动层则处理硬件配置,实现应用层相关接口函数。
杂项设备:字符设备类的一种,杂项设备主设备号为10。
1.DS18B20简介
DS18B20是Dallas半导体公司生产的数字温度传感器,是世界上第一片支持"一线总线"接口的温度传感器。测量温度范围为-55℃ ~ +125℃,精度为±0.5℃。分辨率为9 ~ 12位。支持3V ~ 5.5V输入电压。抗干扰能力强。
每一个DSl820包括一个唯一的64位长的序号,该序号值存放在 DSl820 内部的 ROM(只读存贮器)中。开始8位是产品类型编码(DSl820 编码均为 10H) ,接着的 48位是每个器件唯一的序号,最后 8 位是前面 56 位的CRC(循环冗余校验)码。
引脚 | 说明 |
GND | 地 |
DQ | 数字信号脚 |
VDD | 电源脚3V~5.5V |
DS18B20以9位数字量形式反应器件的温度值。
DS18B20采用单总线通讯,与CPU之间只需要DQ脚相连,再和CPU之间共地即可。每一个DS18B20都有唯一的64位光刻ROM,因此可以在一根数据线上接多个DS18B20模块。
- 单总线协议特性
- 总线协议:一个数据线可挂载多个设备(DS18B20通过64位光刻ROM区分设备);
- 半双工通讯:数据线上同一时间只能发送或者接收数据;
2.DS18B20驱动时序
2.1 发送复位脉冲和检测存在信号
DS18B20初始化过程首先需要发送复位脉冲:至少480us的低电平信号。接下来释放总线,DS18B20开始返回存在信号:60~240us的低电平。最后释放总线,模块初始化完成。
/*发送复位信号,检测存在脉冲*/
static u8 ds18b20_CheckRst(void)
{
u8 time=0;
DS18B20_OUT_MODE();/*输出模式*/
DS18B20_OUT(0);/*总线拉低*/
udelay(600);/*至少480us低电平*/
DS18B20_OUT(1);/*释放总线,恢复为空闲电平*/
udelay(15);
DS18B20_INPUT_MODE();/*输入模式*/
while(DS18B20_IN)
{
time++;
udelay(1);
if(time>=100)return 1;/*等待存在脉冲失败*/
}
time=0;
while(!DS18B20_IN)
{
time++;
udelay(1);
if(time>=250)return 2;//模块出错
}
return 0;
}
2.2 写一位数据时序
要实现写一字节数据,则首先要实现的是写一位数据时序。分为写1和写0。首先是总线拉低,产生写间隙(至少1us)。接着往数据线DQ上写入0或者1,周期时间为60us,最后释放总线(总线拉高,至少1us),至此,写数据完成。
DS18B20_OUT_MODE();/*输出模式*/
DS18B20_OUT(0);//总线拉低,产生写间隙时间
udelay(2);
if(dat&0x01)DS18B20_OUT(1);
else DS18B20_OUT(0);
udelay(60);//写周期时间
DS18B20_OUT(1);//释放总线
udelay(2);
dat>>=1;//继续发送下一位数据
2.3 读一位数据时序
读数据首先需要主机产生读间隙:总线拉低,至少1us的低电平信号。接着释放总线,在15us内进行数据读取,读数据周期时间为60us,最后释放总线:总线拉高,至少1us时间。 至此,读一位数据完成。
DS18B20_OUT_MODE();/*输出模式*/
DS18B20_OUT(0);//总线拉低,产生读间隙时间
udelay(2);
DS18B20_INPUT_MODE();//配置为输入模式
udelay(12);//等待数据到来
data>>=1;
if(DS18B20_IN)data|=0x80;
udelay(50);//读数据时间
DS18B20_OUT(1);//恢复总线为空闲电平
udelay(2);
3.DS18B20相关命令
- 跳转指令0xCC
这条指令允许控制器不需要提供64位光刻ROM就使用存储器操作命令,在总线上仅有一个DS18B20时使用,若有多个则会产生冲突。
- 启动一次温度转换0x44
此命令完成一次温度转换。执行此命令后,DS18B20保持等待状态。若总线在这条命令发送后跟着读间隙,而DS18B20正处于数据转换,则会输出一个0,若温度转换完成,则会输出1。若使用寄生电源,总线必须在这条命令发完后拉高总线,保存500ms。
- 读取一次数据0xBE
此命令用于读取暂存器中的内容,可连续读取9个字节数据。若只想读取温度数据,则只需要读取前两个字节即可。
- 读ROM 0x33
此命令可以读取DS18B20的64位光刻ROM数据,此命令仅能在总线上一个设备的时候使用。
- 匹配ROM 0x55
此命令可以实现和DS18B20的ROM进行匹配,只有和DS1820的64位光刻ROM完全匹配才能响应后面存储器命令。此命令用于当总线上不止一个设备时使用。
- 搜索ROM 0xF0
当系统第一次启动时,无法确认总线上有多少个设备或者该设备的光刻ROM,搜索光刻ROM可以让控制器通过排除法识别总线上的所有设备的64位光刻ROM。
4.DS18B20采集一次温度步骤
采用外部电源供电,且总线上仅有一个DS18B20模块。
5.编写DS18B20驱动,通过杂项设备注册
- 开发平台
开发平台:Ubuntu18.04
编译器:arm-linux-gcc
硬件平台:tiny4412基于Cortex-A9 4核1.5GHZ
开发板内核:Linux3.5
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static unsigned int ds18b20_gpio=EXYNOS4_GPB(4);//GPB_4
#define DS18B20_OUT_MODE() s3c_gpio_cfgpin(ds18b20_gpio,S3C_GPIO_OUTPUT)/*输出模式*/
#define DS18B20_INPUT_MODE() s3c_gpio_cfgpin(ds18b20_gpio,S3C_GPIO_INPUT)/*输入模式*/
#define DS18B20_OUT(x) gpio_set_value(ds18b20_gpio,(x))
#define DS18B20_IN gpio_get_value(ds18b20_gpio)
/*发送复位信号,检测存在脉冲*/
static u8 ds18b20_CheckRst(void)
{
u8 time=0;
DS18B20_OUT_MODE();/*输出模式*/
DS18B20_OUT(0);/*总线拉低*/
udelay(600);/*至少480us低电平*/
DS18B20_OUT(1);/*释放总线,恢复为空闲电平*/
udelay(15);
DS18B20_INPUT_MODE();/*输入模式*/
while(DS18B20_IN)
{
time++;
udelay(1);
if(time>=100)return 1;/*等待存在脉冲失败*/
}
time=0;
while(!DS18B20_IN)
{
time++;
udelay(1);
if(time>=250)return 2;//模块出错
}
return 0;
}
/*写一个字节函数*/
static void ds18b20_writeDat(u8 dat)
{
int i=0;
DS18B20_OUT_MODE();/*输出模式*/
for(i=0;i<8;i++)
{
DS18B20_OUT(0);//总线拉低,产生写间隙时间
udelay(2);
if(dat&0x01)DS18B20_OUT(1);
else DS18B20_OUT(0);
udelay(60);//写周期时间
DS18B20_OUT(1);//释放总线
udelay(2);
dat>>=1;//继续发送下一位数据
}
}
/*读取1字节数据*/
static u8 ds18b20_readDat(void)
{
int i=0;
u8 data=0;
for(i=0;i<8;i++)
{
DS18B20_OUT_MODE();/*输出模式*/
DS18B20_OUT(0);//总线拉低,产生读间隙时间
udelay(2);
DS18B20_INPUT_MODE();//配置为输入模式
udelay(12);//等待数据到来
data>>=1;
if(DS18B20_IN)data|=0x80;
udelay(50);//读数据时间
DS18B20_OUT(1);//恢复总线为空闲电平
udelay(2);
}
return data;
}
/*获取一次温度数据*/
static u16 ds18b20_GetTemp(void)
{
u8 L,H;
u16 temp;
if(ds18b20_CheckRst())return 0xffff;
ds18b20_writeDat(0xcc);
ds18b20_writeDat(0x44);
while(ds18b20_readDat()!=0xff);/*等待温度转换完成*/
if(ds18b20_CheckRst())return 0xffff;
ds18b20_writeDat(0xcc);
ds18b20_writeDat(0xbe);/*读取一次温度*/
L=ds18b20_readDat();
H=ds18b20_readDat();
temp=H<<8|L;
return temp;
}
static int ds18b20_open(struct inode *inode, struct file *file)
{
printk("open函数调用成功\n");
if(ds18b20_CheckRst())
{
printk("DS18B20初始化失败\n");
}
return 0;
}
static int ds18b20_release(struct inode *inode, struct file *file)
{
printk("release函数调用成功");
return 0;
}
long ds18b20_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int dir=_IOC_DIR(cmd);/*数据读写方向,00无参数,10用户层读,01用户层写,11可读写*/
int type=_IOC_TYPE(cmd);/*魔术,标志符*/
int size=_IOC_SIZE(cmd);/*arg的字节数*/
printk("dir=%d,type=%c,size=%d\n",dir,type,size);
int ret;
u16 temp=ds18b20_GetTemp();/*获取一次温度*/
ret=copy_to_user((void *)arg, &temp,size);
return 4-ret;
}
static struct file_operations ds18b20_fops=
{
.open =ds18b20_open,
.release =ds18b20_release,
.unlocked_ioctl =ds18b20_ioctl
};
/*杂项设备结构体*/
static struct miscdevice ds18b20_drv=
{
.minor =MISC_DYNAMIC_MINOR,/*255,有内核自动分配*/
.name ="ds18b20",//设备节点名字
.fops =&ds18b20_fops,//文件操作集合
};
static int __init wbyq_ds18b20_init(void)
{
/*1.GPIO注销*/
gpio_free(ds18b20_gpio);
/*2.注册GPIO*/
gpio_request(ds18b20_gpio,"DS18B20");
/*配置GPIO模式*/
s3c_gpio_cfgpin(ds18b20_gpio,S3C_GPIO_OUTPUT);
gpio_set_value(ds18b20_gpio,1);/*上拉*/
/*注册杂项设备*/
misc_register(&ds18b20_drv);
return 0;
}
/*驱动释放*/
static void __exit wbyq_ds18b20_cleanup(void)
{
printk("驱动出口,驱动注销成功\n");
/*注销杂项设备*/
misc_deregister(&ds18b20_drv);
/*注销GPIO*/
gpio_free(ds18b20_gpio);
}
module_init(wbyq_ds18b20_init);//驱动入口函数
module_exit(wbyq_ds18b20_cleanup);//驱动出口函数
MODULE_LICENSE("GPL");//驱动注册协议
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 ds18b20 Driver");
审核编辑:汤梓红
-
温度传感器
+关注
关注
48文章
2974浏览量
156333 -
DS18B20
+关注
关注
10文章
780浏览量
81060 -
设备驱动
+关注
关注
0文章
68浏览量
10921
发布评论请先 登录
相关推荐
评论