0. 注意
典型的 DS18B20 电路的 inout 端口需要一个 4.7k 上拉电阻
1. DS18B20简介
1.1 DS18B20特性
1.2 DS18B20引脚
1.3 DS18B20内部结构图
1.4 DS18B20的高速缓存器
1.4 DS18B20的温度寄存器
共16位,5位S表示符号位
红色的9-12表示精度为9-12时的有效位;精度为9时,后三位无效,默认精度为12位,即16位全部有效
举例:
+125℃ 0000_0111_1101_0000 12位精度
0000_0为符号位,0表示正数
111_1101_0000B = 2000
2000*0.0625 = 125
1.5 DS18B20的时序
1.5.1 初始化时序
1.5.2 写时序
1.5.3 读时序
2. 系统框图
3. 状态转移图
4. 时序图
4.1 生成clk_us信号
4.2 INIT - WR_CMD的时序
4.3 WAIT - INIT_AGAIN - RD_CMD的时序
4.4 RD_TEMP - INIT的时序
5. 设计文件
5.1 ds18b20.v
`timescale 1ns/1ns
module ds18b20
(
input wire sys_clk ,
input wire sys_rst_n ,
inout wire dq ,
output wire [7:0] sel , //数码管位选信号
output wire [7:0] seg //数码管段选信号
);
wire [19:0] data_out;
ds18b20_ctrl ds18b20_ctrl_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.dq (dq ),
.data_out (data_out )
);
seg_dynamic
#(
.CNT_MAX(17'd99_999)
)
seg_dynamic_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.data (data_out ),
.sel (sel ),
.seg (seg )
);
endmodule
5.2 ds18b20_ctrl.v
`timescale 1ns/1ns
module ds18b20_ctrl
(
input wire sys_clk ,
input wire sys_rst_n ,
inout wire dq ,
output wire [19:0] data_out ,
);
parameter INIT = 6'b000_001,
WR_CMD = 6'b000_010,
WAIT = 6'b000_100,
INIT_AGAIN = 6'b001_000,
RD_CMD = 6'b010_000,
RD_TEMP = 6'b100_000;
parameter WAIT_MAX = 20'd750_000;
parameter WR_CC_44 = 16'h44_cc,
WR_CC_BE = 16'hbe_cc;
reg clk_us ;
reg [5:0] cnt ;
reg [5:0] state ;
reg [19:0] cnt_us ;
reg flag ;
reg [3:0] bit_cnt ;
reg [15:0] data_temp ;
reg [19:0] data ;
reg dq_en ;
reg dq_out ;
assign dq = (dq_en == 1'b1) ? dq_out : 1'bz;
assign data_out = (data * 625) / 10;
//cnt,计数50次,实现1us
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 6'd0;
else if(cnt == 6'd49)
cnt <= 6'd0;
else
cnt <= cnt + 1'b1;
//clk_us,1us的时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
clk_us <= 1'b0;
else if(cnt == 6'd49)
clk_us <= ~clk_us;
else
clk_us <= clk_us;
//cnt_us,1us 时钟计数器,用于状态跳转
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_us <= 20'd0;
else if(((state == INIT || state == INIT_AGAIN) && (cnt_us == 20'd999))
|| ((state == WR_CMD || state == RD_CMD || state == RD_TEMP) && (cnt_us == 20'd64))
|| ((state == WAIT && cnt_us == WAIT_MAX)))
cnt_us <= 20'd0;
else
cnt_us <= cnt_us + 1'b1;
//bit_cnt,bit 计数器,写 1bit 或读 1bit 加 1,一次写完之后清零
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'd0;
else if((state == WR_CMD || state == RD_CMD || state == RD_TEMP)
&& (bit_cnt == 4'd15) && (cnt_us == 20'd64))
bit_cnt <= 4'd0;
else if((state == WR_CMD || state == RD_CMD || state == RD_TEMP)
&& (cnt_us == 20'd64))
bit_cnt <= bit_cnt + 1'b1;
//flag
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag <= 1'b0;
else if((state == INIT || state == INIT_AGAIN) && (cnt_us == 20'd570) && (dq == 1'b0))
flag <= 1'b1;
//else if((state == INIT || state == INIT_AGAIN) && (cnt_us == 20'd999))
else if(cnt_us == 20'd999)
flag <= 1'b0;
else
flag <= flag;
//state????
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= INIT;
else
case(state)
INIT :
if(cnt_us == 20'd999 && flag == 1'b1)
state <= WR_CMD;
else
state <= INIT;
WR_CMD :
if(bit_cnt == 4'd15 && cnt_us == 20'd64)
state <= WAIT;
else
state <= WR_CMD;
WAIT :
if(cnt_us == WAIT_MAX)
state <= INIT_AGAIN;
else
state <= WAIT;
INIT_AGAIN :
if(cnt_us == 20'd999 && flag == 1'b1)
state <= RD_CMD;
else
state <= INIT_AGAIN;
RD_CMD :
if(bit_cnt == 4'd15 && cnt_us == 20'd64)
state <= RD_TEMP;
else
state <= RD_CMD;
RD_TEMP :
if(bit_cnt == 4'd15 && cnt_us == 20'd64)
state <= INIT;
else
state <= RD_TEMP;
default:state <= INIT;
endcase
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
else
case(state)
INIT :
if(cnt_us < 20'd499)
begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
WR_CMD :
if(cnt_us > 20'd62)
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
else if(cnt_us <= 20'd1)
begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else if(WR_CC_44[bit_cnt] == 1'b0)
begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else if(WR_CC_44[bit_cnt] == 1'b1)
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
WAIT :
begin
dq_en <= 1'b1;
dq_out <= 1'b1;
end
INIT_AGAIN :
if(cnt_us < 20'd499)
begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
RD_CMD :
if(cnt_us > 20'd62)
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
else if(cnt_us <= 20'd1)
begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else if(WR_CC_BE[bit_cnt] == 1'b0)
begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else if(WR_CC_BE[bit_cnt] == 1'b1)
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
RD_TEMP :
if(cnt_us <= 1)
begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end
else
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
default:
begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
endcase
//data_temp
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_temp <= 16'b0;
else if((state == RD_TEMP) && (cnt_us == 20'd13))
data_temp <= {dq,data_temp[15:1]};
else
data_temp <= data_temp;
//data
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 20'd1;
else if((state == RD_TEMP) && (bit_cnt == 4'd15) && (cnt_us == 20'd60)
&& (data_temp[15] == 1'b0))
data <= data_temp[10:0];
else if((state == RD_TEMP) && (bit_cnt == 4'd15) && (cnt_us == 20'd60)
&& (data_temp[15] == 1'b1))
data <= ~data_temp[10:0] + 1;
endmodule
5.3 seg_dynamic.v
module seg_dynamic
#(
parameter CNT_MAX = 17'd99_999
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [26:0] data ,
output reg [7:0] sel ,
output reg [7:0] seg
);
wire [3:0] in ;
wire [3:0] ten ;
wire [3:0] hun ;
wire [3:0] tho ;
wire [3:0] ten_tho ;
wire [3:0] hun_tho ;
wire [3:0] mil ;
wire [3:0] must ;
reg [3:0] seg_data ;
reg [2:0] cnt_sel ;
reg [16:0] cnt_1ms ;
reg flag_1ms ;
//cnt_1ms:1ms循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1ms <= 17'd0;
else if(cnt_1ms == CNT_MAX)
cnt_1ms <= 17'd0;
else
cnt_1ms <= cnt_1ms + 1'b1;
//flag_1ms:1ms标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_1ms <= 1'b0;
else if(cnt_1ms == CNT_MAX - 1'b1)
flag_1ms <= 1'b1;
else
flag_1ms <= 1'b0;
//cnt_sel:从0到7循环数,用于选择当前显示的数码管
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sel <= 3'd0;
else if((cnt_sel == 3'd7) && (flag_1ms == 1'b1))
cnt_sel <= 3'd0;
else if(flag_1ms == 1'b1)
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= cnt_sel;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg_data <= 8'b0000_0011;
else
begin
case(cnt_sel)
3'd0: seg_data <= in ;
3'd1: seg_data <= ten ;
3'd2: seg_data <= hun ;
3'd3: seg_data <= tho ;
3'd4: seg_data <= ten_tho;
3'd5: seg_data <= hun_tho;
3'd6: seg_data <= mil ;
3'd7: seg_data <= must ;
endcase
end
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel <= 8'b0111_1111;
else if(flag_1ms == 1'b1)
begin
case(cnt_sel)
3'd0: sel <= 8'b1111_1110;
3'd1: sel <= 8'b1111_1101;
3'd2: sel <= 8'b1111_1011;
3'd3: sel <= 8'b1111_0111;
3'd4: sel <= 8'b1110_1111;
3'd5: sel <= 8'b1101_1111;
3'd6: sel <= 8'b1011_1111;
3'd7: sel <= 8'b0111_1111;
endcase
end
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg <= 8'b0000_0011;
else if(flag_1ms == 1'b1)
begin
case(seg_data)
4'd0: seg <= 8'b0000_0011;
4'd1: seg <= 8'b1001_1111;
4'd2: seg <= 8'b0010_0101;
4'd3: seg <= 8'b0000_1101;
4'd4: seg <= 8'b1001_1001;
4'd5: seg <= 8'b0100_1001;
4'd6: seg <= 8'b0100_0001;
4'd7: seg <= 8'b0001_1111;
4'd8: seg <= 8'b0000_0001;
4'd9: seg <= 8'b0000_1001;
endcase
end
else
seg <= seg;
bcd_8421 bcd_8421_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.data (data ),
.in (in ), //个
.ten (ten ), //十
.hun (hun ), //百
.tho (tho ), //千
.ten_tho (ten_tho ), //万
.hun_tho (hun_tho ), //十万
.mil (mil ), //百万
.must (must ) //千万
);
endmodule
5.4 bcd_8421.v
module bcd_8421
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [26:0] data ,
output reg [3:0] in , //个
output reg [3:0] ten , //十
output reg [3:0] hun , //百
output reg [3:0] tho , //千
output reg [3:0] ten_tho , //万
output reg [3:0] hun_tho , //十万
output reg [3:0] mil , //百万
output reg [3:0] must //千万
);
reg [4:0] cnt_shift ;
reg [58:0] data_shift ;
reg shift_flag ;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_shift <= 5'd0;
else if((cnt_shift == 5'd28) && (shift_flag == 1'b1))
cnt_shift <= 5'd0;
else if(shift_flag == 1'b1)
cnt_shift <= cnt_shift + 1'b1;
else
cnt_shift <= cnt_shift;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_shift <= 59'd0;
else if(cnt_shift == 5'd0)
data_shift <= {32'b0,data};
else if((cnt_shift <= 5'd27) && (shift_flag == 1'b0))
begin
data_shift[30:27] <= (data_shift[30:27] > 4) ? (data_shift[30:27] + 2'd3) : (data_shift[30:27]);
data_shift[34:31] <= (data_shift[34:31] > 4) ? (data_shift[34:31] + 2'd3) : (data_shift[34:31]);
data_shift[38:35] <= (data_shift[38:35] > 4) ? (data_shift[38:35] + 2'd3) : (data_shift[38:35]);
data_shift[42:39] <= (data_shift[42:39] > 4) ? (data_shift[42:39] + 2'd3) : (data_shift[42:39]);
data_shift[46:43] <= (data_shift[46:43] > 4) ? (data_shift[46:43] + 2'd3) : (data_shift[46:43]);
data_shift[50:47] <= (data_shift[50:47] > 4) ? (data_shift[50:47] + 2'd3) : (data_shift[50:47]);
data_shift[54:51] <= (data_shift[54:51] > 4) ? (data_shift[54:51] + 2'd3) : (data_shift[54:51]);
data_shift[58:55] <= (data_shift[58:55] > 4) ? (data_shift[58:55] + 2'd3) : (data_shift[58:55]);
end
else if((cnt_shift <= 5'd27) && (shift_flag == 1'b1))
data_shift <= data_shift << 1;
else
data_shift <= data_shift;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
in <= 4'b0;
ten <= 4'b0;
hun <= 4'b0;
tho <= 4'b0;
ten_tho <= 4'b0;
hun_tho <= 4'b0;
mil <= 4'b0;
must <= 4'b0;
end
else if(cnt_shift == 5'd28)
begin
in <= data_shift[30:27];
ten <= data_shift[34:31];
hun <= data_shift[38:35];
tho <= data_shift[42:39];
ten_tho <= data_shift[46:43];
hun_tho <= data_shift[50:47];
mil <= data_shift[54:51];
must <= data_shift[58:55];
end
endmodule
6. NEXYS4_DDR迪芝伦XC7A100TCSG324-1型的原理图与管脚绑定
直接选择 JA4 端口,即 G17作为 inout 引脚
ds18b20.xdc
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports dq]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[0]}]
set_property PACKAGE_PIN E3 [get_ports sys_clk]
set_property PACKAGE_PIN J15 [get_ports sys_rst_n]
set_property PACKAGE_PIN G17 [get_ports dq]
set_property PACKAGE_PIN J17 [get_ports {sel[0]}]
set_property PACKAGE_PIN J18 [get_ports {sel[1]}]
set_property PACKAGE_PIN T9 [get_ports {sel[2]}]
set_property PACKAGE_PIN J14 [get_ports {sel[3]}]
set_property PACKAGE_PIN P14 [get_ports {sel[4]}]
set_property PACKAGE_PIN T14 [get_ports {sel[5]}]
set_property PACKAGE_PIN K2 [get_ports {sel[6]}]
set_property PACKAGE_PIN U13 [get_ports {sel[7]}]
set_property PACKAGE_PIN H15 [get_ports {seg[0]}]
set_property PACKAGE_PIN L18 [get_ports {seg[1]}]
set_property PACKAGE_PIN T11 [get_ports {seg[2]}]
set_property PACKAGE_PIN P15 [get_ports {seg[3]}]
set_property PACKAGE_PIN K13 [get_ports {seg[4]}]
set_property PACKAGE_PIN K16 [get_ports {seg[5]}]
set_property PACKAGE_PIN R10 [get_ports {seg[6]}]
set_property PACKAGE_PIN T10 [get_ports {seg[7]}]