(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
(4)按鍵亞穩態解決方案的原理
亞穩態其實就是數據的轉變沒有符合時鍾采樣所需要的setup/hold時間,在時鍾的上升沿或下降沿到來時正好采到數據的變化狀態。此時,由於數據並沒有穩定,所以會導致采到的數據不停變化,而不是邏輯0或邏輯1.此時采到的數據會一直抖動,直至隔一段時間穩定。
兩級觸發器可防止亞穩態傳播的原理:假設第一級觸發器的輸入不滿足其建立保持時間,它在第一個脈沖沿到來后輸出的數據就為亞穩態,那么在下 一個脈沖沿到來之前,其輸出的亞穩態數據在一段恢復時間后必須穩定下來,而且穩定的數據必須滿足第二級觸發器的建立時間,如果都滿足了,在下一個脈沖沿到 來時,第二級觸發器將不會出現亞穩態,因為其輸入端的數據滿足其建立保持時間。
原文鏈接:https://blog.csdn.net/dongdongnihao_/article/details/79590213
參考鏈接:https://www.cnblogs.com/amanlikethis/p/3721968.html
參考鏈接:https://blog.csdn.net/emperor_strange/article/details/82491085
