Linux驱动开发-编写DS18B20驱动

描述

【摘要】 当前文章介绍如何在Linux系统下编写一个DS18B20温度传感器驱动,测量环境温度,并将DS18B20注册成字符设备,通过文件接口将温度数据传递给应用层。

1. 前言

当前文章介绍如何在Linux系统下编写一个DS18B20温度传感器驱动,测量环境温度,并将DS18B20注册成字符设备,通过文件接口将温度数据传递给应用层。

当前使用的开发板是友善之臂的Tiny4412开发板,CPU是三星的Exynos-4412,主频是4核1.5GHZ,当前运行的Linux内核版本是3.5。使用的温度传感器是DS18B20,是一个数字温度传感器,非常经典的一款温度传感器,常年应用在各大高校毕设、实验室、毕设、课设场景。DS1820接线比较简单,只需要一根线就行,加上两根电源线,一共3根线,并且DS18B20支持硬件序列号寻址,支持一个IO口上挂载多个DS18B20。

2. DS18B20介绍

DS18B20特性:

(1)全数字温度转换及输出。
(2)先进的单总线数据通信。
(3)最高 12 位分辨率,精度可达土 0.5 摄氏度。
(4)12 位分辨率时的最大工作周期为 750 毫秒。
(5)可选择寄生工作方式。
(6)检测温度范围为–55° C ~+125° C (–67° F ~+257° F)
(7)内置 EEPROM,限温报警功能。
(8)64 位光刻 ROM,内置产品序列号,方便多机挂接。
(9)多样封装形式,适应不同硬件系统。

驱动

DS18B20引脚功能

GND 电压地 DQ 单数据总线 VDD 电源电压 NC 空引脚

DS18B20读取温度的步骤:

发送复位信号--> 检测回应信号---> 发送0xCC-->发送0x44-> 发送复位信号—> 检测回应信号—> 写0xcc---> 写0xbe---> 循环8次读取温度低字节---> 循环8次读取温度高字节----> 打印温度信息

DS18B20温度转换示例:

u16 temp; u8 TL,TH; u16 intT,decT; //温度值的整数和小数部分 TL=DS18B20_Read_Byte(); //读取温度低8位LSB TH=DS18B20_Read_Byte(); //读取温度高8位MSB temp=((u16)TH<<8)|TL; //将读出的温度高低位组合成16位的值 intT = temp >> 4; //分离出温度值整数部分 decT = temp & 0xF; //分离出温度值小数部分 printf("A: %d.%d\r\n",(int)intT,(int)decT); //打印实际温度值

3. 硬件接线图

Tiny4412开发板扩展GPIO口:

驱动 驱动 驱动

4. 示例代码

#include #include #include /*杂项字符设备头文件*/ #include /*文件操作集合*/ #include /*延时函数*/ #include #include /*DS18B20 GPIO接口: GPB_4*/ /*定义指针,用于接收虚拟地址*/ volatile unsigned int *DS18B20_GPBCON; volatile unsigned int *DS18B20_GPBDAT; #define DS18B20_INPUT() {*DS18B20_GPBCON &= ~(0xf << 4 * 4);} #define DS18B20_OUTPUT() {*DS18B20_GPBCON &= ~(0xf << 4 * 4);*DS18B20_GPBCON |= (0x1 << 4 * 4);} /* 函数功能:等待DS18B20的回应 返回1:未检测到DS18B20的存在 返回0:存在 */ unsigned char DS18B20_Check(void) { unsigned char retry=0; DS18B20_INPUT() ///SET PG11 INPUT while((*DS18B20_GPBDAT & (1 << 4))&&retry<200) { retry++; udelay(1); }; if(retry>=200)return 1; else retry=0; while(!(*DS18B20_GPBDAT & (1 << 4))&&retry<240) { retry++; udelay(1); }; if(retry>=240)return 1; return 0; } /* 从DS18B20读取一个位 返回值:1/0 */ unsigned char DS18B20_Read_Bit(void) // read one bit { unsigned char data; DS18B20_OUTPUT(); *DS18B20_GPBDAT &= ~(1 << 4);//输出0 udelay(2); *DS18B20_GPBDAT |= (1 << 4);//输出1 DS18B20_INPUT() udelay(12); if((*DS18B20_GPBDAT & (1 << 4)))data=1; else data=0; udelay(50); return data; } /* 从DS18B20读取一个字节 返回值:读到的数据 */ unsigned char DS18B20_Read_Byte(void) // read one byte { unsigned char i,j,dat; dat=0; for(i=1;i<=8;i++) { j=DS18B20_Read_Bit(); dat=dat>>1; if(j) //主机对总线采样的数 判断-------读数据-1就是1,否则就是0 dat|=0x80; //先收低位数据--一步一步向低位移动>> } return dat; } /* 写一个字节到DS18B20 dat:要写入的字节 */ void DS18B20_Write_Byte(unsigned char dat) { unsigned char j; unsigned char testb; DS18B20_OUTPUT(); for(j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if(testb) { *DS18B20_GPBDAT &= ~(1 << 4);//输出0// Write 1 udelay(2); *DS18B20_GPBDAT |= (1 << 4);//输出1 udelay(60); } else { *DS18B20_GPBDAT &= ~(1 << 4);//输出0// Write 0 udelay(60); *DS18B20_GPBDAT |= (1 << 4);//输出1 udelay(2); } } } /* 从ds18b20得到温度值 精度:0.1C 返回值:温度值 (-550~1250) */ short DS18B20_Get_Temp(void) { unsigned short aaa; unsigned char temp; unsigned char TL,TH; DS18B20_OUTPUT(); *DS18B20_GPBDAT &= ~(1 << 4);//输出0 //拉低DQ udelay(750); //拉低750us *DS18B20_GPBDAT |= (1 << 4);//输出1 //DQ=1 udelay(15); //15US DS18B20_Check(); DS18B20_Write_Byte(0xcc); DS18B20_Write_Byte(0x44); DS18B20_OUTPUT(); *DS18B20_GPBDAT &= ~(1 << 4);//输出0 //拉低DQ udelay(750); //拉低750us *DS18B20_GPBDAT |= (1 << 4);//输出1 //DQ=1 udelay(15); //15US DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip rom DS18B20_Write_Byte(0xbe);// convert TL=DS18B20_Read_Byte(); // LSB TH=DS18B20_Read_Byte(); // MSB aaa=((unsigned short)TH<<8)|TL; return aaa; } /* 杂项字符设备注册示例----->DS18B20 */ static int tiny4412_open(struct inode *my_inode, struct file *my_file) { /*映射物理地址*/ DS18B20_GPBCON=ioremap(0x11400040,4); DS18B20_GPBDAT=ioremap(0x11400044,4); printk("DS18B20初始化成功!\r\n"); /*设置ds18b20为输出模式*/ *DS18B20_GPBCON &= ~(0xf << 4 * 4); *DS18B20_GPBCON |= (0x1 << 4 * 4); return 0; } static int tiny4412_release(struct inode *my_inode, struct file *my_file) { /*释放虚拟地址*/ iounmap(DS18B20_GPBCON); iounmap(DS18B20_GPBDAT); printk("DS18B20释放成功\r\n"); return 0; } static ssize_t tiny4412_read(struct file *my_file, char __user *buf, size_t len, loff_t *loff) { /*读取温度信息*/ short temp=DS18B20_Get_Temp(); copy_to_user(buf,&temp,2); //拷贝温度至应用层 return 0; } static ssize_t tiny4412_write(struct file *my_file, const char __user *buf, size_t len, loff_t *loff) { return 0; } /*文件操作集合*/ static struct file_operations tiny4412_fops= { .open=tiny4412_open, .read=tiny4412_read, .write=tiny4412_write, .release=tiny4412_release }; /* 核心结构体 */ static struct miscdevice tiny4412_misc= { .minor=MISC_DYNAMIC_MINOR, /*自动分配次设备号*/ .name="DS18B20", /*设备文件,指定/dev/生成的文件名称*/ .fops=&tiny4412_fops }; static int __init DS18B20_dev_init(void) { /*杂项设备注册*/ misc_register(&tiny4412_misc); return 0; } static void __exit DS18B20_dev_exit(void) { /*杂项设备注销*/ misc_deregister(&tiny4412_misc); } module_init(DS18B20_dev_init); module_exit(DS18B20_dev_exit); MODULE_LICENSE("GPL");
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分