1. 程式人生 > >基於mealy狀態機的密碼鎖系統設計

基於mealy狀態機的密碼鎖系統設計

應學院課程安排學習了verilog語言並在Xilinx vivado下用暫存器傳輸級的verilog 程式碼做功能實現,最後在basys3開發板上作驗證與測試。

一、FPGA基本介紹

FPGA(Field-Programmable Gate Array),即現場可程式設計門陣列,它是在PAL、GAL、CPLD等可程式設計器件的基礎上進一步發展的產物。它是作為專用積體電路(ASIC)領域中的一種半定製電路而出現的,既解決了定製電路的不足,又克服了原有可程式設計器件閘電路數有限的缺點。在一些特殊場景(如執行中的衛星等)中,可程式設計是極大的優勢。

FPGA在民用中最大的優點是成本與時間:自定製ASIC設計的非經常性工程(NRE)費用遠遠超過基於FPGA的硬體解決方案所產生的費用。ASIC設計初期的巨大投資表明了原始裝置製造商每年需要運輸數千種晶片,但更多的終端使用者需要的是自定義硬體功能,從而實現數十至數百種系統的開發。可程式設計晶片的特性意味著使用者可以節省製造成本以及漫長的交貨組裝時間。這也大大加快了開發過程,快速驗證現有思路和實現,快速改進、定型,繼而送去生產相應的ASIC,從而實現設計花費和產品功效的平衡。

二、本專案要求

這次利用Verilog語言在FPGA開發板basys3上實現密碼鎖的具體要求如下:

1 密碼鎖接受任意長度的密碼,只有密碼為123 時開鎖,其餘情況拒絕開鎖。
2 以開關為輸入密碼訊號,以LED 燈為開鎖訊號。
3 密碼輸入完畢應進入等待狀態,等待確認訊號。
4 以按鍵為確認訊號,輸入確認訊號後顯示是否開鎖。
5 開關撥動一個來回,按鍵按下又彈起作為一次有效輸入。
6 應有復位訊號。
7 請根據mealy 狀態機的規範設計密碼鎖的狀態圖,並用暫存器傳輸級的verilog 程式碼做功能實現。
8 在basys3 板上作驗證與測試。

三、分析設計

設計所要實現的功能為:

1、手動用0~9的撥碼開關設計三位密碼。

2、當輸入密碼開鎖時,輸入密碼後還需要按確認鍵才進行判斷

3、當密碼輸入錯誤時,錯誤指示燈亮,表示開鎖失敗。

4、應有復位訊號。

首先,實驗要求是基於mealy狀態機的,故輸出不僅與儲存電路的當前狀態有關,還與輸入有關。

確定基本要求和模式如下

1、輸出為2位LED燈,第一個作為正確解鎖LED燈,第二個作為錯誤&重置LED燈

2、輸入為10位數字鍵(0~9)、1位確認鍵和1位重置鍵。然後化歸,將確認鍵和數字鍵作為一組(即程式碼中的inKey),重置鍵無法化歸,另算。由於是同步時序邏輯電路,還需要時鐘訊號。

將確認訊號和數字輸入訊號化歸,相當於“1、2、3、確認”4次按鍵,但又有“開關撥動一個來回、按鍵按下又彈起作為一次有效輸入”的要求,可將其視為8個狀態(1個基本狀態+7箇中間狀態),再搭配兩個錯誤狀態:一個是基本錯誤狀態,另一個是在錯誤狀態的基礎上再撥動一次開關(未撥回)的狀態,這樣可以滿足要求。

進一步構思得:10種狀態(基本初態s0,中間狀態s1~s7,錯誤狀態serror和serror1)搭配5種輸入(Put0:00000000000(正常狀態)、Put1:00000000010(輸入1)、Put2:00000000100(輸入2)、Put3:00000001000(輸入3)、PutOK:10000000000(輸入確認鍵)),復位訊號直接強制將任意狀態轉化為基本初態s0且LED燈置為01(錯誤&重置指示燈亮)。

流程圖如下:


四、程式碼實現

由於整個實驗要求不是太難,整個流程結構比較緊湊、簡單,故只用一個模組實現所有功能。

module mima(
	output [1:0] led,
	input [10:0] inKey,
	input reset,
	input clk
	);
	
	reg [1:0] led;
	reg [3:0] state;
	
	parameter led_begin = 2'b00;
	parameter led_true = 2'b10;
	parameter led_false = 2'b01;
	
	parameter put0 = 11'b00000000000;
	parameter put1 = 11'b00000000010;
	parameter put2 = 11'b00000000100;
	parameter put3 = 11'b00000001000;
	parameter putOK = 11'b10000000000;
	
	parameter s0 = 4'b0000;
	parameter s1 = 4'b0001;
	parameter s2 = 4'b0010;
	parameter s3 = 4'b0011;
	parameter s4 = 4'b0100;
	parameter s5 = 4'b0101;
	parameter s6 = 4'b0110;
	parameter s7 = 4'b0111;
	parameter serror = 4'b1000;
	parameter serror1 = 4'b1001;
	
	always @(posedge clk)
		if (reset) // 重置
		begin
		    led <= led_false;
			state <= s0;
		end
		else
			case (state) // mealy有限狀態機
			s0:
			begin
				if (inKey == put1)
				begin
					led <= led_begin;
					state <= s1;
				end
				else if (inKey == put0)
				begin
					led <= led_begin;
					state <= s0;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			s1:
			begin
				if (inKey == put0)
				begin
					led <= led_begin;
					state <= s2;
				end
				else if (inKey == put1)
				begin
					led <= led_begin;
					state <= s1;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			s2:
			begin
				if (inKey == put2)
				begin
					led <= led_begin;
					state <= s3;
				end
				else if (inKey == put0)
				begin
					led <= led_begin;
					state <= s2;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			s3:
			begin
				if (inKey == put0)
				begin
					led <= led_begin;
					state <= s4;
				end
				else if (inKey == put2)
				begin
					led <= led_begin;
					state <= s3;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			s4:
			begin
				if (inKey == put3)
				begin
					led <= led_begin;
					state <= s5;
				end
				else if (inKey == put0)
				begin
					led <= led_begin;
					state <= s4;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			s5:
			begin
				if (inKey == put0)
				begin
					led <= led_begin;
					state <= s6;
				end
				else if (inKey == put3)
				begin
					led <= led_begin;
					state <= s5;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			s6:
			begin
				if (inKey == putOK)
				begin
					led <= led_begin;
					state <= s7;
				end
				else if (inKey == put0)
				begin
					led <= led_begin;
					state <= s6;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			s7: // 根據輸入put0(開關撥回)來決定輸出led正確燈亮
			begin
				if (inKey == put0)
				begin
					led <= led_true;
					state <= s7;
				end
				else if (inKey == putOK)
				begin
					led <= led_begin;
					state <= s7;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			serror: // 基本錯誤狀態,輸入putOK進入下一錯誤狀態
			begin
				if (inKey == putOK)
				begin
					led <= led_begin;
					state <= serror1;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
			serror1: // 錯誤狀態2,輸入put0(開關撥回)輸出led錯誤燈亮
			begin
				if (inKey == put0)
				begin
					led <= led_false;
					state <= serror1;
				end
				else if (inKey == putOK)
				begin
					led <= led_begin;
					state <= serror1;
				end
				else
				begin
					led <= led_begin;
					state <= serror;
				end
			end
		endcase
endmodule

五、測試

執行SyathesisàSynthesized DesignàReport Power,檢視用電估計功率報告如下:


之後進行輸入訊號(序列)測試,測試資料及結果如下:

訊號測試資料表
訊號測試資料 結果(正確燈、錯誤&重置燈)
重置 01
1、2、 00
1、2、3、確認 10
1、2、5 00
1、2、5、確認 01
7、1、2 00
7、1、2、確認 01
1、8、2、3 00
1、8、2、3、確認 01
1、2、3、9 00
1、2、3、9、確認 01
1、2、3、重置 01
4、1、2、重置 01
1、2、7、3、重置 01
1、2、3、8、重置 01

由此表可判斷,此設計和實現沒有問題,完全達到設計要求、圓滿完成設計任務。

下為兩張執行時圖



六、end

如有需要程式碼,直接在csdn上搜索

就好了