Veriog中关于if else语句的问题,大神求救!
- reg [15:0]cnt1;
- reg [3:0]disp_dat;
- /**************************
- //第一部分
- always @( posedge i_50m_clk )
- begin
- if( !i_rst_n ) begin
- cnt1 <= 16'b0;
- disp_dat <= 4'b0;
- end
- else if( cnt1[15] ) disp_dat <= disp_dat + 4'b1;
- else cnt1 <= cnt1 + 16'b1;
- end
- ***************************/
- /**************************
- //第二部分
- always @( posedge i_50m_clk )
- begin
- if( !i_rst_n ) cnt1 <= 20'b0;
- else cnt1 <= cnt1 + 20'b1;
- end
- always @( posedge i_50m_clk or negedge i_rst_n )
- begin
- if( !i_rst_n ) disp_dat <= 4'b0;
- else if( cnt1==16‘h7fff) disp_dat <= disp_dat + 4'b1;
- end
- ***************************/
- /***********************
- 第三部分:
- reg [29:0]cnt;
- always @( posedge i_50m_clk or negedge i_rst_n )
- begin
- if( !i_rst_n ) cnt <= 30'b0;
- else cnt <= cnt + 30'b1;
- end
- reg [3:0]disp_dat;
- always@( cnt[15] )
- begin
- disp_dat <= cnt[19:16];
- end
- **************************/
- 下到板子上的现象:
- 第二部分结果显示是正确的,但是在最低位会特别的亮,并且显示为8(本来应该是0的)。
- 如果是第一部分,结果只显示最低位为8。
- 如果将第二部分改为else if( cnt1[15]) disp_dat <= disp_dat + 4'b1之后,结果显示就和第一部分一模一样。
- 第三部分的结果是完全正确的
- 问题一:
- 第一部分和第二部分,我感觉完全相同,但是编译以后下到板子上完全不一样的结果(现象描述如上)
- 问题二:
- 并且将第二部分中的else if( cnt1==16‘h7fff) disp_dat <= disp_dat + 4'b1;改为else if( cnt1[15]) disp_dat <= disp_dat + 4'b1;之后第二部分的结果又不一样了,这是为什么?
- 附上完整的程序:
- module seg_display( i_50m_clk,i_rst_n,o_sel,o_led_data );
- input i_50m_clk;
- input i_rst_n;
- output [7:0]o_sel;
- output [7:0]o_led_data;
- /***********************
- reg [29:0]cnt;
- always @( posedge i_50m_clk or negedge i_rst_n )
- begin
- if( !i_rst_n ) cnt <= 30'b0;
- else cnt <= cnt + 30'b1;
- end
- reg [3:0]disp_dat;
- always@( cnt[15] )
- begin
- disp_dat <= cnt[19:16];
- end
- **************************/
- reg [15:0]cnt1;
- reg [3:0]disp_dat;
- /**************************
- always @( posedge i_50m_clk )
- begin
- if( !i_rst_n ) begin
- cnt1 <= 20'b0;
- disp_dat <= 4'b0;
- end
- else if( cnt1[15] ) disp_dat <= disp_dat + 4'b1;
- else cnt1 <= cnt1 + 20'b1;
- end
- ****************************/
- always @( posedge i_50m_clk )
- begin
- if( !i_rst_n ) cnt1 <= 20'b0;
- else cnt1 <= cnt1 + 20'b1;
- end
- always @( posedge i_50m_clk or negedge i_rst_n )
- begin
- if( !i_rst_n ) disp_dat <= 4'b0;
- else if( cnt1==16'h7fff ) disp_dat <= disp_dat + 4'b1;
- end
- reg [7:0]o_sel_r;
- always@( disp_dat )
- begin
- case( disp_dat )
- 4'h0 : o_sel_r = 8'b11111110; //?
- 4'h1 : o_sel_r = 8'b11111101; //?
- 4'h2 : o_sel_r = 8'b11111011; //?
- 4'h3 : o_sel_r = 8'b11110111; //?
- 4'h4 : o_sel_r = 8'b11101111; //?
- 4'h5 : o_sel_r = 8'b11011111; //?
- 4'h6 : o_sel_r = 8'b10111111; //?
- 4'h7 : o_sel_r = 8'b01111111; //?
- endcase
- end
- parameter seg0 = 8'hc0,
- seg1 = 8'hf9,
- seg2 = 8'ha4,
- seg3 = 8'hb0,
- seg4 = 8'h99,
- seg5 = 8'h92,
- seg6 = 8'h82,
- seg7 = 8'hf8,
- seg8 = 8'h80,
- seg9 = 8'h90,
- sega = 8'h88,
- segb = 8'h83,
- segc = 8'hc6,
- segd = 8'ha1,
- sege = 8'h86,
- segf = 8'h8e;
- reg [7:0]o_led_data_r;
- always @( disp_dat )
- begin
- case( disp_dat )
- 4'b0000 : o_led_data_r <= seg0;
- 4'b0001 : o_led_data_r <= seg1;
- 4'b0010 : o_led_data_r <= seg2;
- 4'b0011 : o_led_data_r <= seg3;
- 4'b0100 : o_led_data_r <= seg4;
- 4'b0101 : o_led_data_r <= seg5;
- 4'b0110 : o_led_data_r <= seg6;
- 4'b0111 : o_led_data_r <= seg7;
- 4'b1000 : o_led_data_r <= seg8;
- 4'b1001 : o_led_data_r <= seg9;
- 4'b1010 : o_led_data_r <= sega;
- 4'b1011 : o_led_data_r <= segb;
- 4'b1100 : o_led_data_r <= segc;
- 4'b1101 : o_led_data_r <= segd;
- 4'b1110 : o_led_data_r <= sege;
- 4'b1111 : o_led_data_r <= segf;
- default : ;
- endcase
- end
- assign o_sel = o_sel_r;
- assign o_led_data = o_led_data_r;
- endmodule
二楼回答的很有精准!我稍微整理了一下。
第一部分和第二部分是完全不同的。
针对问题1:
1)为什么一直显示的是8呢? 必有原因! 根据你的码管译码,可以得出是低电平驱动数码管段。第一部分综合出来还是有一定的优先级别的,复位优先级最高,其次显示,最后计数。 关键就是在这个优先级别上了,注意显示和计数的顺序,是显示的级别高于计数的级别!可能你已经看出来了,当cnt[15]为1以后,显示部分不断的再重复,而计数部分却停止了! disp_dat 在50MHz的信号下,反复加1,数码管译码段从0-F一直进行,这一个周期只需要20*16 = 320nS,人眼根本反应不过来,这些个状态显示瞬间的执行过来,效果就是灯全部亮了,所以看到的就是一个8字。还可以透露一点的是,cnt=16'h8000,也就是刚好cnt[15]=1时,状态再也执行不下去了,不信? 用逻辑分析仪测试一下吧...呵呵
2)第二个的逻辑设计的是对的,但是速度太快了!拿纸拿笔,我们算算最低位的那个转换速度,算最长的周期吧,cnt1的位宽是20, 也就是计满2的20次方个时钟周期,就开始下一个轮回,50M晶振,周期是20ns,按照 总时间 = 个数*时钟周期时间 的公式计算,折算成秒为单位,这个过程大家都会,计算器按按就出来了,我的结果是0.02097152,约等于0.02s,也就是一个周期的时间太短了,前面的几个数勉强看得清楚,十位就是0.02s的十倍,百位就是0.02s的百倍,个数位上变化速度太快了,跟第一部分一样,所有状态瞬间执行过去看起来就是一个8字,跟第一部分相比,它执行的速度慢下来了许多,各个状态停留的时间还算比较“长”,所以最后一个码管显示的特别亮,这是有道理的。
针对问题2:
仔细分析了问题1的来源,问题2还是一个时钟速度太快的问题。不改之前,else if( cnt1==16‘h7fff) disp_dat <= disp_dat + 4'b1; 这个周期是 cnt1从第一个16'h7fff到下一个16'h7fff,时长约0.02s,但是改为else if( cnt1[15]) disp_dat <= disp_dat + 4'b1;后,表示的是cnt1[15]为1到下一个cnt1[15]为1的周期,这个周期可就大大缩短了,一起算算,计数就是2倍的0x8000,也就是2的16次方个,周期按 总时间=计数个数 * 时钟频率, 结果为65536 * 20ns ,折算成秒的单位,大约为0.0013秒,整个周期不到2个微秒,变化速度太快了,这时候数码管应该全部显示的都是8,看起来乱乱的。
=============================================
两个问题分析完了,第一个是设计上的问题,这个得重新改改,第二个是频率过快的问题,想办法降低下转换频率,试试把位宽加宽,从cnt[15]改成cnt[25],效果会好很多咯,不信? 改改尝试一下吧
你用的clk是50MHz吧?那么快的频率,一直在做,人眼分辨不出来,建议你分频后再试试(粗略的看了一下)
第一个问题:
第一部分和第二部分是完全不同的,cnt[15]和cnt=16'h7fff是不一样的,cnt[15]等于1可以有很多种可能,但cnt==7fff一次循环只会出现一次OK?
第二个问题:
换过来以后你的cnt1的计数方式发生了变化,第一部门计数cnt1在cnt1XXX_XXXX_XXXX_XXXX是不进行计数的,一直处于保持的,儿第二部分cnt1是自由计数的,完全不受控,区别就在这儿!
o_sel_r会产生latch!cnt[15]等于1 的时候低位可以是任何数哦,很多种可能,导致你两次的分频系数不一样!