(1)状态机跑飞的原因
两种可能:1)状态机的输入信号与本地时钟不同步,出现了冒险竞争现象,造成状态机死锁。
2)状态机综合后没有生成一旦进入非有效状态便立即复位,然后进入某个有效状态的电路。
解决办法:1)把外部引入的异步输入信号,做同步处理,作为本状态机的输入。
2)用综合指令或者约束,强行规定综合后必须生成一旦进入非有效状态便立即复位随即进入有效状态的电路。
输入信号是指除了从当前状态反馈信号以外的信号,即从状态机外部输入的信号。
是否会产生一旦进入非有效状态立即进行强制复位的电路,并不会因为你在状态机中加入when others=> state1 综合后就一定生成这样的电路。若想生成这样的电路,必须在综合时要通过综合指令(约束)命令综合器强制生成,才会生成的。
原文链接:https://blog.csdn.net/xiaoxiao_rabbit/article/details/102751545
(2)问题记录
本次的状态机跑飞的原因是第一种,即:状态机的输入信号与本地时钟不同步,出现了冒险竞争现象,造成状态机死锁
实验:使用状态机按键防抖,实现二进制累加,二进制的表现形式为四个LED灯
最初代码:(注:变量abcd没有任何意义,仅在调试中使用)
1 module key_detect( 2 clk , 3 rst_n , 4 key , 5 led , 6 abcd , 7 ); 8 9 //参数定义 10 parameter DATA_W = 4; 11 //输入信号定义 12 input clk; 13 input rst_n; 14 input key; 15 //输出信号定义 16 output[DATA_W-1:0] led; 17 output[3:0] abcd; 18 //输出信号reg定义 19 reg [DATA_W-1:0] led; 20 reg [3:0] abcd; 21 //中间信号定义 22 reg pre_key; 23 wire nedge; 24 wire pedge; 25 26 reg [20:0] cnt; 27 reg en_cnt; 28 reg [1:0] state; 29 always @(posedge clk or negedge rst_n)begin 30 if(!rst_n)begin 31 cnt <= 0; 32 end 33 else if(en_cnt)begin 34 cnt <= cnt + 1'b1; 35 end 36 else 37 cnt <= 0; 38 end 39 40 //时序逻辑写法 41 always@(posedge clk or negedge rst_n)begin 42 if(!rst_n)begin 43 state <= 1'b0; 44 led <= 1'b0; 45 abcd <= 4'b1110; 46 end 47 else begin 48 case (state) 49 2'b00 : begin 50 if(nedge)begin 51 state <= 2'b01; 52 en_cnt <= 1'b1; 53 abcd <= 4'b01; 54 end 55 else begin 56 state <= 2'b00; 57 abcd <= 4'b10; 58 end 59 end 60 2'b01 : begin 61 if(cnt >= 999999)begin 62 en_cnt <= 1'b0; 63 state <= 2'b10; 64 abcd <= 4'b11; 65 end 66 else if(pedge)begin 67 en_cnt <= 1'b0; 68 state <= 2'b00; 69 abcd <= 4'b100; 70 end 71 else begin 72 state <= state; 73 end 74 end 75 2'b10 : begin 76 if(pedge)begin 77 state <= 2'b11; 78 en_cnt <= 1'b1; 79 abcd <= 4'b101; 80 end 81 else begin 82 state <= 2'b10; 83 abcd <= 4'b110; 84 end 85 end 86 2'b11 : begin 87 if(cnt >= 999999)begin 88 led <= led + 1'b1; 89 //led <= 4'b0011; 90 en_cnt <= 1'b0; 91 state <= 2'b00; 92 abcd <= 4'b111; 93 end 94 else if(nedge)begin 95 en_cnt <= 1'b0; 96 state <= 2'b10; 97 abcd <= 4'b1000; 98 end 99 else begin 100 state <= state; 101 end 102 end 103 default: begin 104 state <= 2'b00; 105 abcd <= 4'b1111; 106 end 107 endcase 108 end 109 end 110 111 always @(posedge clk)begin 112 pre_key <= key; 113 end 114 //检测下降沿 115 assign nedge = !key && pre_key; 116 //检测上升沿 117 assign pedge = key && !pre_key;
出现的问题:
以上代码在仿真中没有发现问题
但是,将程序下载进FPGA电路板中,发现在随机一次按键按下去之后,LED灯保持当前这个状态在其后不管按几次按键都无法改变LED灯的状态
随后使用quartus自带的逻辑笔进行调试
在出错的时序中,状态机的状态都转为无效
因此,推断是状态机跑飞的原因->key按键输入信号与本地时钟不同步
(3)问题的解决方案
将检测按键上跳沿与下降沿的程序进行异步信号同步化
出错代码:
1 always @(posedge clk)begin 2 pre_key <= key; 3 end 4 //检测下降沿 5 assign nedge = !key && pre_key; 6 //检测上升沿 7 assign pedge = key && !pre_key;
异步信号同步化代码:
1 reg key_in_sa,key_in_sb; 2 always @(posedge clk or negedge rst_n)begin 3 if(!rst_n)begin 4 key_in_sa <= 1'b0; 5 key_in_sb <= 1'b0; 6 end 7 else begin 8 key_in_sa <= key; 9 key_in_sb <= key_in_sa; 10 end 11 end 12 13 reg pre_keya,pre_keyb; 14 always @(posedge clk or negedge rst_n)begin 15 if(!rst_n)begin 16 pre_keya <= 1'b0; 17 pre_keyb <= 1'b0; 18 end 19 else begin 20 pre_keya <= key_in_sb; 21 pre_keyb <= pre_keya; 22 end 23 end 24 //检测下降沿 25 assign nedge = !pre_keya && pre_keyb; 26 //检测上升沿 27 assign pedge = pre_keya && !pre_keyb;
参考代码原文链接:https://www.cnblogs.com/xiaomeige/p/5500964.html
来源:https://www.cnblogs.com/cnlntr/p/12455068.html