一、ds18b20基本时序
- ds18b20器件为单wire通信模式,即采用三态进行输入输出的控制。三态控制原理如下:
- ds18b20器件的三种时序关系如下:
相关器件的时序关系,网上资料比较多,笔者这里就只给出关键部分了。
3.三段式状态机具体代码如下(参考了相关资料)
/*
相较于一段式、二段式状态机,三段式状态机更易于优化和理解,笔者参考相关资料,
剔除了一些先入为主的思想,而且做到了一个always只给一个变量赋值,而且使用全局时钟,
不使用简单分频出来的“时钟“作为其主时钟
*/
timescale 1ns/1ns
module ds18b20_ctrl(
input wire sys_clk ,
input wire sys_rst_n ,
inout wire dq ,
output reg [19:0] data_out ,
output reg sign
);
parameter INIT_1 = 6'b000_001;
parameter WR_CMD = 6'b000_010;
parameter WAIT = 6'b000_100;
parameter INIT_2 = 6'b001_000;
parameter RD_CMD = 6'b010_000;
parameter RD_TEM = 6'b100_000;
parameter WR_CMD_DATA = 16'h44cc;
parameter RD_CMD_DATA = 16'hbecc;
reg [5:0] cur_state ;
reg [5:0] next_state ;
parameter CNT_DIV_1US = 6'd49;
reg [5:0] cnt_div_1us;
reg en_1us;
reg [19:0] cnt_1us;
reg dq_en ;
reg dq_out ;
reg [3:0] cnt_bit ;
reg flag ;
reg [15:0] data_reg;
reg [10:0] temp_reg;
assign dq = ((dq_en==1'b1)?(dq_out):(1'bz));
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
cnt_div_1us <= 6'd0;
end else if(cnt_div_1us==CNT_DIV_1US) begin
cnt_div_1us <= 6'd0;
end else begin
cnt_div_1us <= cnt_div_1us + 1'b1;
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
en_1us <= 1'b0;
end else if(cnt_div_1us==(CNT_DIV_1US-1'b1)) begin
en_1us <= 1'b1;
end else begin
en_1us <= 1'b0;
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
cnt_1us <= 20'd0;
end else if((((cur_state==INIT_1)||(cur_state==INIT_2)))&&
(cnt_1us==20'd999)&&(en_1us==1'b1)) begin
cnt_1us <= 20'd0;
end else if((cur_state==WAIT) &&(cnt_1us==20'd74_9999)&&(en_1us==1'b1))
begin
cnt_1us <= 20'd0;
end else if((((cur_state==WR_CMD)||(cur_state==RD_CMD)))&&
(cnt_1us==20'd64)&&(cnt_bit==4'd15)&&(en_1us==1'b1)) begin
cnt_1us <= 20'd0;
end else if((((cur_state==WR_CMD)||(cur_state==RD_CMD)))&&
(cnt_1us==20'd64)&&(en_1us==1'b1)) begin
cnt_1us <= 20'd0;
end else if(en_1us==1'b1) begin
cnt_1us <= cnt_1us + 1'b1;
end else begin
cnt_1us <= cnt_1us;
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
cnt_bit <= 4'd0;
end else if(((cur_state==WR_CMD)||(cur_state==RD_CMD))&&(cnt_1us==20'd64)&&
(cnt_bit==4'd15)&&(en_1us==1'b1)) begin
cnt_bit <= 4'd0;
end else if(((cur_state==WR_CMD)||(cur_state==RD_CMD))&&(cnt_1us==20'd64)&&
(en_1us==1'b1)) begin
cnt_bit <= cnt_bit + 1'b1;
end else begin
cnt_bit <= cnt_bit;
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
flag <= 1'b0;
end else if(((cur_state==INIT_1)||(cur_state==INIT_2))&&(cnt_1us==20'd570)&&
(dq==1'b0)&&(en_1us==1'b1)) begin
flag <= 1'b1;
end else if(((cur_state==INIT_1)||(cur_state==INIT_2))&&(cnt_1us==20'd999)&&
(en_1us==1'b1)) begin
flag <= 1'b0;
end else begin
flag <= flag;
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
cur_state <= INIT_1;
end else begin
cur_state <= next_state;
end
end
always@(*) begin
next_state = INIT_1;
case(cur_state)
INIT_1 : begin
if((cnt_1us==20'd999)&&(flag==1'b1)&&(en_1us==1'b1)) begin
next_state = WR_CMD;
end else begin
next_state = INIT_1;
end
end
WR_CMD : begin
if((cnt_bit==4'd15)&&(cnt_1us==20'd64)&&(en_1us==1'b1)) begin
next_state = WAIT;
end else begin
next_state = WR_CMD;
end
end
WAIT : begin
if(cnt_1us==20'd74_9999) begin
next_state = INIT_2;
end else begin
next_state = WAIT;
end
end
INIT_2 : begin
if((cnt_1us==20'd999)&&(flag==1'b1)&&(en_1us==1'b1)) begin
next_state = RD_CMD;
end else begin
next_state = INIT_2;
end
end
RD_CMD : begin
if((cnt_bit==4'd15)&&(cnt_1us==20'd64)&&(en_1us==1'b1)) begin
next_state = RD_TEM;
end else begin
next_state = WR_CMD;
end
end
RD_TEM : begin
if((cnt_bit==4'd15)&&(cnt_1us==20'd64)&&(en_1us==1'b1)) begin
next_state = INIT_1;
end else begin
next_state = RD_TEM;
end
end
default: next_state = INIT_1;
endcase
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end else begin
case(next_state)
INIT_1 : begin
if(cnt_1us<=20'd499) begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end else begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
end
WR_CMD : begin
if(WR_CMD_DATA[cnt_bit]==1'b0) begin
if(cnt_1us<=10'd62) begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end else begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
end else begin
if(cnt_1us<=10'd1) begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end else begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
end
end
WAIT : begin
dq_en <= 1'b1;
dq_out <= 1'b1;
end
INIT_2 : begin
if(cnt_1us<=20'd499) begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end else begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
end
RD_CMD : begin
if(RD_CMD_DATA[cnt_bit]==1'b0) begin
if(cnt_1us<=10'd62) begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end else begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
end else begin
if(cnt_1us<=10'd1) begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end else begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
end
end
RD_TEM : begin
if(cnt_1us<=20'd1) begin
dq_en <= 1'b1;
dq_out <= 1'b0;
end else begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
end
default: begin
dq_en <= 1'b0;
dq_out <= 1'b0;
end
endcase
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
data_reg <= 16'd0;
end else if((cur_state==RD_TEM)&&(cnt_1us==20'd10)) begin
data_reg <= {dq,data_reg[15:1]};
end else begin
data_reg <= data_reg;
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
temp_reg <= 11'd0;
end else if((data_reg[15]==1'b0)&&(cur_state==RD_TEM)&&(cnt_bit==4'd15)&&(cnt_1us==20'd60)) begin
temp_reg <= data_reg[10:0];
end else if((data_reg[15]==1'b1)&&(cur_state==RD_TEM)&&(cnt_bit==4'd15)&&(cnt_1us==20'd60)) begin
temp_reg <= ~data_reg[10:0] + 1'b1;
end else begin
temp_reg <= temp_reg;
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
data_out <= 20'd0;
end else begin
data_out <= temp_reg * 625 / 10;
end
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
sign <= 1'b0;
end else if((data_reg[15]==1'b1)&&(cur_state==RD_TEM)&&(cnt_bit==4'd15)&&(cnt_1us==20'd60)) begin
sign <= 1'b1;
end else if((data_reg[15]==1'b0)&&(cur_state==RD_TEM)&&(cnt_bit==4'd15)&&(cnt_1us==20'd60)) begin
sign <= 1'b0;
end else begin
sign <= sign;
end
end
endmodule
```
4.后续出现的几个问题(待解决)
- WAIT状态下是需等待750000us,即cnt_1us计数到749999,由于时序逻辑,
输出滞后状态一个系统时钟,而且dq_en,dq_out应该全为高,可是抓出来的两个信号,
***却在WAIT和INIT_2交替处,拉低了一个系统时钟***,百思不得其解~~
- 编译时出现warnings:
Warning (332060): Node: sys_clk was determined to be a clock
but was found without an associated clock assignment.
Critical Warning (332168): The following clock transfers have no clock
uncertainty assignment. For more accurate results, apply clock uncertainty
assignments or use the derive_clock_uncertainty command.
Critical Warning (332169): From altera_reserved_tck (Rise) to
altera_reserved_tck (Rise) (setup and hold)
Critical Warning (332169): From altera_reserved_tck (Rise) to
altera_reserved_tck (Fall) (setup and hold)
整个工程编写花了较少时间,大部分时间都花在了调试debug上~~