犯下的错误:
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 ;// localparamlocalparam WAIT_500MS = 3'b001 ,TRIGER = 3'b010 ,RESPOUND = 3'b100 ;// wire signal definewire flag_base ;wire nege ;wire pose ;wire WAIT_500MStoTRIGER ; wire TRIGERtoRESPOUND ; wire RESPOUNDtoWAIT_500MS;// reg signal definereg 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) beginif(~sys_rst_n) beginflag <= 0 ;end else begincase (state_c)WAIT_500MS: beginif(cnt_us == MS_500) beginflag <= 1 ;end else beginflag <= 0 ;endendTRIGER : beginif(cnt_us == 10) beginflag <= 1 ;end else beginflag <= 0 ;endendRESPOUND : flag <= 0 ;default : flag <= 0 ;endcaseendend// 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) beginif(~sys_rst_n) beginadd_cnt_base <= 1'b0 ;end else beginif(pose || nege) beginadd_cnt_base <= ~add_cnt_base ;end else beginadd_cnt_base <= add_cnt_base ;endendend// reg signal define// reg echo_reg0;// reg echo_reg1;// reg echo_reg2;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) beginecho_reg0 <= 1'b0 ;echo_reg1 <= 1'b0 ;echo_reg2 <= 1'b0 ;end else beginecho_reg0 <= echo ;echo_reg1 <= echo_reg0 ;echo_reg2 <= echo_reg1 ;endend// reg [2:0] state_c ;// reg [2:0] state_n ; 三段式状态机,状态转移描述,状态转移条件描述,与状机有关信号描述always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) beginstate_c <= WAIT_500MS ;end else beginstate_c <= state_n ;endendalways @(*) begincase (state_c)WAIT_500MS :beginif(WAIT_500MStoTRIGER) beginstate_n <= TRIGER ;end else beginstate_n <= WAIT_500MS ;endendTRIGER :beginif(TRIGERtoRESPOUND) beginstate_n <= RESPOUND ;end else beginstate_n <= TRIGER ;endendRESPOUND :beginif(RESPOUNDtoWAIT_500MS) beginstate_n <= WAIT_500MS ;end else beginstate_n <= RESPOUND ;endenddefault:state_n <= WAIT_500MS ;endcaseendassign 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) beginif(~sys_rst_n) begincnt_base <= 32'd0 ;end else begincase (state_c)WAIT_500MS :beginif(cnt_base == 49) begincnt_base <= 32'd0 ;end else begincnt_base <= cnt_base + 1'b1 ;endendTRIGER :beginif(cnt_base == 49) begincnt_base <= 32'd0 ;end else begincnt_base <= cnt_base + 1'b1 ;endendRESPOUND :beginif(nege) begincnt_base <= 32'd0 ;end else beginif(add_cnt_base) begincnt_base <= cnt_base + 1'b1 ;end else begincnt_base <= cnt_base ;endendenddefault:cnt_base <= 32'd0 ;endcaseendend// reg [19:0] cnt_us ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) begincnt_us <= 20'd0 ;end else begincase (state_c)WAIT_500MS: beginif(flag_base && cnt_us == MS_500) begincnt_us <= 20'd0 ;end else beginif(flag_base) begincnt_us <= cnt_us + 1'b1 ;end else begincnt_us <= cnt_us ;endendendTRIGER : beginif(flag_base && cnt_us == 10) begincnt_us <= 20'd0 ;end else beginif(flag_base) begincnt_us <= cnt_us + 1'b1 ;end else begincnt_us <= cnt_us ;endendendRESPOUND :cnt_us <= 20'd0 ;default: cnt_us <= 20'd0 ;endcaseendend// reg trig ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) begintrig <= 1'b0 ;end else beginif(state_c == TRIGER) begintrig <= 1'b1 ;end else begintrig <= 1'b0 ;endendend// reg [19:0] distancealways @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) begindistance <= 20'd0 ;end else beginif(nege) begindistance <= (cnt_base * 20'd34 / 20'd10000) ;end else begindistance <= distance ;endendend
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