1,由于使用cnt_base 做echo回响信号高电平时间的测量,它的数据应该很大,位宽也很大。也可以采用cnt_us计数器,计算这个高电平时间的。我为了精确计算距离,所以才仍然用的cnt_base计数器。
2,在RESPOUND状态下,cnt_base归零条件写错了。呜呜。
因为这个add_cnt_base信号是我写代码时后加上去的,没有画它的时序图。也是我对时序逻辑赋值延后条件一个时钟周期的认识还不够深刻吧。导致这个归零条件错了一个sys_clk.
Error:(vsim-3601) Iteration limit reached at time 55445 ns.(仿真时遇到的)
在55445ns的时候,超出了迭代的限制。一般modelsim的迭代限制为5000次。
一般认为出现这种错误,是因为在代码里面出现了回环,通常是组合电路的问题。比方说在一个组合逻辑块里面,对敏感变量进行赋值。
作为敏感变量,只要变化,就会触发组合逻辑块的赋值,而赋值又会立马让敏感变量变化,然后再触发组合逻辑块赋值。
这样循环往复,每次触发变化的时间,是几乎可以忽略不计的。一旦敏感变量触发组合电路的赋值,便会不断地,触发--赋值--触发---赋值。。。
并且组合电路动作,几乎不花时间,这样实际上就是一个死循环。
解决办法:找到代码中采用电平敏感描述组合的逻辑块,查找问题;具体,就是避免在敏感变量A所触发的逻辑块中,再次对敏感变量A进行赋值操作。
hc_sr04的代码里64行,就是活生生的例子。
module hc_sr04 (
input wire sys_clk ,
input wire sys_rst_n ,
input wire echo ,
output reg trig ,
output reg [19:0] distance
);
// parameter
parameter MS_500 = 20'd499_999 ;
// localparam
localparam WAIT_500MS = 3'b001 ,
TRIGER = 3'b010 ,
RESPOUND = 3'b100 ;
// wire signal define
wire flag_base ;
wire nege ;
wire pose ;
wire WAIT_500MStoTRIGER ;
wire TRIGERtoRESPOUND ;
wire RESPOUNDtoWAIT_500MS;
// reg signal define
reg echo_reg0 ;
reg echo_reg1 ;
reg echo_reg2 ;
reg flag ;
reg add_cnt_base;
reg [2:0] state_c ;
reg [2:0] state_n ;
reg [31:0] cnt_base ;
reg [19:0] cnt_us ;
/*******************************************************************************/
// wire flag_base;
assign flag_base = (cnt_base == 49) ? 1'b1 : 1'b0 ;
// wire flag ;
// assign flag = (state_c != RESPOUND) ? ((state_c == WAIT_500MS && cnt_us == MS_500) ? 1'b1 : (state_c == TRIGER && cnt_us == 10) ? 1'b1 : 1'b0) : 1'b0 ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
flag <= 0 ;
end else begin
case (state_c)
WAIT_500MS: begin
if(cnt_us == MS_500) begin
flag <= 1 ;
end else begin
flag <= 0 ;
end
end
TRIGER : begin
if(cnt_us == 10) begin
flag <= 1 ;
end else begin
flag <= 0 ;
end
end
RESPOUND : flag <= 0 ;
default : flag <= 0 ;
endcase
end
end
// wire nege ;
// wire pose ;
assign nege = ~echo_reg1 && echo_reg2 ;
assign pose = echo_reg1 && ~echo_reg2 ;
// // wire add_cnt_base;
// assign add_cnt_base = (pose || nege) ? ~add_cnt_base : 1'b0 ; 这里产生了迭代。不利于仿真,所以改成时序逻辑。
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
add_cnt_base <= 1'b0 ;
end else begin
if(pose || nege) begin
add_cnt_base <= ~add_cnt_base ;
end else begin
add_cnt_base <= add_cnt_base ;
end
end
end
// reg signal define
// reg echo_reg0;
// reg echo_reg1;
// reg echo_reg2;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
echo_reg0 <= 1'b0 ;
echo_reg1 <= 1'b0 ;
echo_reg2 <= 1'b0 ;
end else begin
echo_reg0 <= echo ;
echo_reg1 <= echo_reg0 ;
echo_reg2 <= echo_reg1 ;
end
end
// reg [2:0] state_c ;
// reg [2:0] state_n ; 三段式状态机,状态转移描述,状态转移条件描述,与状机有关信号描述
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
state_c <= WAIT_500MS ;
end else begin
state_c <= state_n ;
end
end
always @(*) begin
case (state_c)
WAIT_500MS :begin
if(WAIT_500MStoTRIGER) begin
state_n <= TRIGER ;
end else begin
state_n <= WAIT_500MS ;
end
end
TRIGER :begin
if(TRIGERtoRESPOUND) begin
state_n <= RESPOUND ;
end else begin
state_n <= TRIGER ;
end
end
RESPOUND :begin
if(RESPOUNDtoWAIT_500MS) begin
state_n <= WAIT_500MS ;
end else begin
state_n <= RESPOUND ;
end
end
default:state_n <= WAIT_500MS ;
endcase
end
assign WAIT_500MStoTRIGER = (state_c == WAIT_500MS) && (flag_base && flag) ;
assign TRIGERtoRESPOUND = (state_c == TRIGER ) && (flag_base && flag) ;
assign RESPOUNDtoWAIT_500MS = (state_c == RESPOUND ) && (nege) ;
// reg [19:0] cnt_base ; // 用来产生1us信号,也用来计算距离。
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
cnt_base <= 32'd0 ;
end else begin
case (state_c)
WAIT_500MS :begin
if(cnt_base == 49) begin
cnt_base <= 32'd0 ;
end else begin
cnt_base <= cnt_base + 1'b1 ;
end
end
TRIGER :begin
if(cnt_base == 49) begin
cnt_base <= 32'd0 ;
end else begin
cnt_base <= cnt_base + 1'b1 ;
end
end
RESPOUND :begin
if(nege) begin
cnt_base <= 32'd0 ;
end else begin
if(add_cnt_base) begin
cnt_base <= cnt_base + 1'b1 ;
end else begin
cnt_base <= cnt_base ;
end
end
end
default:cnt_base <= 32'd0 ;
endcase
end
end
// reg [19:0] cnt_us ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
cnt_us <= 20'd0 ;
end else begin
case (state_c)
WAIT_500MS: begin
if(flag_base && cnt_us == MS_500) begin
cnt_us <= 20'd0 ;
end else begin
if(flag_base) begin
cnt_us <= cnt_us + 1'b1 ;
end else begin
cnt_us <= cnt_us ;
end
end
end
TRIGER : begin
if(flag_base && cnt_us == 10) begin
cnt_us <= 20'd0 ;
end else begin
if(flag_base) begin
cnt_us <= cnt_us + 1'b1 ;
end else begin
cnt_us <= cnt_us ;
end
end
end
RESPOUND :cnt_us <= 20'd0 ;
default: cnt_us <= 20'd0 ;
endcase
end
end
// reg trig ,
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
trig <= 1'b0 ;
end else begin
if(state_c == TRIGER) begin
trig <= 1'b1 ;
end else begin
trig <= 1'b0 ;
end
end
end
// reg [19:0] distance
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n) begin
distance <= 20'd0 ;
end else begin
if(nege) begin
distance <= (cnt_base * 20'd34 / 20'd10000) ;
end else begin
distance <= distance ;
end
end
end
endmodule
module top(
input wire sys_clk ,
input wire sys_rst_n ,
input wire echo ,
output wire trig ,
output wire ds ,
output wire oe ,
output wire shcp ,
output wire stcp
);
// 例化间连线
wire [19:0] distance_w ;
wire [05:0] point_w ;
wire sign_w ;
wire seg_en_w ;
assign point_w = 6'b000_010 ;
assign sign_w = 1'b0 ;
assign seg_en_w= 1'b1 ;
hc_sr04 hc_sr04_insert(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.echo ( echo ) ,
.trig ( trig ) ,
.distance ( distance_w )
);
seg_595_dynamic seg_595_dynamic_insert(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.data ( distance_w ) ,
.point ( point_w ) ,
.sign ( sign_w ) ,
.seg_en ( seg_en_w ) ,
.ds ( ds ) ,
.oe ( oe ) ,
.shcp ( shcp ) ,
.stcp ( stcp )
);
endmodule