FPGA|CPLD|ASICwilliam hill官网
直播中

何格

4年用户 7经验值
擅长:可编程逻辑 嵌入式技术
私信 关注
[问答]

一个关于状态机的状态跳变问题,请大家看看是哪里逻辑不够严密?

`
  1. module         dithering(
  2.     input         clk,
  3.     input         key_in,
  4.     output reg  key
  5.     );


  6.     wire key_rising;
  7.     wire key_falling;

  8.     reg  key_mid = 0;                                           //按键输出的中间信号
  9.     reg  counter_20ms_flag = 0;                   //计数标志,如果到达20ms则变为1
  10.     reg  counter_20ms_en = 0;                   //计数器使能,检测到边沿开始计数
  11.     reg  counter_20ms_falling_flag = 0;//下降标志信号

  12.     reg  key_in_state0 ,key_in_state1;                   //寄存按键状态
  13.     reg  [20:0]counter_20ms = 0;          //上升沿计数器

  14.     assign key_rising  = ((~key_in_state1)&&key_in_state0); //上升
  15.     assign key_falling = (key_in_state1&&(~key_in_state0));//下降

  16.     parameter Idle                     = 4'b0001;
  17.     parameter First_Filter  = 4'b0010;
  18.         parameter Done              = 4'b0100;
  19.         parameter Second_Filter = 4'b1000;
  20.         reg [3:0]current_state = Idle;
  21.         reg [3:0]next_state;

  22.         always@(posedge clk)begin
  23.                 key_in_state0 <= key_in;
  24.                 key_in_state1 <= key_in_state0;

  25.         end

  26.         always@(posedge clk)
  27.                 key <= key_mid;

  28.     always@(posedge clk)
  29.             current_state <= next_state;
  30.    

  31.     always@(posedge clk)begin
  32.             case (current_state)
  33.                     Idle                 :
  34.                                                     if(key_rising == 1)  begin
  35.                                                             next_state <= First_Filter;
  36.                                                             key_mid <= 0; end
  37.                                                     else begin
  38.                                                             next_state <= Idle;
  39.                                                             key_mid <= 0; end
  40.                                              

  41.                     First_Filter:         if(key_falling == 1)begin
  42.                                                             next_state <= Idle;
  43.                                                             key_mid <= 0; end
  44.                                                    
  45.                                                     else if(counter_20ms_flag) begin
  46.                                                             next_state <= Done;
  47.                                                             key_mid <= 0; end
  48.                                                     else begin
  49.                                                             next_state <= First_Filter;
  50.                                                             key_mid <= 0; end
  51.                                               
  52.                     Done                :
  53.                                                     if(key_falling) begin
  54.                                                             next_state <= Second_Filter;
  55.                                                             key_mid <= 1; end
  56.                                                     else begin
  57.                                                             next_state <= Done;
  58.                                                             key_mid <= 1; end
  59.                                               
  60.               Second_Filter:  
  61.                                                       if(counter_20ms_flag) begin
  62.                                                               next_state <= Idle;
  63.                                                               key_mid <= 1; end
  64.                                                       else if(key_rising) begin
  65.                                                               next_state <= Done;
  66.                                                               key_mid <= 1; end
  67.                                                       else begin
  68.                                                               next_state <= Second_Filter;
  69.                                                               key_mid <= 1; end
  70.                                                 


  71.                     default                :  next_state <= next_state;
  72.             endcase

  73.     end       


  74.     always@(posedge clk)begin
  75.             if(counter_20ms_en == 1)
  76.                     if(counter_20ms < 999999)
  77.                             counter_20ms <= counter_20ms + 1'b1;
  78.                     if(counter_20ms == 999999 && counter_20ms_en == 1) begin
  79.                             counter_20ms_flag <= 1;        //满20ms输出一个时钟的标志信号
  80.                             counter_20ms <= 0;end                          
  81.             else begin
  82.                             counter_20ms_flag <= 0;
  83.                             counter_20ms <= 0; end
  84.             end

  85.     always@(posedge clk)begin

  86.             case (current_state)
  87.                     Idle                 :  counter_20ms_en <= 0;

  88.                     First_Filter : counter_20ms_en <= 1;       
  89.                     Done                 : counter_20ms_en <= 0;
  90.                     Second_Filter: counter_20ms_en <= 1;
  91.                     default :           counter_20ms_en <= counter_20ms_en;
  92.             endcase
  93.     end



  94. endmodule

想用状态机写一个按键消抖模块,但是在仿真的时候出现了问题,:
问题描述:当key_in为1时状态机的状态在第一个和第二个状态间来回跳变。
第一次发帖,不知道格式。



` 状态机仿真.PNG tb文件.PNG
dithering.v (7.53 KB)
(下载次数: , 2020-4-10 20:18 上传)
dithering_sim.v (1007 Bytes)
(下载次数: , 2020-4-10 20:18 上传)
dithering_sim_4000ns_resault.png

回帖(2)

卿小小_9e6

2020-4-10 15:00:42
01.三段式状态机写的有问题,导致状态机跳变,里面的key_mid赋值存在互斥情况。

02.一般第二段只有状态机跳变,赋值操作放在第三段。
03.我把999999改成"patameter  NUM=99",这样仿真运行4us即可。
04.sys_rst_n相关的逻辑可以忽略掉,不影响系统功能。
4 1 举报
  • 卿小小_9e6: 没有使用你的仿真代码验证,自己试一下(注意sys_rst的处理)。
  • 何格 回复 卿小小_9e6: 第一次写三段式状态机所以有很多问题,我昨天将状态转换那里的敏感信号改成组合逻辑就成功了。然后昨晚上我上网搜了一些资料,发现三段式状态机的状态转换那个模块都是组合逻辑。这点我就不是很明白为什么不能用时序逻辑。还有就是谢谢你的解答。
  • 卿小小_9e6 回复 何格: 简单来讲,状态机的跃迁/跳变尽量不影响逻辑状态的运行,所以第二段推荐组合逻辑。
    如果想用时序逻辑,也可以实现,只不过正常的逻辑运行可能会滞后1~N个时钟周期。
  • 何格 回复 卿小小_9e6: 好的,谢谢!

何格

2020-4-10 15:03:16
这是仿真文件
举报

更多回帖

发帖
×
20
完善资料,
赚取积分