正点原子 发表于 2019-6-10 11:21:57

【正点原子FPGA连载】第二十五章 DS18B20数字温度传感器实验--摘自【正点原子】开拓者 FPGA 开发指南

本帖最后由 正点原子 于 2020-10-23 11:47 编辑

1)实验平台:正点原子开拓者FPGA开发板
2)平台购买地址:https://item.taobao.com/item.htm?id=579749209820
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-281143-1-1.html
4)本实例源码下载:
5)对正点原子FPGA感兴趣的同学可以加群讨论:712557122点击加入:
6)关注正点原子公众号,获取最新资料更新:


第二十五章 DS18B20数字温度传感器实验

DS18B20是常用的数字温度传感器, 其输出数字信号来表示温度,具有体积小,硬件开销低,抗干扰能力强,精度高的特点,又由于封装形式多样,适用于各种狭小空间设备数字测温和控制领域,也可应用于锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。 本章我们将使用FPGA开发板学习如何使用DS18B20进行温度测量。
本章包括以下几个部分:
25.1 温度传感器DS18B20简介
25.2 实验任务
25.3 硬件设计
25.4 程序设计
25.5 下载验证
25.1 温度传感器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) ➔连续读出两个字节数据(即温度)➔结束或开始下一循环。

25.2 实验任务
本节实验任务是使用开拓者FPGA开发板通过DS18B20采集温度,并将采集到的温度值(带符号位) 用数码管显示。
25.3 硬件设计
DS18B20的引脚图如下所示:


图 25.3.1 DS18B20引脚图

对于DS18B20而言, 有两种供电方式:寄生电源和外部电源供电。寄生电源供电时DS18B20的GND和VDD引脚都接地, DS18B20从数据线DQ上汲取能量:在信号线处于高电平期间把能量存储在内部电容,在信号线处于低电平期间消耗电容上的电能工作,直到高电平到来再给寄生电源(电容)供电。使用这种电路供电时,要想使DS18B20进行精确的温度转换, IO线必须保证在温度转换期间提供足够的能量,否则会造成无法转换温度或者温度误差极大。寄生电源供电方式如下图所示:





图 25.3.2 寄生电源供电

在外部电源供电方式下, DS18B20工作电源由VDD引脚接入,不存在电源电流不足的问题,可以保证转换精度,同时理论上总线可以挂接任意多个DS18B20传感器。在使用外部供电方式下, DS18B20的GND引脚不能悬空,否则不能转换温度。外部电源供电方式是DS18B20最佳的供电方式,稳定可靠,抗干扰能力强。外部电源供电方式如下图所示:



图 25.3.3 外部电源供电

我们的开拓者FPGA开发板上DS18B20采用外部电源供电,其原理图如下图所示:




图 25.3.4 DS18B20接口原理图

本实验中, 各端口信号的管脚分配如下表所示:




表 25.3.1 温度传感器(DS18B20)数码管显示实验管脚分







25.4 程序设计
根据实验任务,我们可以大致规划出系统的工作流程: 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 sel , //输出数码管位选信号
6 output seg_led //输出数码管段选信号
7 );
8 9
//parameter define
10 parameter POINT = 6'b000100; // 数码管小数点的位置
11
12 //wire define
13 wire 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 ), // 数码管使能信号
ALIENTEK PIONEER 开发板教

471
开拓者 FPGA 开发指南
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 综合后的状态机

25.5 下载验证
首先我们打开温度传感器数码管显示工程,在工程所在的路径下打开temp_disp/par文件夹,在里面找到“temp_disp.qpf”并双击打开。注意工程所在的路径名只能由字母、数字以及下划线组成,不能出现中文、空格以及特殊字符等。temp_disp工程打开后如图 25.5.1所示。



图 25.5.1 温度传感器数码管显示工程

将DS18B20接插到开拓者开发板上的单总线接口,如下图所示。 然后连接电源线并打开电源开关。DS18B20




图 25.5.2 插入DS18B20

接下来我们下载程序,验证温度传感器数码管显示实验的功能。工程打开后通过点击工具栏 中 的 “Programmer ” 图 标 打 开 下 载 界 面 , 通 过 “Add File ” 按 钮 选 择temp_disp/par/output_files目录下的“temp_disp.sof”文件。开发板电源打开后,在程序
下载界面点击“Hardware Setup”,在弹出的对话框中选择当前的硬件连接为“USBBlaster”。然后点击“Start”将工程编译完成后得到的sof文件下载到开发板中,如下图所示:




图 25.5.3 程序下载完成界面

下载完成后,实验结果如图 25.5.4所示, 数码管上显示读取到的温度值,与用室内温度计测量到的温度值接近,说明温度传感器数码管显示实验下载验证成功。需要说明的是,下载完成后,开始显示的是“0.00”,短暂的显示“0.00”后显示“85.00”,这过程不超过1秒,
然后显示当前环境温度值,出现这种现象的原因是在进行温度转换化时有500ms的延时,这500ms的延时是为了兼容寄生电源供电,此时显示“0.00”,延时结束后温度转换并未结束,
此时读到的温度值为DS18B20的默认值85,故而显示“85.00”,转换结束后读到的值为当前环境温度值。



图 25.5.4 实验结果

nibia 发表于 2019-6-10 11:52:33

fpga开发的真正干货,很难get到
页: [1]
查看完整版本: 【正点原子FPGA连载】第二十五章 DS18B20数字温度传感器实验--摘自【正点原子】开拓者 FPGA 开发指南