基於FPGA數字式競賽搶答器(完整版)


其他賬號https://blog.csdn.net/qq_45082737/article/details/106515582

修改了一處錯誤,頂層文件中sel的位寬,由[2:0]改為[3:0]

 

1、報告首頁

FPGA 器件屬於專用集成電路中的一種半定制電路,是可編程的邏輯列陣,能夠有效的解決原有的器件門電路數較少的問題。FPGA 的基本結構包括可編程輸入輸出單元,可配置邏輯塊,數字時鍾管理模塊,嵌入式塊RAM,布線資源,內嵌專用硬核,底層內嵌功能單元。由於FPGA具有布線資源豐富,可重復編程和集成度高,投資較低的特點,在數字電路設計領域得到了廣泛的應用。FPGA的設計流程包括算法設計、代碼仿真以及設計、板機調試,設計者以及實際需求建立算法架構,利用EDA建立設計方案或HD編寫設計代碼,通過代碼仿真保證設計方案符合實際要求,最后進行板級調試,利用配置電路將相關文件下載至FPGA芯片中,驗證實際運行效果。
可編程邏輯器件是通過EDA技術將電子應用系統的既定功能和技術指標具體實現的硬件載體,FPGA作為實現這一途徑的主流器件之一,具有直接面向用戶,靈活性和通用性極大,使用方便,硬 件測試和實現快捷等特點。
硬件描述語言(HDL)是一種用來設計數字邏輯系統和描述數字電路的語言,常用的主要有VHDL、Verilog HDL、System Verilog 和 System C。
作為一種全方位的硬件描述語言,超高速集成電路硬件描述語言(VHDL)具有與具體硬件電路無關、與設計平台無關的特性,具有寬范圍描述能力、不依賴於特定的器件、可將復雜控制邏輯的設計用嚴謹簡潔的代碼進行描述等優點,得到眾多EDA公司的支持,在電子設計領域得到了廣泛應用。
VHDL是一種用於電路設計的高級語言,與其他硬件描述語言相比,其具有語言簡潔、靈活性強、不依賴於器件設計等特點,使其成為EDA技術通用的硬件描述語言,使EDA技術更便於設計者掌握。
Verilog HDL是廣泛應用的硬件描述語言,可以用於硬件設計流 程的建模、綜合、模擬等多個階段。
Verilog HDL 優點:類似C語言,上手容易,靈活。大小寫敏感。在寫激勵和建模方面有優勢。缺點:很多錯誤在編譯的時候不能被發現。
VHDL 優點:語法嚴謹,層次結構清晰。缺點:熟悉時間長,不夠靈活
ISE是使用XILINX的FPGA的必備的設計工具。目前官方提供下載的最新版本是14.7。它可以完成FPGA開發的全部流程,包括設計輸入、仿真、綜合、布局布線、生成BIT文件、配置以及在線調試等,功能非常強大。
本次課設我們是使用VerilogHDL語言在IES Design Suite14.7和spartan 3E Basys2開發板來實現的。

2、題目及要求的功能、技術指標、硬件平台、軟件工具

本次課程設計的題目是:基於FPGA的競賽搶答器。
實驗要實現的基本功能是 主持人按下開始,三個人搶答,主持人可以給選手加分或者減分,分數用數碼管來顯示。以下是主要功能和指標:
(1)設計一個可容納3組參賽的數字式搶答器,每組設一個按鈕,供搶答使用。
(2)搶答器具有第一信號鑒別和鎖存功能,使除第一搶答者外的按鈕不起作用。
(3)設置一個主持人“復位”按鈕。
(4)主持人復位后,開始搶答,第一信號鑒別鎖存電路得到信號后,有指示燈顯示搶答組別,揚聲器發出1~2秒的音響。
(5)設置一個計分電路,每組開始預置10分,由主持人記分,答對一次1分,答錯一次減1分。
本次設計內容是通過VerilogHDL語言在IES Design Suite14.7和spartan 3E Basys2開發板來實現的。

3、課程設計目的

這次FPGA的課程設計是一次實踐的機會,是我們將平時學到的Verilog HDL的理論知識轉化為實際操作;強化了我們對Verilog HDL應用能力,加深了對Verilog HDL的理解;了解所學知識的實際應用;熟悉相關EDA工具的使用;熟悉了FPGA數字電路設計流程;熟練掌握基於Vrilog HDL的FPGA設計方法;對自頂向下的系統設計有了更深刻的認識。

4、系統方案設計

本設計采用了FPGA開發板實現邏輯處理的功能,為了實現數據的輸入和輸出,模塊外圍包括:選手輸入s0,s1,s2輸入接口;主持人復位rst加減控制add,sub分數重置c’l’r輸入接口;LED選手燈輸出接口;蜂鳴器輸出接口;數碼管的段選位選A~H,sel輸出接口;50MHZ時鍾clk輸入接口。

在這里插入圖片描述
這次實驗打算把他分為下面幾個模塊:
在這里插入圖片描述
鎖存鑒定模塊,記分模塊,動態掃描分數顯示模塊,led燈和蜂鳴器控制模塊。
由搶答模塊的輸出信號來驅動后面幾個模塊的工作。

(1)鎖存鑒定模塊

搶答器鑒別鎖存模塊: 搶答器鑒別模塊在這個模塊中主要實現搶答過程中的搶答功能,並且能實現當有一路搶答按鍵按下時,該路搶答信號將其余過濾搶答封鎖的功能。其中有三個搶答信號 s1,s2,s3;系統復位信號 rst。
我們可以通過這樣的邏輯語言來實現對輸入信號的鎖存
在這里插入圖片描述
每個語句的輸出會對其他語句的輸入產生影響來起到鎖存的功能。

(2)記分模塊

在此模塊中,我們主要實現了在搶答過程中的主持人對選手分數加減。首先,我們重置分數顯示,也就是說,所有的分數都是10。根據參賽者的答案,如果參賽者回答正確,按下add按鈕,該選手將加分;如果參賽者答錯了,按下sub按鈕減去該選手分數。按照下面的流程可以實現其功能。
在這里插入圖片描述

(3)動態掃描分數顯示模塊

數碼管顯示模塊主要是由兩個模塊組成分別為動態掃描以及譯碼這兩個模塊組成:動態掃描模塊主要是將輸入的分數進行動態掃描,顯示到每一位數碼管的,譯碼模塊是將輸入的信號轉化為數碼管的電平信號。

1)動態掃描

首先我們需要六個數碼管(但是實驗板只有四個,設置一個設能端口xuan,xuan為1時顯示前兩個人的分數,為0時顯示三號選手的分數),我們設置一個中間變量sec,當復位信號rst為低時,sec為零,我們使sec不停加一使他在000到011(即0到3)之間循環;
在這里插入圖片描述
然后我們在設計一個always塊使用case語句對daout(數據輸出)進行賦值。當sec等於000,001,010,011時,daout對應的為a1[7:4],a1[3:0],
a2[7:4],a2[3:0];再用一次case語句對daout(數據輸出)進行賦值。當sec等於000,001,010,011時,daout對應的為a3[7:4],a3[3:0],0000,0000;
(注意:在引腳約束時注意順序排列)

2)譯碼部分

在這個模塊中主要實現搶答過程中將BCD碼轉換成7段現實數碼管的功能
在這里插入圖片描述
因為本次實驗只要求顯示0~9所以其他不予理會,當輸入的BCD碼為除了上表以外的部分都輸出11000000(最高為是數碼管的點)

(4)led燈和蜂鳴器控制模塊

在這個模塊中主要實現搶答過程中的蜂鳴功能,當搶答者按下搶答鍵時,除了指示燈顯示意外,同時蜂鳴器蜂鳴3秒。此模塊就是運用分頻信號來控制蜂鳴器,已達到蜂鳴3秒的實驗效果。
Led燈只需將chose信號賦給led_out即可;
先用一個計數器來產生一個時鍾周期為1s的clk1s,再利用clk1s為敏感信號來控制計數器count3,這個計數器由ena(chose三位的或)來控制,再用case語句對fmq_out來進行賦值,當count3=001,010,011時,fmqout輸出為高電平,其余為低。
在這里插入圖片描述

5、FPGA總體設計

在這里插入圖片描述在這里插入圖片描述

端口 位寬 I/O 說明
rst 1 I 主持人的開始“復位”信號
clk 1 I 系統時鍾50MHZ
s0 1 I 一號選手的輸入
s1 1 I 二號選手的輸入
s2 1 I 三號選手的輸入
add 1 I 加分使能
sub 1 I 減分使能
clr 1 I 分數重置
led_out 3 O LED選擇信號
fmq_out 1 O 蜂鳴器輸出
sel 4 O 位選信號
A~H 1 O 段選信號
xuan 1 I 切換數碼管顯示選手的分數(1時,前兩個選手的分數;0時,三號選手的分數)

具體的模塊划分如下圖

 

 

 

(1)鎖存鑒定模塊

在這里插入圖片描述

(2)記分模塊

在這里插入圖片描述

(3)動態掃描分數顯示模塊

1)動態掃描

在這里插入圖片描述

2)譯碼部分

在這里插入圖片描述

(4)led燈和蜂鳴器控制模塊

在這里插入圖片描述

6、驗證方案及仿真結果

(1)鎖存鑒定模塊

在這里插入圖片描述
如圖所示,當裁判的復位鍵按下之后,三個選手開始搶答,當s0(一號選手)先搶下之后其他選手的搶答對chose的輸出沒有影響,裁判按下復位chose重新回到000,第二回合二號選手先搶答,搶下之后其他選手的搶答對chose的輸出沒有影響。
實現了模塊的功能

(2)記分模塊

在這里插入圖片描述
由圖可以以看出實現了模塊的功能要求。a1,a2a3為三個選手的分數,初始值都為00010000(10分)chose信號為000;之后chose信號變為010,即選中a2選手的分數;當add信號出現高電平時,a2的分數變為00010001(11分);當add信號再次出現高電平時,a2的分數變為00010010(12分);當add信號再次出現高電平時,a2的分數變為00010011(13分),實現了加分的功能;當sub信號出現高電平時,a2的分數變為00010010(12分),即實現了減分的功能;當clr信號出現高電平時三個選手的分數恢復為00010000(10分)

(3)動態掃描分數顯示模塊

1)動態掃描

在這里插入圖片描述
從兩幅波形圖都可以看出實現了模塊功能。
當xuan為1時,顯示前兩個選手的分數;當xuan為0時,顯示三號選手的分數,多余的數碼顯示為00。
如圖:xuan為1時,觀察位選信號sel和數據輸出daout,當a1=00010000,a2=00010000,對應的sel=0001,daout=0001,代表第一位輸出0001;sel=0010,
daout=0000代表第二位顯示0000。如圖可看出正確的顯示了a1a2的分數。當xuan=0時,也正確顯示了a3的分數。

2)譯碼部分

在這里插入圖片描述
這個仿真結果可以對照上面給出的譯碼表可知,完成了模塊功能

(4)led燈和蜂鳴器控制模塊

在這里插入圖片描述
這個仿真結果也很容易明白;clk1s時一個周期為一秒的一個脈沖時鍾,如圖當chose信號有001輸入后,fmq_out會輸出一個高電平持續時間圖中也可以看出來約為2.7us(可以調節計數器的值來變化clk1s的比例);
led_out如圖可見於chose保持一致。

頂層模塊的仿真驗證

如圖,三個選手進行搶答,①1號選手先按下搶答按鍵,蜂鳴器響起約三秒,一號LED燈亮,作答之后裁判進行加分和減分的操作,下面a1分數變化。③最后裁判按下復位鍵開始下一輪搶答。④三號選手先搶答,然后加分,a3發生變化,⑤裁判按下clr分數都恢復為10分。⑥裁判按下復位。其中xuan=0可以看到分數顯示為三號選手的分數

7、綜合布局布線、引腳分配

在這里插入圖片描述
因為Basys2板子的數碼管只有四個,但題目要求六個,所以設置了一個使能端xuan,為1時顯示前兩位選手的分數,為0時顯示第三位選手的分數。

//引腳分配
//輸入
NET "clk" LOC = B8;
NET "rst" LOC = P11;
NET "s0" LOC =G12;
NET "s1" LOC = C11;
NET "s2" LOC = M4;
NET "add" LOC = L3;
NET "sub" LOC = K3;
NET "clr" LOC = A7;
NET "xuan" LOC = B4;
//LED和蜂鳴器
NET "led_out[0]" LOC = M5;
NET "led_out[1]" LOC = M11;
NET "led_out[2]" LOC = P7;
NET "fmq_out" LOC = P6;//用一個LED燈代替
//位選
NET "sel[2]" LOC = f12;
NET "sel[2]" LOC = J12;
NET "sel[1]" LOC = M13;
NET "sel[0]" LOC = K14;
//段選
NET "H" LOC = N13;
NET "G" LOC = M12;
NET "F" LOC = L13;
NET "E" LOC = P12;
NET "D" LOC = N11;
NET "C" LOC = N14;
NET "B" LOC = H12;
NET "A" LOC = L14;

8、總結

收獲很大

9、 參考文獻

《Verilog HDL 數字設計與綜合(第二版)》 夏宇聞 電子工業出版社
《基於Verilog 的FPGA設計基礎》 杜慧敏 西安電子科技大學出版社
《深入淺出玩轉FPGA》 吳宇航 北京航空航天大學出版社
《基於FPGA的數字系統設計》 李輝 西安電子科技大學出版社

10、附件代碼

//////////////////////////////////////*頂層模塊*//////////////////////////////////////////////////
module qiangdaqi_top_1(rst, clk, s0, s1, s2,clr, add, sub,xuan,fmq_out,led_out,sel,A,B,C,D,E,F,G,H
    );
   input        rst;
   input        clk;
   input        s0;
   input        s1;
   input        s2;
	input        clr;
   input        add;
   input        sub;
	input        xuan;
	output [2:0] led_out;
	output       fmq_out;
	output [3:0] sel;
	output       A,B,C,D,E,F,G,H;
   
	wire [2:0] chose;
	wire [7:0]    a1;
	wire [7:0]    a2;
	wire [7:0]    a3;
	wire [3:0] daout;
	
	qd_zz qd_zz_1 (
		.rst(rst), 
		.clk(clk), 
		.s0(s0), 
		.s1(s1), 
		.s2(s2), 
		.chose(chose));

	jf_zz jf_zz_1 (
		.clr(clr), 
		.add(add), 
		.sub(sub), 
		.chose(chose), 
		.a1(a1), 
		.a2(a2), 
		.a3(a3)
	);
	
	fmq_zz fmq_zz_1 (
		.chose(chose), 
		.rst(rst), 
		.fmq_out(fmq_out), 
		.clk(clk),
		.led_out(led_out)
	);
	
	dtsm_zz dtsm_zz_1 (
		.clk(clk), 
		.rst(rst),
		.a1(a1), 
		.a2(a2), 
		.a3(a3), 
		.daout(daout), 
		.sel(sel),
		.xuan(xuan)
	);
	
	ym_zz ym_zz_1 (
		.daout(daout), 
		.A(A), 
		.B(B), 
		.C(C), 
		.D(D), 
		.E(E), 
		.F(F), 
		.G(G), 
		.H(H)
	);

endmodule
///////////////////////////////////*搶答鑒別模塊*//////////////////////////////////////////////
module qd_zz(rst, clk, s0, s1, s2, chose
    );
   input        rst;
   input        clk;
   input        s0;
   input        s1;
   input        s2;
   output [2:0] chose;
   reg [2:0]    chose;
  
   always @(negedge rst or posedge clk)
   begin
      if (!rst)
      begin
         chose <= 3'b000;
      end
      else 
      begin
         if ((s0 == 1'b1 | chose[0] == 1'b1) & (~(chose[1] == 1'b1 | chose[2] == 1'b1 )))
         begin
            chose[0] <= 1'b1;
         end
         if ((s1 == 1'b1 | chose[1] == 1'b1) & (~(chose[0] == 1'b1 | chose[2] == 1'b1 )))
         begin
            chose[1] <= 1'b1;
         end
         if ((s2 == 1'b1 | chose[2] == 1'b1) & (~(chose[1] == 1'b1 | chose[0] == 1'b1 )))
         begin
            chose[2] <= 1'b1;
         end
        
      end
   end
	endmodule
//////////////////////////////////////*計分模塊*////////////////////////////////////////////
module jf_zz(clr, add, sub, chose, a1, a2, a3,led_out
    );

   input        clr;
   input        add;
   input        sub;
   input [2:0]  chose;
   output [7:0] a1;
   reg [7:0]    a1;
   output [7:0] a2;
   reg [7:0]    a2;
   output [7:0] a3;
   reg [7:0]    a3;
   output [2:0] led_out;
   wire jiajian;

assign jiajian=add^sub;
assign led_out = chose;

   always @(posedge clr or posedge jiajian)
      if (clr == 1'b1)
      begin
         a1 <= 8'b00010000;
         a2 <= 8'b00010000;
         a3 <= 8'b00010000;
      end
      else 
      begin
         if (add == 1'b1)
            case (chose)
               3'b001 :
                  if (a1 == 8'b00100000)
                     ;
                  else if (a1[3:0] == 4'b1001)
                  begin
                     a1[3:0] <= 4'b0000;
                     a1[7:4] <= a1[7:4] + 1'b1;
                  end
                  else
                     a1[3:0] <= a1[3:0] + 1'b1;
               3'b010 :
                  if (a2 == 8'b00100000)
                     ;
                  else if (a2[3:0] == 4'b1001)
                  begin
                     a2[3:0] <= 4'b0000;
                     a2[7:4] <= a2[7:4] + 1'b1;
                  end
                  else
                     a2[3:0] <= a2[3:0] + 1'b1;
               3'b100 :
                  if (a3 == 8'b00100000)
                     ;
                  else if (a3[3:0] == 4'b1001)
                  begin
                     a3[3:0] <= 4'b0000;
                     a3[7:4] <= a3[7:4] + 1'b1;
                  end
                  else
                     a3[3:0] <= a3[3:0] + 1'b1;
               default :
                  ;
            endcase
         else if (sub == 1'b1)
            case (chose)
               3'b001 :
                  if (a1 == 8'b00000000)
                     ;
                  else if (a1[3:0] == 4'b0000)
                  begin
                     a1[3:0] <= 4'b1001;
                     a1[7:4] <= a1[7:4] - 1'b1;
                  end
                  else
                     a1[3:0] <= a1[3:0] - 1'b1;
               3'b010 :
                  if (a2 == 8'b00000000)
                     ;
                  else if (a2[3:0] == 4'b0000)
                  begin
                     a2[3:0] <= 4'b1001;
                     a2[7:4] <= a2[7:4] - 1'b1;
                  end
                  else
                     a2[3:0] <= a2[3:0] - 1'b1;
               3'b100 :
                  if (a3 == 8'b00000000)
                     ;
                  else if (a3[3:0] == 4'b0000)
                  begin
                     a3[3:0] <= 4'b1001;
                     a3[7:4] <= a3[7:4] - 1'b1;
                  end
                  else
                     a3[3:0] <= a3[3:0] - 1'b1;
               default :
                  ;
            endcase
      end
  
endmodule
////////////////////////////////*蜂鳴器和LED顯示*/////////////////////////////////////////
module fmq_zz(chose,rst,fmq_out,led_out,clk);
  input rst,clk;
  input [2:0]chose;
  output [2:0]led_out;
  output fmq_out;
  reg fmq_out,clk1s;
  reg [27:0] count1s;
  wire ena;
  
  assign led_out=chose;
  
  always@(posedge clk or negedge rst)
  begin
     if(!rst)
	    begin
		  count1s=28'd0; clk1s=1'd0;
		  end
	 else
	    begin
		  if(count1s>28'd20)
		      begin 
			    count1s=28'd0;
				clk1s=~clk1s;
			  end
		  else
		      count1s=count1s+1'd1;
	    end
	end
	
assign ena=chose[0]|chose[1]|chose[2];

reg [2:0]count3;

always@(posedge clk1s or negedge rst)
begin 
  if(!rst)
      count3=3'd0;
  else 
     if(ena)
     count3=count3+1'd1;
	  else
	  count3=0;
end

always@(posedge clk)
 begin
    case(count3)
	    3'b000: fmq_out=1'b0;//count3默認是000,所以這樣
	    3'b001: fmq_out=1'b1;//001,010,011時,輸出高
		3'b010: fmq_out=1'b1;
		3'b011: fmq_out=1'b1;
		3'b100: fmq_out=1'b0;
		3'b101: fmq_out=1'b0;
	    3'b110: fmq_out=1'b0;
		default:fmq_out=1'b0;
    endcase	
end 
    
endmodule
///////////////////////////////////////*動態掃描*///////////////////////////////////////////
module dtsm_zz(clk,rst, a1,a2,a3, daout, sel,xuan);
   
  input rst;
   input        clk;
   input [7:0]  a1;
   input [7:0]  a2;
   input [7:0]  a3;
   input        xuan;
 
   output [3:0] daout;
   reg [3:0]    daout;
   output [3:0] sel;
	
   reg [1:0]    sec;
	reg [3:0]    sell;

   always @(posedge clk or negedge rst)
      begin
		  if(!rst)
		   begin
		      sec<=2'b00;
		   end
		 else
         if (sec == 2'b11)
            sec <= 2'b00;
         else  
            sec <= sec + 1;
      end

   always @(sec or xuan or a1 or a2 or a3)
    begin
      if(xuan) 
		begin
	     case (sec)
         2'b00 :
            begin 
				daout <= a1[7:4];sell<=4'b0001;end
         2'b01 :
			   begin
            daout <= a1[3:0];sell<=4'b0010;end
         2'b10 :
			begin
            daout <= a2[7:4];sell<=4'b0100;end
         2'b11 :
			begin
            daout <= a2[3:0];sell<=4'b1000;end
         default :
			begin
            daout <= 4'b0000;sell<=4'b0000;end
         endcase
			end
	  else
	  	  begin
		  case (sec)
         2'b00 :
			begin
            daout <= a3[7:4];sell<=4'b0001;end
         2'b01 :
			begin
            daout <= a3[3:0];sell<=4'b0010;end
         2'b10 :
			begin
			   daout <= 4'b0000;sell<=4'b0100;end
         2'b11 :
			begin
            daout <= 4'b0000;sell<=4'b1000;end
         default :
			begin
            daout <= 4'b0000;sell<=4'b0000;end
	       endcase
			end 
	 end

assign sel=sell;

endmodule

////////////////////////////////////*譯碼模塊*//////////////////////////////////////////////
module ym_zz(daout, A, B, C, D, E, F, G, H
    );

   input [3:0] daout;
   
   output      A;
   output      B;
   output      C;
   output      D;
   output      E;
   output      F;
   output      G;
   output      H;

   wire [3:0]  DATA;
   reg [7:0]   DOUT;
   
   assign DATA = daout;
   
   always @(DATA)
      
      case (DATA)
         
         4'b0000 :
            DOUT <= 8'b11000000;
         
         4'b0001 :
            DOUT <= 8'b11111001;
         
         4'b0010 :
            DOUT <= 8'b10100110;
         
         4'b0011 :
            DOUT <= 8'b10110000;
         
         4'b0100 :
            DOUT <= 8'b10011001;
         
         4'b0101 :
            DOUT <= 8'b10010010;
         
         4'b0110 :
            DOUT <= 8'b10000010;
         
         4'b0111 :
            DOUT <= 8'b11111000;
         
         4'b1000 :
            DOUT <= 8'b10000000;
         
         4'b1001 :
            DOUT <= 8'b10010000;
         
         default :
            DOUT <= 8'b11000000;
      endcase
 
   assign H = DOUT[7];
   assign G = DOUT[6];
   assign F = DOUT[5];
   assign E = DOUT[4];
   assign D = DOUT[3];
   assign C = DOUT[2];
   assign B = DOUT[1];
   assign A = DOUT[0];

endmodule

你竟然看完了!!!!
代碼都是我調試過的,測試文件沒有上傳
作者水平有限,如有錯誤歡迎指正

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM