文章目录
-
- 一.传感器介绍
-
- 1.特点
- 2.内部结构
- 3.ds18b20管脚
- 4.ds18b20内部高速临时存储器
- 5.ds18b20工作时序
- 6.ds18b20单线通信
- 二.FPGA代码实现
-
- 1.状态图
- 2.代码实现
-
- 2.1DS18B20驱动模块
- 2.2数据处理模块
- 2.3数字管驱动模块
- 2.4顶层模块
- 3.仿真
一.传感器介绍
ds18b20是一种常用的数字温度传感器,具有体积小、硬件成本低、抗干扰能力强、精度高等特点。
1.特点
ds18b单线数字温度传感器具有独特的优点:
( 1 )采用单总线接口法,微处理器与微处理器连接只需一条线即可实现DS18B20双向通信。单总线具有经济性好、抗干扰能力强、现场温度测量适合恶劣环境、使用方便等优点,使用户能够轻松构建传感器网络,为测量系统的构建引入新的概念。 ( 2 )测量温度范围宽。测量精度高 DS18B测量范围为20 -55 ℃ ~ 125 ℃ ; 在 -10~ 85°C范围内,精度为 ± 0.5°C 。 ( 3 )使用中不需要任何外围元件。 ( 4 )支持多点网络功能。多点网络功能。 DS18B20 可并联在唯一的单线上,实现多点测温。 ( 5 )灵活的供电方式。DS18B20 数据线可以通过内部寄生电路获取电源。因此,当数据线上的时间顺序满足一定的要求时,不能连接外部电源,使系统结构更简单、更可靠。 ( 6 )可配置测量参数。DS18B通过程序设置20的测量分辨率 9~12 位。 ( 7 ) 当负压特性电源极性反转时,温度计不会因发热而燃烧,但不能正常工作。 ( 8 )掉电保护功能。DS18B20 内部含有 EEPROM ,系统断电后,仍能保存分辨率和报警温度的设定值。
2.内部结构
ds18b20主要由四部分组成:64位ROM,温度传感器、非挥发性温度报警触发器TH和TL,配置寄存器。 ROM64位序列号出厂前用光刻制,可视为DS18B20地址序列码,每个DS18B2064位序列号不同。 64位ROM循环冗余校验码: ROM它的作用是让每一个DS18B20都不一样,这样一条总线就可以挂多个DS18B20的目的。
3.ds18b20管脚
- GND为电源地;
- DQ输入/输出数字信号;
- VDD外部供电电源输入端(寄生电源接接地)
4.ds18b20内部高速临时存储器
高速临时存储器由9个字节组成。当温度转换命令发布时,转换获得的温度值以二字节补码的形式存储在高速临时存储器的第0和第1个字节中。单片机可以通过单线接口读取数据。读取时,相应的温度计算:当符号位置时S=0时,二进制位直接转换为十进制;当S=一、先将补码变成原码,再计算十进制值。 说明:
字节0表示低温八位数据。 字节1表示高八位数据的温度。 字节2表示高温阀值。 字节3表示低温阀值。 字节4表示配置寄存器。 字节5、字节6、字节7保留字节。
DS18B20中的温度传感器以16位二进制的形式完成二进制的形式提供,并以其形式表达 中S是符号位。 例如: 125℃的数字输出07D0H。(正温直接将16进制数转换为10进制,获得温度值 ) -55℃的数字输出为 FC90H。(负温取反16进制数,然后加1 再转为10进制数)
5.ds18b20工作时序
①主机首先发出480-960微秒的低电平脉冲,然后将总线释放为高电平,并在接下来的480微秒内检测总线。如果有低电平,说明总线上的设备已经响应了。如果没有低电平,总是高电平,说明总线上没有设备响应。 ②作为从器件DS18B20一上电,就一直在检测总线上是否有480-960微秒的低电平。如果是这样,在总线转换为高电平后,等待15-60微秒,然后将总线电平降低60-240微秒,以响应脉冲,并告诉主机本设备已准备好。如果没有检测到,就一直在等待检测。 写作周期至少为60微秒,最长不超过120微秒。写作周期开始时,主机首先将总线拉低1微秒,表示写作周期开始。随后若主机想写0,则继续拉低电平最少60微秒直至写周期结束,然后释放总线为高电平。如果主机想写1,总线在开始拉低总线电平1微秒后释放为高电平,直到写周期结束。作为从机DS18B检测到总线后,等待15微秒,然后从15微秒开始us到45us总线开始采样,采样期内总线高电平为1,采样期内总线低电平为0。
读数据操作时序也分为读0时序和读1时序两个过程。读时间隙是从主机拉下单总线后,在1微秒后释放单总线为高电平DS18B将数据传输到单总线。DS18B在检测到总线被拉低1微秒后,20开始发送数据,如果要发送0,将总线拉到低电平,直到读取周期结束。如果要发出1,释放总线为高电平。主机在开始拉低总线1微秒后释放总线,然后在15微秒内完成总线采样检测,包括前拉低总线电平1微秒。如果总线在采样期为低电平,则确认为0。采样期内总线为高电平,确认为1。至少需要60个读时过程才能完成读时过程us才能完成。
6.ds18b20单线通信
DS18B20 单线通信功能是分时完成的,他有严格的间隙概念,如果序列混乱,1-WIRE 该设备不会对主机做出反应,因此读写顺序非常重要。 DS18B20 各种操作必须按协议进行。 DS18B20 协议规定,微控制器控制 DS18B20 温度转换必须通过以下方式完成 3个步骤 : (1)每次读写前对 DS18B20 复位初始化。复位要求主要。 CPU 将数据线下拉500us ,然后释放, DS18B20 收到信号后等待 16us-60us 左右,然后发出60us-240us 低脉冲,主 CPU 收到此信号后,复位成功。 (2)发送一个 ROM 指令
指令名称 | 指令代码 | 指令功能 |
---|---|---|
读ROM | 33H | 读DS18B20ROM编码(即读64位地址) |
ROM匹配(符合ROM) | 55H | 发出这个命令后,然后发出64人 ROM编码,访问单总线对应编码DS18820为下一步做出回应 DS18B读写准备 |
搜索ROM | 0F0H | 用于确定同一总线上的挂接 DS18B20的个数和识别64位ROM地址,准备操作各种设备 |
跳过ROM | 0CCH | 忽略64位ROM地址,直接方向DS18B20发温度变换命令,适用于单片机工作 |
警报搜索 | 0ECH | 该指令执行后,只有温度超过设定值上限或下限的电影才能响应 |
(3)发送存储指令
指令名称 | 指令代码 | 指令功能 |
---|---|---|
温度变换 | 44H | 启动 DS1820进行温度转换,转换时间最长为500ms(典型为200ms ),结果存入内部9字节 RAM中 |
读暂存器 | 0BEH | 读内部 RAM中9宇节的内容 |
写暂存器 | 4EH | 发出向内部RAM的第3, 4字节写上,下限温度数据命令,紧跟该命令之后,是传送两字节的数据 |
复制暂存器 | 48H | 将RAM中第3,4字节的内容复制到EEPROM中 |
重调EEPROM | 0B8H | EEPROM中的内容恢复到 RAM中的第3, 4字节 |
读供电方式 | 0B4H | 读DS18B20的供电模式,寄生供电时 DS18B20发送“0”,外接电源供电DS18B20发送“1” |
二.FPGA代码实现
1.状态图
FPGA作为主机,DS18B20作为从机。 ①主状态机实现发复位脉冲-接收存在脉冲-发ROM指令-发温度转换指令-延时-温度读取指令-读取温度; ②从状态机负责发送数据或读取数据时序:拉低总线-发送数据/采样数据-释放总线; 主从机状态图: 状态说明:
M_IDLE:空闲状态,等待开始通信; M_RST:发送复位脉冲; M_RELE:释放总线; M_RACK:接收存在脉冲; M_RSKP:发送跳过ROM指令; M_SCON:发送温度转换命令; M_WAIT:等待750ms; M_SRTM:发送温度读取指令; M_RTMP:读取温度值; S_IDLE:空闲状态,等待传输请求; S_LOW:发数据前先拉低1us; S_SEND:发送1bit数据; S_SAMP:接收1bit数据; S_RELE:释放总线; S_DONE:发送/接收一次数据完成;
2.代码实现
2.1DS18B20驱动模块
在该模块,主从状态机都是属于FPGA主机部分,主状态机控制整个流程,而从状态机在主状态机的控制下实现相关主机状态下的操作。
module ds18b20_driver( input clk ,//时钟信号 input rst_n ,//复位信号 input dq_in , output reg dq_out ,//dq总线FPGA输出 output reg dq_out_en ,//输出数据有效信号 output reg temp_sign ,//温度值符号位 0:正 1:负 output reg [23:0] temp_out ,//温度输出 output reg temp_out_vld //温度输出有效信号 ); //状态机参数 localparam //主机状态参数 M_IDLE = 9'b0_0000_0001 ,//空闲状态 M_REST = 9'b0_0000_0010 ,//复位 M_RELE = 9'b0_0000_0100 ,//释放总线 -- ds18b20等待 M_RACK = 9'b0_0000_1000 ,//接收应答 -- 主机接收存在脉冲 M_ROMS = 9'b0_0001_0000 ,//ROM命令 -- 跳过ROM命令 M_CONT = 9'b0_0010_0000 ,//转化 M_WAIT = 9'b0_0100_0000 ,//等待 -- 12bit分辨率下的温度转化时间 M_RCMD = 9'b0_1000_0000 ,//读命令 -- 读暂存器命令 M_RTMP = 9'b1_0000_0000 ,//读温度 -- 产生读时隙 -- 接收2字节带符号位的补码温度 //从机状态参数 S_IDLE = 6'b00_0001 ,//空闲状态 S_LOW = 6'b00_0010 ,//拉低总线 -- 时隙的开始 S_SEND = 6'b00_0100 ,//发送 -- 15us内 S_SAMP = 6'b00_1000 ,//采样 -- 在15us内 S_RELE = 6'b01_0000 ,//释放 -- 时隙的恢复时间 S_DONE = 6'b10_0000 ;// parameter TIME_1US = 50 ,//1us TIME_RST = 500 ,//复位脉冲 500us TIME_REL = 20 ,//主机释放总线 20us TIME_PRE = 200 ,//主机接收存在脉冲 200us TIME_WAIT= 750000 ,//主机发完温度转换命令 等待750ms TIME_LOW = 2 ,//主机拉低总线 2us TIME_RW = 60 ,//主机读、写1bit 60us TIME_REC = 3 ;//主机读、写完1bit释放总线 3us localparam CMD_ROMS = 8'hCC ,//跳过ROM指令 CMD_CONT = 8'h44 ,//温度转化指令 CDM_RTMP = 8'hBE ;//读暂存器指令 //信号定义 reg [8:0] m_state_c ;//主机现态 reg [8:0] m_state_n ;//主机次态 reg [5:0] s_state_c ;//从机现态 reg [5:0] s_state_n ;//从机次态 reg [5:0] cnt_1us ;//1us计数器 wire add_cnt_1us ; wire end_cnt_1us ; reg [19:0] cnt0 ;//复位脉冲、释放、存在脉冲、等待750ms wire add_cnt0 ; wire end_cnt0 ; reg [19:0] X ; reg [5:0] cnt1 ;//计数从机状态机每个状态持续时间 wire add_cnt1 ; wire end_cnt1 ; reg [5:0] Y ; reg [4:0] cnt_bit ; wire add_cnt_bit ; wire end_cnt_bit ; reg slave_ack ;//接收存在脉冲 reg flag ;//0:发送温度转换命令 1:发送温度读取命令 reg [7:0] wr_data ; reg [15:0] orign_data ;//采样温度值寄存器 reg [10:0] temp_data ; wire [23:0] temp_data_w ;//组合逻辑计算实际温度值 十进制 wire m_idle2m_rest ; wire m_rest2m_rele ; wire m_rele2m_rack ; wire m_rack2m_roms ; wire m_roms2m_cont ; wire m_roms2m_rcmd ; wire m_cont2m_wait ; wire m_wait2m_rest ; wire m_rcmd2m_rtmp ; wire m_rtmp2m_idle ; wire s_idle2s_low ; wire s_low2s_send ; wire s_low2s_samp ; wire s_send2s_rele ; wire s_samp2s_rele ; wire s_rele2s_low ; wire s_rele2s_done ; //主机状态机设计 描述状态转移 always@(posedge clk or negedge rst_n)begin if(!rst_n)begin m_state_c <= M_IDLE; end else begin m_state_c <= m_state_n; end end //主机状态转移条件 always @(*) begin case(m_state_c) M_IDLE:begin if(m_idle2m_rest) m_state_n = M_REST; else m_state_n = m_state_c; end M_REST:begin if(m_rest2m_rele) m_state_n = M_RELE; else m_state_n = m_state_c; end M_RELE:begin if(m_rele2m_rack) m_state_n = M_RACK; else m_state_n = m_state_c; end M_RACK:begin if(m_rack2m_roms) m_state_n = M_ROMS; else m_state_n = m_state_c; end M_ROMS:begin if(m_roms2m_cont) m_state_n = M_CONT; else if(m_roms2m_rcmd) m_state_n = M_RCMD; else m_state_n = m_state_c; end M_CONT:begin if(m_cont2m_wait) m_state_n = M_WAIT; else m_state_n = m_state_c; end M_WAIT:begin if(m_wait2m_rest) m_state_n = M_REST; else m_state_n = m_state_c; end M_RCMD:begin if(m_rcmd2m_rtmp) m_state_n = M_RTMP; else m_state_n = m_state_c; end M_RTMP:begin if(m_rtmp2m_idle) m_state_n = M_IDLE; else m_state_n = m_state_c; end default:m_state_n = M_IDLE; endcase end assign m_idle2m_rest = m_state_c == M_IDLE && (1'b1) ;//主机IDLE状态直接转换成复位状态 一次采集的开始 重复采集 assign m_rest2m_rele = m_state_c == M_REST && (end_cnt0);//500us复位脉冲 assign m_rele2m_rack = m_state_c == M_RELE && (end_cnt0);//20us释放总线 assign m_rack2m_roms = m_state_c == M_RACK && (end_cnt0 && slave_ack == 1'b0);//200us,主机接收存在脉冲 assign m_roms2m_cont = m_state_c == M_ROMS && (s_state_c == S_DONE && flag == 1'b0);//主机发送完8bit跳过ROM命令 0:温度转化命令 assign m_roms2m_rcmd = m_state_c == M_ROMS && (s_state_c == S_DONE && flag == 1'b1);//主机发送完8bit跳过ROM命令 1:读温度命令 assign m_cont2m_wait = m_state_c == M_CONT && (s_state_c == S_DONE);//主机发送8bit温度转化命令 assign m_wait2m_rest = m_state_c == M_WAIT && (end_cnt0);//等待750ms转换完成 assign m_rcmd2m_rtmp = m_state_c == M_RCMD && (s_state_c == S_DONE);//主机发送8bit读命令 --等待从机接收数据完成 assign m_rtmp2m_idle = m_state_c == M_RTMP && (s_state_c == S_DONE);//主机读温度 --等待从机发送数据完成 //从机状态机设计 描述状态转移 always@(posedge clk or negedge rst_n)begin if(!rst_n)begin s_state_c <= S_IDLE; end else begin s_state_c <= s_state_n; end end //从机状态转移条件 always @(*) begin case(s_state_c) S_IDLE:begin if(s_idle2s_low) s_state_n = S_LOW; else s_state_n = s_state_c; end S_LOW :begin if(s_low2s_send) s_state_n = S_SEND; else if(s_low2s_samp) s_state_n = S_SAMP; else s_state_n = s_state_c; end S_SEND:begin if(s_send2s_rele) s_state_n = S_RELE; else s_state_n = s_state_c; end S_SAMP:begin if(s_samp2s_rele) s_state_n = S_RELE; else s_state_n = s_state_c; end S_RELE:begin if(s_rele2s_done) s_state_n = S_DONE; else if(s_rele2s_low) s_state_n = S_LOW; else s_state_n = s_state_c; end S_DONE:begin s_state_n = S_IDLE; end default:s_state_n = S_IDLE; endcase end assign s_idle2s_low = s_state_c == S_IDLE && (m_state_c == M_ROMS || m_state_c == M_CONT || m_state_c == M_RCMD || m_state_c == M_RTMP);//主状态机要发送ROM命令 温度转化命令 读温度命令 读温度过程 每1bit数据 按照协议要求主机拉低 assign s_low2s_send = s_state_c == S_LOW && (m_state_c == M_ROMS || m_state_c == M_CONT || m_state_c == M_RCMD) && end_cnt1;//主机拉低2us后 从状态机开始发送数据(命令) assign s_low2s_samp = s_state_c == S_LOW && (m_state_c == M_RTMP && end_cnt1);//主机拉低2us后 从状态机采样接收温度数据 assign s_send2s_rele = s_state_c == S_SEND && (end_cnt1);//主机读1bit数据 (60us内完成) assign s_samp2s_rele = s_state_c == S_SAMP && (end_cnt1);//主机写1bit数据 (60us内完成) assign s_rele2s_low = s_state_c == S_RELE && (end_cnt1 && end_cnt_bit == 1'b0);//主机读写完1bit (3us) 继续下一bit assign s_rele2s_done = s_state_c == S_RELE && (end_cnt1 && end_cnt_bit == 1'b1);//主机读写完1bit (3us) bit数读写完 //1us计数器 always@(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_1us <= 0; end else if(add_cnt_1us) begin if(end_cnt_1us)begin cnt_1us <= 0; end else begin cnt_1us <= cnt_1us + 1; end end end assign add_cnt_1us = m_state_c != M_IDLE;//非IDLE状态持续计数 assign end_cnt_1us = add_cnt_1us && cnt_1us == TIME_1US - 1; always@(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt0 <= 0; end else if(add_cnt0) begin if(end_cnt0)begin cnt0 <= 0; end else begin cnt0 <= cnt0 + 1; end end end assign add_cnt0 = (m_state_c == M_REST || m_state_c == M_RELE || m_state_c == M_RACK || m_state_c == M_WAIT) && end_cnt_1us; assign end_cnt0 = add_cnt0 && cnt0 == X - 1; always@(posedge clk or negedge rst_n)begin if(!rst_n)begin X <= 0; end else if(m_state_c == M_REST)begin//复位:500us (480us) X <= TIME_RST; end else if(m_state_c == M_RELE)begin//释放总线:20us (15-60us内) X <= TIME_REL; end else if(m_state_c == M_RACK)begin//接收应答:200us (60-240us) X <= TIME_PRE; end else if(m_state_c == M_WAIT) begin//等待:750ms (等待转换完成) X <= TIME_WAIT; end end always@(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt1 <= 0; end else if(add_cnt1) begin if(end_cnt1)begin cnt1 <= 0; end else begin cnt1 <= cnt1 + 1; end end end assign add_cnt1 = (s_state_c == S_LOW || s_state_c == S_SEND || s_state_c == S_SAMP || s_state_c == S_RELE) && end_cnt_1us; assign end_cnt1 = add_cnt1 && cnt1 == Y - 1; always@(posedge clk or negedge rst_n)begin if(!rst_n)begin Y <= 0; end else if(s_state_c == S_LOW)begin Y <= TIME_LOW;//主机拉低总线 2us (大于1us) end else if(s_state_c == S_SEND || s_state_c == S_SAMP) begin Y <= TIME_RW;//主机读写1bit 60us (至少60us) end else begin Y <= TIME_REC;//主机读写完1bit释放总线 3us (至少1us) end end always@(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_bit <= 0; end else if(add_cnt_bit) begin if(end_cnt_bit)begin cnt_bit <= 0; end else begin cnt_bit <= cnt_bit + 1; end end end assign add_cnt_bit = s_state_c == S_RELE && end_cnt1; assign end_cnt_bit = add_cnt_bit && cnt_bit == ((m_state_c == M_RTMP)?16-1:8-1);//读温度状态有16bit数据,其余状态8bit数据 //slave_ack 采样传感器的存在脉冲 always@(posedge clk or negedge rst_n)begin if(!rst_n)begin slave_ack <= 1'b1; end//接收应答状态 计数器计到60us 进行采样 else if(m_state_c == M_RACK && cnt0 == 60 && end_cnt_1us)begin slave_ack <= dq_in; end end always@(posedge clk or negedge rst_n)begin//命令发送标志 (区分温度转换和温度读取命令) if(!rst_n)begin flag <= 0; end else if(m_wait2m_rest)begin//从等待状态转移到复位状态 flag置一读温度 flag <= 1'b1; end else if(m_rtmp2m_idle) begin//从读温度状态转移到复位状态 flag置零读温度命令 flag <= 1'b0; end end //输出信号 //dq_out always@(posedge clk or negedge rst_n)begin if(!rst_n)begin dq_out <= 0; end else if(m_idle2m_rest | s_idle2s_low | s_rele2s_low | m_wait2m_rest)begin dq_out <= 1'b0; end else if(s_low2s_send) begin//向从机发送命令码 dq_out <= wr_data[cnt_bit]; end end //dq_out_en always@(posedge clk or negedge rst_n)begin if(!rst_n)begin dq_out_en <= 0; end else if(m_idle2m_rest | s_idle2s_low | s_rele2s_low | m_wait2m_rest)begin dq_out_en 标签:
jst连接器b10pr3传感器参数传感器重复性的正负f0温度传感器然后外接传感器等一些器件传感器fc15