2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html
第二十五章 DS18B20数字温度传感器实验
DS18B20是常用的数字温度传感器,其输出数字信号来表示温度,具有体积小,硬件开销
低,抗干扰能力强,精度高的特点,又由于封装形式多样,适用于各种狭小空间设备数字测温
和控制领域,也可应用于锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各
种非极限温度场合。本章我们将使用FPGA开发板学习如何使用DS18B20进行温度测量。
本章包括以下几个部分:
25.1 温度传感器DS18B20简介
25.2 实验任务
25.3 硬件设计
25.4 程序设计
25.5 下载验证
温度传感器DS18B20简介
温度传感器(temperature transducer)是指能感受温度并转换成可用输出信号的传感器,
是各种传感器中最常用的一种。早期使用的是模拟温度传感器,如热敏电阻,随着环境温度的
变化,其阻值也随之发生变化,用处理器采集电阻两端的电压,然后根据给定的公式就可计算
出当前环境温度。随着科技的进步,现代的温度传感器已经走向数字化,外形小,接口简单,
广泛应用在生产实践的各个领域,为我们的生活提供便利。随着现代仪器的发展,微型化、集
成化、数字化正成为传感器发展的一个重要方向。美国DALLAS
半导体公司推出的数字化温度传
感器DS18B20采用单总线协议,即与FPGA接口仅需占用一个I/O端口,无须任何外部
元件,直接
将环境温度转化成数字信号,以数字码方式串行输出,从而大大简化了传感器与FPGA的接口设
计。
DS18B20测量温度范围为-55~+125℃,精度为±0.5℃。现场(实时)温度直接以“单总线”
的数字方式传输,大大提高了系统的抗干扰性。它能直接读出被测温度,并且可根据实际要求
通过简单的编程实现9~l2位的数字值读数方式。它工作在3~5.5V的电压范围,采用多种封装形
式,从而使系统设计灵活、方便,设定分辨率及用户设定的报警温度存储在EEPROM中,掉电后
依然保存。其内部结构如图 25.1.1所示:
图 25.1.1 DS18B20内部结构
DS18B20的内部结构主要由8部分组成:64位ROM和单线接口、存储器和控制逻辑、高速缓
存器、温度传感器、配置寄存器、高温触发器TH、低温触发器TL、8位CRC生成器。那么,FPGA
需要怎样控制才能让DS18B20工作并将温度数据读取出来呢?
首先我们来看一下操作DS18B20的命令:
DS18B20的命令分为两类,分别是ROM功能命令和RAM功能命令。ROM功能命令是对64位ROM
进行操作。64位ROM的具体内容如下图:
图 25.1.2 64位ROM内容
64位ROM中的序列号是出厂前被光刻好的,它可以看做该DS18B20的地址序列码。其各位排
列顺序是:开始8位为产品类型标号,接下来48位是该DS18B20自身的序列号,最后8位是前面
56位的CRC循环冗余校验码(CRC=X8+X5+X4+1)。光刻ROM的作用是使每一个DS18B20都各不相同,
这样就可以实现一条总线上挂接多个DS18B20的目的。与此对应的命令有如下5条:
1)
33H:读ROM
这个命令允许总线控制器(FPGA)读取DS18B20的8位系列编码、唯一的序列号和8位CRC码。
只有在总线上存在单只DS18B20的时候才能使用该命令。
2)
55H:匹配ROM
发出此命令之后,接着发出64位ROM编码,让总线控制器(FPGA)在多点总线上定位一只
特定的DS18B20。只有和64位ROM序列完全匹配的DS18B20才会做出响应。所有和64位ROM序列不
匹配的DS18B20都将等待复位脉冲。这条命令在总线上有单个或多个器件时都可以使用。
3)
CCH:跳过ROM
这条命令允许总线控制器(FPGA)不用提供64位ROM编码就进行下一步操作,在单点总线
(一个DS18B20)情况下可以节省时间。如果总线上不止一个从机,在跳过ROM命令之后跟着发
一条读命令,由于多个从机同时传送信号,总线上就会发生数据冲突(漏极开路上拉效果相当
于相与)。
4)
F0H:搜索ROM
当一个系统初次启动时,总线控制器可能并不知道总线上有多少器件或它们的64位ROM编
码。搜索ROM命令允许总线控制器用排除法识别总线上的所有DS18B20的64位编码。
5)
ECH:报警搜索命令
发出此命令后,只有温度超过设定值上限或下限的DS18B20才做出响应。要注意的是只要
DS18B20不掉电,报警状态将一直保持,直到再一次测得的温度值达不到报警条件为止。
下面介绍以上几条指令的用法。当主机需要对众多在线DS18B20中的某一个进行操作时,
首先应将主机逐个与DS18B20挂接,读出其序列号;然后再将所有的DS18B20挂接到总线上,主
机发出匹配ROM命令(55H)之后,主机紧接着提供的64位ROM编码(包括该DS18B20的48位序列号)
之后的操作就是针对该DS18B20。
如果主机只对一个DS18B20进行操作,就不需要读取ROM编码以及匹配ROM编码,只要用跳
过ROM(CCH命令),就可进行下一步对高速缓存器的操作。
主机发出对ROM的操作命令之后,就进一步发出对RAM的命令。这里的RAM主要是指高速缓
存器。我们先了解一下高速缓存器的数据结构,如下图所示:
图 25.1.3 高速缓存器的数据结构
由上图可知DS18B20的高速缓存器共有9个8位寄存器,其中温度数据低位(LSB)对应字节
地址0,温度数据高位(MSB)对应字节地址1,以此类推,配置寄存器的字节地址为4。温度数
据存放的格式如下图:
图 25.1.4 温度数据格式
DS18B20在出厂时默认配置温度数据为12位,其中最高位为符号位,即温度值共11位,最
低四位为小数位。FPGA在读取温度数据时,一次会读2字节共16位,读完后将低11位的二进制
数转化为十进制数后再乘以0.0625得到所测的实际温度值。另外还需要判断温度的正负,前5
个数字为符号位,这5位同时变化,我们只需要判断其中任何一位就可以了。前5位为1时,读
取的温度为负值,则测到的数值需要取反加1再乘以0.0625才可得到实际温度值。前5位为0时,
读取的温度为正值,只要将测得的数值乘以0.0625即可得到实际温度值。
了解了高速缓存器的数据结构后,就可以用命令控制高速缓存器。DS18B20具有6条对RAM
的命令:
1)
44H:温度转换。
这条命令启动一次温度转换。温度转换命令被执行,而后DS18B20保持等待状态。如果总
线控制器在这条命令之后跟着发出读时间隙,而DS18B20又忙于做时间转换的话,DS18B20将在
总线上输出“0”,若温度转换完成,则输出“1”。如果使用寄生
电源,总线控制器必须在发
出这条命令后立即启动强上拉,并保持500ms。转换结果的低位存入BYTE0、高位存入BYTE1。
2)
BEH:读高速缓存器。
这个命令读取暂存器的内容。读取将从BYTE0开始,一直进行下去,直到第9个字节(BYTE8,
CRC)读完。如果不想读完所有字节,控制器可以在任何时间发出复位命令来终止读取。另外
需要注意的是,字节内容都是最低位先传送。
3)
4EH:写暂存器。
这个命令向DS18B20的高速缓存器中写入数据,开始位置在地址2。接下来写入的两个字节
将被存到高速缓存器的字节地址位2和3的高、低温触发器。可以在任何时刻发出复位命令来终
止写入。
4)
48H:复制高速缓存器
这条命令把高速缓存器的内容拷贝到DS18B20的E2PROM存储器中,即把温度报警触发字节
存入非易失性存储器里。如果总线控制器在这条命令之后跟着发出读时间隙,而DS18B20又正
在忙于把暂存器拷贝到E2PROM存储器,DS18B20就会输出一个“0”,如果拷贝结束的话,DS18B20
则输出“1”。如果使用寄生电源,总线控制器必须在这条命令发出后立即起动强上拉并最少
保持10ms。
5)
B8H:重调E2PROM
这条命令把E2PROM里的值拷回高速缓存器。这种拷回操作在DS18B20上电时自动执行,这
样器件一上电高速缓存器里马上就存在有效的数据了。若在这条命令发出之后发出读时间隙,
器件会输出温度转换忙的标识:“0”=忙,“1”=完成。
6)
B4H:读供电方式
读DS18B20的供电方式。若把这条命令发给DS18B20后发出读时间隙,器件会返回它的电源
模式:“0”=寄生电源,“1”=外部电源。
知道了DS18B20的结构和命令,那么我们该如何发送命令和接收数据呢?
由于DS18B20温度传感器采用单总线的方式进行
通信,因此我们先简略的介绍一下单总线
通信的原理。
单总线传输的定义:顾名思义,即主机和从机用一根总线进行通信,是一种半双工的通信
方式,单线=时钟线+数据线+控制线(+电源线)。理想状况下一条总线上的从器件数量几乎不
受数量限制。
单总线技术具有线路简单,硬件开销少,成本低廉,便于总线扩展和维护等优点。但由于只有一根总线,驱动能力一般较差,不能接过多的从器件,实际使用中,一般最多只能接8个
从器件;抗干扰能力较差,一般只能在中短距离的低速传输中使用;软件设计复杂,事物往往
有两面性,硬件部分的简单往往需要软件在复杂度上做出牺牲。
单总线传输就如同一根独木桥,行走于独木桥上的各种信号必须严格遵守通信协议才能
“安全过桥”。接下来我们就简单的介绍一下数据是如何传输的。
单总线通信协议为确保数据的完整性,定义了如下几种单线信号类型:复位脉冲、存在脉
冲、写0、写1、读0和读1。所有这些信号,除存在脉冲外,都是由总线控制器发出的。
单总线协议中主机和从机(DS18B20)间的任何通讯都需要以初始化序列开始,初始化序
列见下图。
图 25.1.5 初始化时序图
一个复位脉冲跟着一个存在脉冲表明DS18B20已经准备好发送和接收数据(适当的ROM命令
和RAM操作命令)。主机输出低电平,保持低电平时间至少480us,以产生复位脉冲。接着主机
释放总线,4.7K的上拉电阻将单总线拉高,延时15~60us,此时DS18B20拉低总线60~240us,
以产生低电平存在脉冲以应答主机。
初始化完成之后,主机就可以向从机读写数据。读写数据涉及到读写时隙的概念。在单总
线通信协议中,读写时隙的概念十分重要,当主机向从机输出数据时产生写时隙,当主机从从
机读取数据时产生读时隙,每一个时隙总线只能传输一位数据。无论是在读时隙还是写时隙,
它们都以主机拉低数据线开始,数据线的下降沿使从设备触发其内部的延时
电路,使之与主机
同步。在写时隙内,该延迟电路决定从设备采样数据线的时间延迟。
单总线通信协议中写时隙有两种:写1和写0。主机采用写1时隙向从机写入1,而采用写0
时隙向从机写入0。所有写时隙至少要60us,且在两次独立的写时隙之间至少需要1us的恢复时
间。两种写时隙均起始于主机拉低数据总线。产生写0时隙的方式:在主机拉低数据线后,只
需要在整个时隙间保持低电平即可(至少60us)。产生1时隙的方式:主机拉低总线后,接着
必须在15us之内释放总线,由上拉电阻将总线拉至高电平;在写时隙开始后15us~60us期间,
单总线器件采样总电平状态。如果在此期间采样值为高电平,则逻辑1写入器件;如果为0,写入逻辑0,时隙图如下图所示:
图 25.1.6 写时隙图
对于读时隙,单总线器件仅在主机发出读数据命令后,才向主机传输数据。主机发出读数
据命令后,必须马上产生读时隙,以便从机能够传输数据。所有读时隙至少需要60us,且在两
次独立的读时隙之间至少需要1us的恢复时间。每个读时隙都由主机发起,至少拉低总线1us。
在主机发出读时隙之后,单总线器件才开始在总线上发送0或1。若从机发送1,则保持总线为
高电平;若发出0,则拉低总线。当发送0时,从机在读时隙结束后释放总线,由上拉电阻将总
线拉回至空闲高电平状态。从机发出的数据在起始时隙之后,保持有效时间15us,因此主机在
读时隙期间必须释放总线,并且在时隙起始后的15us之内采样总线状态,时隙图如下图所示:
图 25.1.7 读时隙图
在了解了单总线时序之后,我们来看看DS18B20的典型温度读取过程,DS18B20的典型温度
读取过程为:初始化➔发跳过ROM命令(CCH)➔发开始转换命令(44H)➔延时➔初始化➔发
送跳过ROM命令(CCH)➔发读存储器命令(BEH)➔连续读出两个字节数据(即温度)➔结束或
开始下一循环。
实验任务
本节实验任务是使用开拓者FPGA开发板通过DS18B20采集温度,并将采集到的温度值(带
符号位)用数码管显示。
硬件设计
DS18B20的引脚图如下所示:
图 25.3.1 DS18B20引脚图
对于DS18B20而言,有两种供电方式:寄生电源和外部电源供电。
寄生电源供电时DS18B20的GND和VDD引脚都接地,DS18B20从数据线DQ上汲取能量:在信号
线处于高电平期间把能量存储在内部电容,在信号线处于低电平期间消耗电容上的电能工作,
直到高电平到来再给寄生电源(电容)供电。使用这种电路供电时,要想使DS18B20进行精确
的温度转换,IO线必须保证在温度转换期间提供足够的能量,否则会造成无法转换温度或者温
度误差极大。寄生电源供电方式如下图所示:
图 25.3.2 寄生电源供电
在外部电源供电方式下,DS18B20工作电源由VDD引脚接入,不存在电源电流不足的问题,
可以保证转换精度,同时理论上总线可以挂接任意多个DS18B20传感器。在使用外部供电方式
下,DS18B20的GND引脚不能悬空,否则不能转换温度。外部电源供电方式是***佳的供
电方式,稳定可靠,抗干扰能力强。外部电源供电方式如下图所示:
图 25.3.3 外部电源供电
我们的开拓者FPGA开发板上DS18B20采用外部电源供电,其原理图如下图所示:
图 25.3.4 DS18B20接口原理图
本实验中,各端口信号的管脚分配如下表所示:
表 25.3.1 温度传感器(DS18B20)数码管显示实验管脚分配
程序设计
根据实验任务,我们可以大致规划出系统的工作流程:FPGA控制DS18B20采集温度数据,
并将收到的温度数据转换成十进制显示在数码管上。由此画出的功能框图如下图所示。
图 25.4.1 温度传感器数码管显示系统框图
程序中各模块端口及信号连接如下图所示:
图 25.4.2 顶层模块原理图
FPGA顶层(temp_disp)例化了以下两个模块:DS18B20驱动模块(ds18b20_dri)和数码
管动态显示模块(seg_led),实现各模块间信号的交互。
DS18B20驱动模块(ds18b20_dri):搭建单总线通信协议与DS18B20进行通信,并控制
DS18B20采集温度,并将采集到温度值进行处理与输出
数码管动态显示模块(seg_led):将采集到的温度值显示到数码管上。
顶层模块的代码如下所示:
1
module temp_disp
(
2
input sys_clk
, //输入的系统时钟
3
input sys_rst_n
, //输入的复位信号
4
inout dq
, //ds18b20温度传感器单总线
5
output [5
:0
] sel
, //输出数码管位选信号
6
output [7
:0
] seg_led //输出数码管段选信号
7
);
8
9 //parameter define
10
parameter POINT
= 6'b000100
; // 数码管小数点的位置
11
12 //wire define
13
wire [19
:0
] temp_data
; // 温度数值
14
wire sign
; // 符号位
15
16 //*****************************************************
17 //** main code
18 //*****************************************************
19
20 //例化动态数码管驱动模块
21 seg_led u_seg_led
(
22 //module clock
23
.clk
(sys_clk
), // 时钟信号
24
.rst_n
(sys_rst_n
), // 复位信号
25 //seg_led interface
26
.sel
(sel
), // 位选
27
.seg_led
(seg_led
), // 段选
28 //user interface
29
.data
(temp_data
), // 显示的数值
30
.point
(POINT
), // 小数点具体显示的位置,从高到低,高电平有效
31
.en
(1'b1
), // 数码管使能信号
32
.sign
(sign
) // 符号位(高电平显示“-”号)
33
);
34
35 //例化DS18B20驱动模块
36 ds18b20_dri u1_ds18b20_dri
(
37 //module clock
38
.clk
(sys_clk
), // 时钟信号(50MHz)
39
.rst_n
(sys_rst_n
), // 复位信号
40 //user interface
41
.dq
(dq
), // DS18B20的DQ引脚数据
42
.temp_data
(temp_data
), // 转换后得到的温度值
43
.sign
(sign
) // 符号位
44
);
45
46
endmodule
代码第10行的POINT参数用于控制数码管小数点的显示位置,小数点显示在哪一位,哪一
位就置“1”,本次实验保留温度值的小数点后两位,所以其参数值为“000100”。动态数码
管显示模块请大家参考“动态数码管显示实验”,在该实验已详细介绍。
前面我们讲了控制DS18B20读取温度的顺序,可以发现,DS18B20的读写操作很适合使用状
态机来实现,下图为DS18B20驱动模块的状态跳转图。
图 25.4.3 DS18B20驱动模块的状态转换图
DS18B20驱动模块使用三段式状态机来实现温度的读取,从上图可以比较直观的看到每个
状态实现的功能以及跳转到下一个状态的条件。首先初始化,初始化完成后,由于单总线上只
有一个DS18B20,所以可以跳过DS18B20的身份识别,即发送跳过ROM命令,进入写字节状态,
向DS18B20发送该命令;发送完该命令后发送温度转换命令进行温度转换,状态机再次进入写
字节状态;写完温度转换命令后,为了兼容寄生电源供电,进入延时状态以适当的延时,延时
结束后,进入初始化状态,初始化完成后发送跳过ROM命令,进入写字节状态;写完跳过ROM命
令后,发送读取温度命令,从DS18B20中读取温度数据,读取完温度数据后,再次进入初始化
状态以循环操作。
因为代码较长,只粘贴了第二段状态机组合逻辑状判断状态转换条件的源代码,代码如下:
87 //组合逻辑判断状态转换条件
88
always @( * ) begin
89
case(cur_state
)
90 init
: begin // 初始化状态
91
if (init_done
)
92 next_state
= rom_skip
;
93
else
94 next_state
= init
;
95
end
96 rom_skip
: begin // 跳过ROM命令
97
if(st_done
)
98 next_state
= wr_byte
;
99
else
100 next_state
= rom_skip
;
101
end
102 wr_byte
: begin // 写字节状态
103
if(st_done
)
104
case(cmd_cnt
) // 写不同命令的字节
105 4'b1
: next_state
= temp_convert
;
106 4'd2
: next_state
= init
;
107 4'd3
: next_state
= rd_temp
;
108 4'd4
: next_state
= rd_byte
;
109
default: next_state
= temp_convert
;
110
endcase
111
else
112 next_state
= wr_byte
;
113
end
114 temp_convert
: begin // 温度转换命令
115
if(st_done
)
116 next_state
= wr_byte
;
117
else
118 next_state
= temp_convert
;
119
end
120 rd_temp
: begin // 读温度命令
121
if(st_done
)
122 next_state
= wr_byte
;
123
else
124 next_state
= rd_temp
;
125
end
126 rd_byte
: begin // 读字节状态
127
if(st_done
)
128 next_state
= init
;
129
else
130 next_state
= rd_byte
;
131
end
132
default: next_state
= init
;
133
endcase
134
end
代码综合后的状态机如下图所示,同我们规划的状态转换相符。
图 25.4.4 综合后的状态机
下载验证
首先我们打开温度传感器数码管显示工程,在工程所在的路径下打开temp_disp/par文件
夹,在里面找到“temp_disp.qpf”并双击打开。注意工程所在的路径名只能由字母、数字以
及下划线组成,不能出现中文、空格以及特殊字符等。temp_disp工程打开后如图 25.5.1所示。
图 25.5.1 温度传感器数码管显示工程
将DS18B20接插到开拓者开发板上的单总线接口,如下图所示。然后连接电源线并打开电
源开关。
图 25.5.2 插入DS18B20
接下来我们下载程序,验证温度传感器数码管显示实验的功能。工程打开后通过点击工具
栏中的“ Programmer ”图标打开下载界面,通过“ Add File ”按钮选择
temp_disp/par/output_files目录下的“temp_disp.sof”文件。开发板电源打开后,在程序
下载界面点击“Hardware Setup”,在弹出的对话框中选择当前的硬件连接为“USB
Blaster[USB-0]”。然后点击“Start”将工程编译完成后得到的sof文件下载到开发板中,如
下图所示:
图 25.5.3 程序下载完成界面
下载完成后,实验结果如
错误!未找到引用源。所示,数码管上显示读取到的温度值,与
用室内温度计测量到的温度值接近,说明温度传感器数码管显示实验下载验证成功。需要说明
的是,下载完成后,开始显示的是“0.00”,短暂的显示“0.00”后显示“85.00”,这过程不
超过1秒,然后显示当前环境温度值,出现这种现象的原因是在进行温度转换化时有500ms的延
时,这500ms的延时是为了兼容寄生电源供电,此时显示“0.00”,延时结束后温度转换并未
结束,此时读到的温度值为DS18B20的默认值85,故而显示“85.00”,转换结束后读到的值为
当前环境温度值。