本想着一天发一个实验的,这个ds18b20,耗时两天。代码写了两次,呜呜~
由于第二次写代码没画时序图,所以代码和时序图一些参数有些不一致,但问题不大。
这里有几件事情值得一提:
1:关于状态机的编写,我觉得还是三段式比较好。
2:关于生成其他时钟信号,用来做触发边沿。我不喜欢用这种方法(提一个概念“全局时钟网络”)。所以用产生一个1us base基础计时器,产生一个1us的标志信号。之后的计数器与该计数器级联,记得把<end_cnt_base>这个标志信号加上。
我犯下的错误:
1:在画时序图是,没有画<end_cnt_base>标志信号,直接默认时钟为周期为1us,造成了混乱。所以以后要注意。
2:&& 逻辑写成了 || 逻辑
3:三态门输出 Z 写成了 1
4:数据位宽定义错误,因为少思考了一个数据对应的位宽。
4:读取温度时,少记一位。注意data_bit跳转条件,和发指令时不一样的。
module ds18b20(
input wire sys_clk ,
input wire sys_rst_n ,
inout wire dq ,
output reg [19:0] data ,
output reg sign
);
// localparam 指令,先发低位。
localparam WR_CMD_WORD = 16'h44CC ,
RD_CMD_WORD = 16'hBECC ;
localparam INIT = 6'b000_001 ,
WR_CMD = 6'b000_010 ,
WAIT = 6'b000_100 ,
INIT_AGIN = 6'b001_000 ,
RD_CMD = 6'b010_000 ,
RD_TEMP = 6'b100_000 ;
// wire signal define
wire end_cnt_base ;
wire INITtoWR_CMD ;
wire WR_CMDtoWAIT ;
wire WAITtoINIT_AGIN ;
wire INIT_AGINtoRD_CMD ;
wire RD_CMDtoRD_TEMP ;
wire RD_TEMPtoINIT ;
// reg signal define
reg [5:0] cnt_base ;
reg dq_en ;
reg dq_out ;
reg [5:0] state_c /*synthesis preserve*/;
reg [5:0] state_n /*synthesis preserve*/;
reg [19:0] cnt ;
reg [4:0] data_bit ;
reg flag_respond ;
reg data_done ;
reg [15:0] data_temp ; // 读取高速缓存器的byte0和byte1,一共16位。
/****************************************************************************************/
// reg [5:0] cnt_base ;
// wire end_cnt_base ;
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
cnt_base <= 6'd0 ;
else if(end_cnt_base)
cnt_base <= 6'd0 ;
else
cnt_base <= cnt_base + 1'b1 ;
assign end_cnt_base = cnt_base == 49;
// reg [5:0] state_c ;
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
state_c <= INIT;
else
state_c <= state_n ;
// reg [5:0] state_n ;
always @(*)
case (state_c)
INIT :if(INITtoWR_CMD)
state_n <= WR_CMD ;
else
state_n <= INIT ;
WR_CMD :if(WR_CMDtoWAIT)
state_n <= WAIT ;
else
state_n <= WR_CMD ;
WAIT :if(WAITtoINIT_AGIN)
state_n <= INIT_AGIN ;
else
state_n <= WAIT ;
INIT_AGIN :if(INIT_AGINtoRD_CMD)
state_n <= RD_CMD ;
else
state_n <= INIT_AGIN ;
RD_CMD :if(RD_CMDtoRD_TEMP)
state_n <= RD_TEMP ;
else
state_n <= RD_CMD ;
RD_TEMP :if(RD_TEMPtoINIT)
state_n <= INIT ;
else
state_n <= RD_TEMP ;
default : state_n <= INIT ;
endcase
// 状态转移条件
assign INITtoWR_CMD = (state_c == INIT ) && (end_cnt_base && flag_respond == 1'b1 && cnt == 999);
assign WR_CMDtoWAIT = (state_c == WR_CMD ) && (end_cnt_base ==1'b1 && cnt == 60 && data_bit == 15) ;
assign WAITtoINIT_AGIN = (state_c == WAIT ) && (end_cnt_base && cnt == 749_999) ;
assign INIT_AGINtoRD_CMD = (state_c == INIT_AGIN ) && (end_cnt_base && flag_respond == 1'b1 && cnt == 999);
assign RD_CMDtoRD_TEMP = (state_c == RD_CMD ) && (end_cnt_base ==1'b1 && cnt == 60 && data_bit == 15) ;
assign RD_TEMPtoINIT = (state_c == RD_TEMP ) && (end_cnt_base ==1'b1 && cnt == 60 && data_done == 1'b1);
// reg [19:0] cnt ;
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
cnt <= 20'd0 ;
else case (state_c)
INIT : if(cnt == 999 && end_cnt_base == 1'b1)
cnt <= 20'd0 ;
else if(end_cnt_base == 1'b1)
cnt <= cnt + 1'b1 ;
WR_CMD : if(cnt == 60 && end_cnt_base == 1'b1)
cnt <= 20'd0 ;
else if(end_cnt_base == 1'b1)
cnt <= cnt + 1'b1 ;
WAIT : if(cnt == 749_999 && end_cnt_base == 1'b1)
cnt <= 20'd0 ;
else if(end_cnt_base == 1'b1)
cnt <= cnt + 1'b1 ;
INIT_AGIN : if(cnt == 999 && end_cnt_base == 1'b1)
cnt <= 20'd0 ;
else if(end_cnt_base == 1'b1)
cnt <= cnt + 1'b1 ;
RD_CMD : if(cnt == 60 && end_cnt_base == 1'b1)
cnt <= 20'd0 ;
else if(end_cnt_base == 1'b1)
cnt <= cnt + 1'b1 ;
RD_TEMP : if(cnt == 60 && end_cnt_base == 1'b1)
cnt <= 20'd0 ;
else if(end_cnt_base == 1'b1)
cnt <= cnt + 1'b1 ;
default : cnt <= 20'd0 ;
endcase
// reg [3:0] data_bit ;
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
data_bit <= 5'd0 ;
else case (state_c)
INIT : data_bit <= 5'd0 ;
WR_CMD : if(end_cnt_base == 1'b1 && cnt == 60 && data_bit == 15)
data_bit <= 5'd0 ;
else if(end_cnt_base == 1'b1 && cnt == 60)
data_bit <= data_bit + 1'b1 ;
else
data_bit <= data_bit ;
WAIT : data_bit <= 5'd0 ;
INIT_AGIN : data_bit <= 5'd0 ;
RD_CMD : if(end_cnt_base == 1'b1 && cnt == 60 && data_bit == 15)
data_bit <= 5'd0 ;
else if(end_cnt_base == 1'b1 && cnt == 60)
data_bit <= data_bit + 1'b1 ;
else
data_bit <= data_bit ;
RD_TEMP : if(end_cnt_base == 1'b1 && cnt == 10 && data_bit == 16) // 第十微秒的时候采样。
data_bit <= 5'd0 ;
else if(end_cnt_base == 1'b1 && cnt == 10)
data_bit <= data_bit + 1'b1 ;
else
data_bit <= data_bit ;
default : data_bit <= 5'd0 ;
endcase
// reg flag_respond ;
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
flag_respond <= 1'b0 ;
else if(state_c != INIT && state_c != INIT_AGIN)
flag_respond <= 1'b0 ;
else if((state_c == INIT || state_c == INIT_AGIN) && cnt == 590 && dq == 1'b0)
flag_respond <= 1'b1 ;
else
flag_respond <= flag_respond ;
// reg data_done ;
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
data_done <= 1'b0 ;
else if(state_c != RD_TEMP)
data_done <= 1'b0 ;
else if(state_c == RD_TEMP && end_cnt_base == 1'b1 && data_bit == 16)
data_done <= 1'b1 ;
else
data_done <= data_done ;
// reg [15:0] data_temp ;
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
data_temp <= 16'd0 ;
else if(state_c == RD_TEMP && end_cnt_base == 1'b1 && cnt == 13)
data_temp <= {dq,data_temp[15:1]} ;
else
data_temp <= data_temp ;
// reg dq_en ;
// reg dq_out ;
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 (state_c)
INIT : begin
if(cnt >= 0 && cnt <= 499) 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(cnt == 60) begin
dq_en <= 1'b0 ;
dq_out <= 1'b0 ;
end else begin
if(WR_CMD_WORD[data_bit] == 1'b1) begin
if(cnt >= 0 && cnt <= 14) begin
dq_en <= 1'b1 ;
dq_out <= 1'b0 ;
end else begin
dq_en <= 1'b0 ;
dq_out <= 1'b0 ;
end
end else begin
dq_en <= 1'b1 ;
dq_out <= 1'b0 ;
end
end
end
WAIT : begin
dq_en <= 1'b1 ;
dq_out <= 1'b1 ;
end
INIT_AGIN: begin
if(cnt >= 0 && cnt <= 499) 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(cnt == 60) begin
dq_en <= 1'b0 ;
dq_out <= 1'b0 ;
end else begin
if(RD_CMD_WORD[data_bit] == 1'b1) begin
if(cnt >= 0 && cnt <= 14) begin
dq_en <= 1'b1 ;
dq_out <= 1'b0 ;
end else begin
dq_en <= 1'b0 ;
dq_out <= 1'b0 ;
end
end else begin
dq_en <= 1'b1 ;
dq_out <= 1'b0 ;
end
end
end
RD_TEMP : begin
if(cnt == 0 || cnt == 1) 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
/***********************************************************************/
// wire dq
assign dq = (dq_en == 1'b1) ? dq_out : 1'bz ;
// reg [19:0] data
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
data <= 20'd0 ;
else if(state_c == RD_TEMP && data_done == 1'b1)
if(data_temp[15] == 1'b0)
data <= data_temp[10:0] * 10'd625;
else
data <= (~data_temp[10:0] + 1'b1 ) * 10'd625;
else
data <= data ;
// reg sign
always @(posedge sys_clk or negedge sys_rst_n)
if(~sys_rst_n)
sign <= 1'b0 ;
else if(state_c == RD_TEMP && data_done == 1'b1)
sign <= data_temp[15];
else
sign <= sign ;
endmodule
module top(
input wire sys_clk ,
input wire sys_rst_n ,
inout wire dq ,
output wire ds ,
output wire oe ,
output wire shcp ,
output wire stcp
);
wire [19:0] data_w /*synthesis keep */;
wire sign_w ;
wire [05:00] point_w ;
wire seg_en_w ;
assign seg_en_w= 1'b1 ;
assign point_w = 6'b010_000 ;
ds18b20 ds18b20_insert(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.dq ( dq ) ,
.data ( data_w ) ,
.sign ( sign_w )
);
seg_595_dynamic seg_595_dynamic_insert(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.data ( data_w ) ,
.point ( point_w ) ,
.sign ( sign_w ) ,
.seg_en ( seg_en_w ) ,
.ds ( ds ) ,
.oe ( oe ) ,
.shcp ( shcp ) ,
.stcp ( stcp )
);
endmodule