微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > Veriog中关于if else语句的问题,大神求救!

Veriog中关于if else语句的问题,大神求救!

时间:10-02 整理:3721RD 点击:
这是关于数码管动态扫描,扫描部分。

  1. reg [15:0]cnt1;
  2. reg [3:0]disp_dat;

  3. /**************************
  4. //第一部分
  5. always @( posedge i_50m_clk  )
  6. begin
  7.         if( !i_rst_n )        begin
  8.                 cnt1 <= 16'b0;
  9.                 disp_dat <= 4'b0;        
  10.         end
  11.         else if( cnt1[15] )        disp_dat <= disp_dat + 4'b1;
  12.         else        cnt1 <= cnt1 + 16'b1;
  13. end
  14. ***************************/
  15. /**************************
  16. //第二部分
  17. always @( posedge i_50m_clk  )
  18. begin
  19.         if( !i_rst_n )                cnt1 <= 20'b0;
  20.         else        cnt1 <= cnt1 + 20'b1;
  21. end

  22. always @( posedge i_50m_clk or negedge i_rst_n )
  23. begin
  24.         if( !i_rst_n )        disp_dat <= 4'b0;
  25.         else if( cnt1==16‘h7fff)        disp_dat <= disp_dat + 4'b1;        
  26. end
  27. ***************************/

  28. /***********************
  29. 第三部分:
  30. reg [29:0]cnt;               

  31. always @( posedge i_50m_clk or negedge i_rst_n )
  32. begin
  33.         if( !i_rst_n )        cnt <= 30'b0;
  34.         else cnt <= cnt + 30'b1;               
  35. end

  36. reg [3:0]disp_dat;

  37. always@( cnt[15] )
  38. begin
  39.         disp_dat <= cnt[19:16];
  40. end
  41. **************************/



  42. 下到板子上的现象:
  43. 第二部分结果显示是正确的,但是在最低位会特别的亮,并且显示为8(本来应该是0的)。
  44. 如果是第一部分,结果只显示最低位为8。
  45. 如果将第二部分改为else if( cnt1[15])        disp_dat <= disp_dat + 4'b1之后,结果显示就和第一部分一模一样。
  46. 第三部分的结果是完全正确的


  47. 问题一:
  48. 第一部分和第二部分,我感觉完全相同,但是编译以后下到板子上完全不一样的结果(现象描述如上)
  49. 问题二:
  50. 并且将第二部分中的else if( cnt1==16‘h7fff)        disp_dat <= disp_dat + 4'b1;改为else if( cnt1[15])        disp_dat <= disp_dat + 4'b1;之后第二部分的结果又不一样了,这是为什么?




  51. 附上完整的程序:
  52. module seg_display( i_50m_clk,i_rst_n,o_sel,o_led_data );

  53. input        i_50m_clk;
  54. input        i_rst_n;
  55. output        [7:0]o_sel;
  56. output        [7:0]o_led_data;
  57. /***********************
  58. reg [29:0]cnt;               

  59. always @( posedge i_50m_clk or negedge i_rst_n )
  60. begin
  61.         if( !i_rst_n )        cnt <= 30'b0;
  62.         else cnt <= cnt + 30'b1;               
  63. end

  64. reg [3:0]disp_dat;

  65. always@( cnt[15] )
  66. begin
  67.         disp_dat <= cnt[19:16];
  68. end
  69. **************************/

  70. reg [15:0]cnt1;
  71. reg [3:0]disp_dat;
  72. /**************************
  73. always @( posedge i_50m_clk  )
  74. begin
  75.         if( !i_rst_n )        begin
  76.                 cnt1 <= 20'b0;
  77.                 disp_dat <= 4'b0;        
  78.         end
  79.         else if( cnt1[15] )        disp_dat <= disp_dat + 4'b1;
  80.         else        cnt1 <= cnt1 + 20'b1;
  81. end
  82. ****************************/

  83. always @( posedge i_50m_clk  )
  84. begin
  85.         if( !i_rst_n )                cnt1 <= 20'b0;
  86.         else        cnt1 <= cnt1 + 20'b1;
  87. end

  88. always @( posedge i_50m_clk or negedge i_rst_n )
  89. begin
  90.         if( !i_rst_n )        disp_dat <= 4'b0;
  91.         else if( cnt1==16'h7fff )        disp_dat <= disp_dat + 4'b1;               
  92. end


  93. reg [7:0]o_sel_r;

  94. always@( disp_dat )
  95. begin
  96.         case( disp_dat )
  97.                 4'h0 : o_sel_r = 8'b11111110; //?
  98.                 4'h1 : o_sel_r = 8'b11111101; //?
  99.                 4'h2 : o_sel_r = 8'b11111011; //?
  100.                 4'h3 : o_sel_r = 8'b11110111; //?
  101.                 4'h4 : o_sel_r = 8'b11101111; //?
  102.                 4'h5 : o_sel_r = 8'b11011111; //?
  103.                 4'h6 : o_sel_r = 8'b10111111; //?
  104.                 4'h7 : o_sel_r = 8'b01111111; //?               
  105.         endcase
  106. end

  107. parameter                 seg0 = 8'hc0,
  108.                                         seg1 = 8'hf9,
  109.                                         seg2 = 8'ha4,
  110.                                         seg3 = 8'hb0,
  111.                                         seg4 = 8'h99,
  112.                                         seg5 = 8'h92,
  113.                                         seg6 = 8'h82,
  114.                                         seg7 = 8'hf8,
  115.                                         seg8 = 8'h80,
  116.                                         seg9 = 8'h90,
  117.                                         sega = 8'h88,
  118.                                         segb = 8'h83,
  119.                                         segc = 8'hc6,
  120.                                         segd = 8'ha1,
  121.                                         sege = 8'h86,
  122.                                         segf = 8'h8e;  

  123. reg [7:0]o_led_data_r;

  124. always @( disp_dat )
  125. begin
  126.         case( disp_dat )
  127.                 4'b0000 : o_led_data_r <= seg0;
  128.                 4'b0001 : o_led_data_r <= seg1;
  129.                 4'b0010 : o_led_data_r <= seg2;
  130.                 4'b0011 : o_led_data_r <= seg3;
  131.                 4'b0100 : o_led_data_r <= seg4;
  132.                 4'b0101 : o_led_data_r <= seg5;
  133.                 4'b0110 : o_led_data_r <= seg6;
  134.                 4'b0111 : o_led_data_r <= seg7;
  135.                 4'b1000 : o_led_data_r <= seg8;
  136.                 4'b1001 : o_led_data_r <= seg9;
  137.                 4'b1010 : o_led_data_r <= sega;
  138.                 4'b1011 : o_led_data_r <= segb;
  139.                 4'b1100 : o_led_data_r <= segc;
  140.                 4'b1101 : o_led_data_r <= segd;
  141.                 4'b1110 : o_led_data_r <= sege;
  142.                 4'b1111 : o_led_data_r <= segf;
  143.                 default :  ;
  144.         endcase
  145. end

  146. assign o_sel = o_sel_r;
  147. assign o_led_data = o_led_data_r;

  148. 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 的时候低位可以是任何数哦,很多种可能,导致你两次的分频系数不一样!

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top