开发环境:
主机:Ubuntu12.04
开发板:RT5350
Openwrt:Openwrt15.05
1 硬件原理
下图是我们温度传感器的接入引脚,3.3V 供电,io 口接 P07的 GP0( GPIO0 的简称 )。
DS18B20 数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有 LTM8877,LTM8874 等等。主要根据应用场合的不同而改变其外观。封装后的 DS18B20 可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。
2 单总线的概念
目前常用的微机与外设之间进行数据传输的串行总线主要有 I2C 总线、 SPI 总线和 SCI总线。其中 I2C 总线以同步串行 2 线方式进行通信(一条时钟线,一条数据线) ,SPI 总线则以同步串行 3 线方式进行通信(一条时钟线,一条数据输入线,一条数据输出线),而 SCI 总线是以异步方式进行通信(一条数据输入线,一条数据输出线) 。这些总线至少需要两条或两条以上的信号线。
1-wire , 即 单 线 总 线 , 又 叫 单 总 线 。 近 年 来 , 美 国 的 达 拉 斯 半 导 体 公 司(DALLASSEMICONDUCTOR) 推出了一项特有的单总线(1-Wire Bus)技术。该技术与上述总线不同,它采用单根信号线,既可传输时钟,又能传输数据,而且数据传输是双向的,因而这种单总线技术具有线路简单,硬件开销少,成本低廉,便于总线扩展和维护等优点。
3 ds18b20 相关时序
- 初始化(复位)时序图:
(1) 先将数据线置高电平“ 1” 。
(2) 延时(该时间要求的不是很严格,但是尽可能的短一点)
(3) 数据线拉到低电平“ 0” 。
(4) 延时 750 微秒(该时间的时间范围可以从 480 到 960 微秒) 。
(5) 数据线拉到高电平“ 1” 。
(6) 延时等待(如果初始化成功则在 15 到 60 微秒时间之内产生一个由 DS18B20 所
返回的低电平“ 0” 。据该状态可以来确定它的存在,但是应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时控制) 。
(7) 若 CPU 读到了数据线上的低电平“ 0”后,还要做延时,其延时的时间从发出的高电平算起(第(5)步的时间算起)最少要 480 微秒。
(8) 将数据线再次拉高到高电平“ 1”后结束。
- 写 ds18b20 时序图:
(1) 数据线先置低电平“ 0” 。
(2) 延时确定的时间为 15 微秒。
(3) 按从低位到高位的顺序发送字节(一次只发送一位) 。
(4) 延时时间为 45 微秒。
(5) 将数据线拉到高电平。
(6) 重复上(1)到(6)的操作直到所有的字节全部发送完为止。
(7) 最后将数据线拉高。
- 读 ds18b20 时序图:
(1)将数据线拉高“ 1” 。
(2)延时 2 微秒。
(3)将数据线拉低“ 0” 。
(4)延时 3 微秒。
(5)将数据线拉高“ 1” 。
(6)延时 5 微秒。
(7)读数据线的状态得到 1 个状态位,并进行数据处理。
(8)延时 60 微秒。
4 驱动程序
关于字符设备驱动程序的使用,我们可以参照点亮 led 灯的那个实验,这里只给出跟ds18b20 密切相关的驱动程序,详细的程序请查看我们的驱动文件!
//配置连接温度传感器的引脚
#define DS18B20_L *GPIO21_0_DATA &= ~(1< < 0) //低电平
#define DS18B20_H *GPIO21_0_DATA |= (1< < 0) //高电平
#define DS18B20_OUT *GPIO21_0_DIR |= (1< < 0) //输出
#define DS18B20_IN *GPIO21_0_DIR &= ~(1< < 0) //输入
#define DS18B20_STA *GPIO21_0_DATA & 0x01
//寄存器定义
volatile unsigned long *GPIO21_0_DIR;
volatile unsigned long *GPIO21_0_DATA;
/**************** 基本定义 **********************/
//初始化函数必要资源定义
//用于初始化函数当中
//device number;
dev_t dev_num;
//struct dev
struct cdev ds18b20_cdev;
//auto "mknode /dev/ds18b20 c dev_num minor_num"
struct class *ds18b20_class = NULL;
struct device *ds18b20_device = NULL;
/******************** ds18b20有关的函数 ****************************/
//复位ds18b20传感器
static unsigned char ds18b20_reset(void)
{
unsigned char ret = 0;
unsigned char count = 0;
DS18B20_OUT;
DS18B20_H;
udelay(100);
DS18B20_L;
udelay(600);
DS18B20_H;
udelay(45);
DS18B20_IN;
do
{
ret = DS18B20_STA;
udelay(1);
count++;
}
while(ret != 0 && count< 50);
DS18B20_OUT;
udelay(400);
DS18B20_H;
return ret;
}
//从ds18b20读取一个字节
static unsigned char read_byte(void)
{
unsigned char i,byte=0;
DS18B20_OUT;
DS18B20_H;
udelay(100);
for(i = 0; i< 8; i++)
{
byte > >= 1;
DS18B20_L;
udelay(4);
DS18B20_H;
udelay(2);
if(DS18B20_STA == 1)
byte |= 0x80;
udelay(10);
}
return byte;
}
//向ds18b20写入一个字节
static unsigned char write_byte(unsigned char byte)
{
unsigned char i;
DS18B20_OUT;
DS18B20_H;
udelay(100);
for(i = 0; i< 8; i++)
{
DS18B20_L;
if( byte & 0x01 )
DS18B20_H;
else
DS18B20_L;
udelay(40);
DS18B20_H;
byte > >= 1;
}
udelay(10);
}
//从ds18b20中读出温度数据
static unsigned int read_temp(void)
{
unsigned int t = 0 , l = 0;
if(ds18b20_reset())
{
printk("step1,reset_ds18b20 error!n");
return 0;
}
write_byte(0xcc);
write_byte(0x44);
udelay(4);
if(ds18b20_reset())
{
printk("step2,reset_ds18b20 error!n");
return 0;
}
write_byte(0xcc);
write_byte(0xbe);
l = read_byte();
t = read_byte();
t < <= 8;
t += l;
return t;
}
/**********************************************************************/
/**************** 结构体 file_operations 成员函数 *****************/
//open
static int ds18b20_open(struct inode *inode, struct file *file)
{
printk("ds18b20 drive open...n");
DS18B20_OUT; //初始化该引脚为输出;
return 0;
}
//close
static int ds18b20_close(struct inode *inode , struct file *file)
{
return 0;
}
//read
static ssize_t ds18b20_read(struct file *file, char __user *buffer,
size_t len, loff_t *pos)
{
unsigned int temp;
printk("ds18b20 drive read...n");
temp = read_temp();
copy_to_user(buffer, &temp, 4);
return 4;
}
/***************** 结构体: file_operations ************************/
//struct
static const struct file_operations ds18b20_fops = {
.owner = THIS_MODULE,
.open = ds18b20_open,
.release = ds18b20_close,
.read = ds18b20_read,
};
/************* functions: init , exit*******************/
//条件值变量,用于指示资源是否正常使用
unsigned char init_flag = 0;
unsigned char add_code_flag = 0;
//init
static __init int ds18b20_init(void)
{
int ret_v = 0;
printk("ds18b20 drive init...n");
//函数alloc_chrdev_region主要参数说明:
//参数2: 次设备号
//参数3: 创建多少个设备
if( ( ret_v = alloc_chrdev_region(&dev_num,0,1,"ds18b20") ) < 0 )
{
goto dev_reg_error;
}
init_flag = 1; //标示设备创建成功;
printk("The drive info of ds18b20:nmajor: %dnminor: %dn",
MAJOR(dev_num),MINOR(dev_num));
cdev_init(&ds18b20_cdev,&ds18b20_fops);
if( (ret_v = cdev_add(&ds18b20_cdev,dev_num,1)) != 0 )
{
goto cdev_add_error;
}
ds18b20_class = class_create(THIS_MODULE,"ds18b20");
if( IS_ERR(ds18b20_class) )
{
goto class_c_error;
}
ds18b20_device = device_create(ds18b20_class,NULL,dev_num,NULL,"ds18b20");
if( IS_ERR(ds18b20_device) )
{
goto device_c_error;
}
printk("auto mknod success!n");
//------------ 请在此添加您的初始化程序 --------------//
GPIO21_0_DATA = (volatile unsigned long *)ioremap(0x10000620, 4);
GPIO21_0_DIR = (volatile unsigned long *)ioremap(0x10000624, 4);
//如果需要做错误处理,请:goto ds18b20_error;
add_code_flag = 1;
//---------------------- END ---------------------------//
goto init_success;
dev_reg_error:
printk("alloc_chrdev_region failedn");
return ret_v;
cdev_add_error:
printk("cdev_add failedn");
unregister_chrdev_region(dev_num, 1);
init_flag = 0;
return ret_v;
class_c_error:
printk("class_create failedn");
cdev_del(&ds18b20_cdev);
unregister_chrdev_region(dev_num, 1);
init_flag = 0;
return PTR_ERR(ds18b20_class);
device_c_error:
printk("device_create failedn");
cdev_del(&ds18b20_cdev);
unregister_chrdev_region(dev_num, 1);
class_destroy(ds18b20_class);
init_flag = 0;
return PTR_ERR(ds18b20_device);
//------------------ 请在此添加您的错误处理内容 ----------------//
ds18b20_error:
add_code_flag = 0;
return -1;
//-------------------- END -------------------//
init_success:
printk("ds18b20 init success!n");
return 0;
}
//exit
static __exit void ds18b20_exit(void)
{
printk("ds18b20 drive exit...n");
if(add_code_flag == 1)
{
//---------- 请在这里释放您的程序占有的资源 ---------//
printk("free your resources...n");
iounmap(GPIO21_0_DATA);
iounmap(GPIO21_0_DIR);
printk("free finishn");
//---------------------- END -------------------//
}
if(init_flag == 1)
{
//释放初始化使用到的资源;
cdev_del(&ds18b20_cdev);
unregister_chrdev_region(dev_num, 1);
device_unregister(ds18b20_device);
class_destroy(ds18b20_class);
}
}
/**************** module operations**********************/
//module loading
module_init(ds18b20_init);
module_exit(ds18b20_exit);
//some infomation
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("from Jafy");
MODULE_DESCRIPTION("ds18b20 drive");
5 应用程序
int main(int argc, char **argv)
{
int fd;
float t;
unsigned int tmp = 0;
//打开温度传感器驱动模块
fd = open("/dev/ds18b20", O_RDWR | O_NONBLOCK);
if (fd < 0)
{
printf("can't open!n");
return -1;
}
read(fd, &tmp, sizeof(tmp));
t = tmp * 0.0625;
printf("the current temperature is %fn",t);
close(fd);
return 0;
}
编译模块驱动,不熟悉的朋友可看LED驱动相关。
$make package/kernel/ds18b20/compile V=99
编译模块驱动和应用程序
$make package/ds18b20_app/compile V=99
$make package/ds18b20_app/install V=99
$make package/index V=99
复制文件传给开发板测试
6 实验结果
审核编辑:汤梓红
-
温度传感器
+关注
关注
48文章
2902浏览量
155868 -
DS18B20
+关注
关注
10文章
778浏览量
80680 -
引脚
+关注
关注
16文章
1179浏览量
50254 -
开发板
+关注
关注
25文章
4933浏览量
97157 -
OpenWrt
+关注
关注
10文章
127浏览量
39261
发布评论请先 登录
相关推荐
评论