<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統 > 設計應用 > 比賽計分系統設計

          比賽計分系統設計

          作者:時間:2023-12-11來源:電子森林收藏
          • 任務:基于核心板 和 底板 完成設計并觀察調試結果
          • 要求:按動核心板獨立按鍵,驅動底板上8位數碼管為比賽雙方在0~999內計分。
          • 解析:驅動獨立按鍵,當按動兩隊加分按鍵時,控制兩隊分數調整,最后通過驅動底板上的數碼管電路將得分值顯示在數碼管上。

          在基礎數字電路實驗部分我們已經掌握了驅動獨立按鍵的原理及方法,控制數碼管顯示十進制數的BCD碼方案前面也多次介紹,本實驗主要學習數碼管掃描顯示的原理及方法。

          本文引用地址:http://www.ex-cimer.com/article/202312/453767.htm
          • 熟悉獨立按鍵驅動模塊的應用
          • 了解數碼管掃描顯示的原理及方法
          • 了解74HC595的工作原理及驅動方法
          • 完成設計實現

          根據前面的實驗解析我們可以得知,該設計可以拆分成三個功能模塊實現,

          • Debounce:通過驅動獨立按鍵工作獲取操作信息數據。
          • Counter:根據按鍵的操作信息控制雙方比賽分值調整。
          • Segment_scan:通過驅動串轉并芯片74HC595控制數碼管掃描顯示比賽分值。

          頂層模塊Game_Score通過實例化三個子模塊并將對應的信號連接,最終實現的總體設計。

          Top-Down層次設計

          模塊結構設計

          數碼管連接方式

          在前面之前的教程中數碼管章節已為大家介紹了數碼管獨立顯示的相關內容,關于獨立顯示這里就不在贅述。我們的實驗平臺的擴展板卡上有8位數碼管,根據驅動方法不同,有以下比較:

          獨立顯示數碼管

          獨立顯示:控制每個數碼管至少需要8個I/O口控制,8位數碼管就需要8*8 = 64根信號線才能分別顯示。獨立顯示實現簡單,但是需要大量的信號線。

          掃描顯示數碼管

          掃描顯示:將每位數碼管的同一段選信號連接在一起,這樣我們就只需要8根段選信號和8根位選信號,共計16根信號。掃描顯示可以有效節約I/O口資源,實現起來稍顯復雜。

          上圖中我們用了4位數碼管,共用了段選控制8+位選控制4=12管腳,如果是8位數碼管,按照上面方式連接,段選控制還是8管腳,位選控制也增加到8管腳,共計16管腳,當然硬件的連接還需要結合軟件的驅動,掃描顯示數碼管的驅動方法和獨立顯示數碼管驅動方法不同,接下來我們一起來學習。

          數碼管模塊電路連接

          數碼管連接方式部分我們了解到數碼管常用的兩種連接方式,獨立顯示數碼管的原理及驅動方法我們在基礎數字電路實驗部分就已經詳細學習了,本實驗我們來學習掃描顯示數碼管工作原理及驅動方法。

          前面我們說8位數碼管通過掃描顯示方式連接需要16管腳,對于大部分控制器件來說依然有點多,所以我們需要一種串行通信控制并行輸出的驅動器,處理器通過串行接口(引腳占用少)驅動驅動器完成16或更多信號的控制,74HC595就是這么一款驅動器。通過3路串行輸入(兼容SPI協議)控制8路并行輸出,而且可以級聯使用。

          74HC595驅動數碼管電路

          數碼管模塊驅動設計

          我們知道數碼管分位共陰極和共陽極,我們底板上使用的就是8位共陰極數碼管,驅動數碼管顯示需要字庫,方便程序中通過數據索引對應字庫,在基礎數字電路實驗部分我們已經學習過。

          7段共陰極數碼管字庫定義如下:

          reg[6:0] seg [15:0]; 
          always @(negedge rst_n) begin
          	seg[0]	=	7'h3f;   // 0
          	seg[1]	=	7'h06;   // 1
          	seg[2]	=	7'h5b;   // 2
          	seg[3]	=	7'h4f;   // 3
          	seg[4]	=	7'h66;   // 4
          	seg[5]	=	7'h6d;   // 5
          	seg[6]	=	7'h7d;   // 6
          	seg[7]	=	7'h07;   // 7
          	seg[8]	=	7'h7f;   // 8
          	seg[9]	=	7'h6f;   // 9
          	seg[10]	=	7'h77;   // A
          	seg[11]	=	7'h7c;   // b
          	seg[12]	=	7'h39;   // C
          	seg[13]	=	7'h5e;   // d
          	seg[14]	=	7'h79;   // E
          	seg[15]	=	7'h71;   // F
          	end

          數碼管顯示需要段選(a b c d e f g)輸出字庫數據,位選(dig)輸出選通信號,前面硬件電路連接部分看到8位數碼管的段選全部對應連在了一起,好像不能同時顯示8個不同的數字,是的,我們理解的沒錯,想要掃描顯示數碼管工作需要采用分時掃描的方式驅動。怎么樣分時掃描?

          • 首先我們考慮怎么樣讓第1個數碼管顯示數字1,控制數碼管段選端輸出1的字庫7'h06(G=0、F=0、E=0、D=0、C=1、B=1、A=0),同時控制數碼管位選端只選通第1個數碼管顯示(DIG1=0、DIG2~DIG8都為1)
          • 然后如果我們有8秒的時間,第1秒時間內控制第1個數碼管顯示數字1,第2秒時間內控制第2個數碼管顯示數字2,依次類推,這樣我們就可以在8秒時間內將8個不同數字分時顯示出來
          • 最后我們將8秒的時間變成8毫秒,每個數碼管顯示1毫秒,這樣我們在1秒時間內將8個數字顯示(掃描)125次,即刷新率為125次/秒,人眼睛有視覺暫留效應,當數碼管閃爍刷新頻率足夠高(例如125)時,我們看到的是8個數碼管同時顯示。

          以上描述的就是掃描顯示的數碼管的工作原理及驅動方法

          // dat_1[3:0]   //SEG1 顯示的數據輸入
          ......
          // dat_8[3:0]   //SEG8 顯示的數據輸入
          // dat_en[7:0]  //數碼管數據位顯示使能,[MSB~LSB]=[SEG1~SEG8]
          // dot_en[7:0]  //數碼管小數點位顯示使能,[MSB~LSB]=[SEG1~SEG8]
          // data[15:0]    //數碼管掃描控制數據,[15:8]為段選,[7:0]為位選
          MAIN:begin
          	cnt_main <= cnt_main + 1'b1;
          	state <= WRITE;		//在配置完發給74HC595的數據同時跳轉至WRITE狀態,完成串行時序
          	case(cnt_main)
          		//對8位數碼管逐位掃描
          		//data          [15:8]為段選,         [7:0]為位選
          		3'd0: data <= {{dot_en[7],seg[dat_1]},dat_en[7]?8'hfe:8'hff};
          		3'd1: data <= {{dot_en[6],seg[dat_2]},dat_en[6]?8'hfd:8'hff}; 
          		3'd2: data <= {{dot_en[5],seg[dat_3]},dat_en[5]?8'hfb:8'hff}; 
          		3'd3: data <= {{dot_en[4],seg[dat_4]},dat_en[4]?8'hf7:8'hff}; 
          		3'd4: data <= {{dot_en[3],seg[dat_5]},dat_en[3]?8'hef:8'hff};
          		3'd5: data <= {{dot_en[2],seg[dat_6]},dat_en[2]?8'hdf:8'hff}; 
          		3'd6: data <= {{dot_en[1],seg[dat_7]},dat_en[1]?8'hbf:8'hff}; 
          		3'd7: data <= {{dot_en[0],seg[dat_8]},dat_en[0]?8'h7f:8'hff}; 
          		default: data <= {8'h00,8'hff};
          	endcase
          	end

          如果不考慮74HC595驅動芯片,FPGA直接連接數碼管模塊的段選和位選信號,data作為輸出端口分配給段選和位選控制管腳,程序到這里差不多就OK了,然而為了節約IO管腳資源的占用,我們電路里有串轉并的驅動芯片74HC595,所以我們還需要增加程序設計,將data的數據通過串行的方式傳輸到74HC595芯片,然后74HC595芯片將會根據data的內容控制數碼管模塊顯示。

          74HC595是較為常用的串行轉并行的芯片,內部集成了一個8位移位寄存器、一個存儲器和8個三態緩沖輸出。在最簡單的情況下我們只需要控制3根引腳輸入得到8根引腳并行輸出信號,而且可以級聯使用,我們使用3個I/O口控制兩個級聯的74HC595芯片,產生16路并行輸出,連接到掃描顯示的8位數碼管上。

          不同的IC廠家都可以生產74HC595芯片,功能都是一樣的,然而不同廠家的芯片手冊對于管腳的命名會存在差異,管腳順序相同,大家可以對應識別 上圖是本設計中74HC595芯片的硬件電路連接,參考74HC595數據手冊了解其具體用法,下圖中我們了解到OE#(G#)和MR#(SCLR#)信號分別為輸出使能(低電平輸出)和復位管腳(低電平復位),OE#(G#)我們接GND讓芯片輸出使能,MR#(SCLR#)我們接VCC讓芯片的移位寄存器永遠不復位,如此FPGA只需要控制SHCP(SCK)、STCP(RCK)和DS(SER)即可。

          74HC595引腳功能描述

          74HC595內部結構圖

          74HC595時序圖

          根據74HC595內部結構及時序圖可以得知,SHCP(SCK)每個上升沿都會將DS(SER)的數據采樣到8位移位寄存器中,當STCP(RCK)上升沿時,8位移位寄存器中的數據被所存到8位鎖存器中,同時對應Q0~Q7管腳刷新對應輸出。對于我們的硬件,我們首先通過SHCP(SCK)和DS(SER)配合將需要傳輸的16位數據輸出,然后控制STCP(RCK)產生上升沿,所以我們需要至少16個SH_CP(SCK)周期完成1次數碼管控制。

          74HC595串行驅動 程序實現如下:

          //seg_rck     //74HC595的RCK管腳
          //seg_sck     //74HC595的SCK管腳
          //seg_din     //74HC595的SER管腳
          WRITE:begin
          	if(cnt_write >= 6'd33) cnt_write <= 1'b0;
          	else cnt_write <= cnt_write + 1'b1;
          	case(cnt_write)
          		//74HC595是串行轉并行的芯片,3路輸入可產生8路輸出,而且可以級聯使用
          		//74HC595的時序實現,參考74HC595的芯片手冊
          		6'd0:  begin seg_sck <= LOW; 
          		seg_din <= data[15]; 
          		end		//SCK下降沿時SER更新數據
          		6'd1:  begin seg_sck <= HIGH; 
          		end				//SCK上升沿時SER數據穩定
          		6'd2:  begin seg_sck <= LOW; 
          		seg_din <= data[14]; end
          		6'd3:  begin seg_sck <= HIGH; 
          		end
          		6'd4:  begin seg_sck <= LOW; 
          		seg_din <= data[13]; 
          		end
          		6'd5:  begin seg_sck <= HIGH; 
          		end
          		6'd6:  begin seg_sck <= LOW; 
          		seg_din <= data[12]; 
          		end
          		6'd7:  begin seg_sck <= HIGH; 
          		end
          		6'd8:  begin seg_sck <= LOW; 
          		seg_din <= data[11]; end
          		6'd9:  begin seg_sck <= HIGH; 
          		end
          		6'd10: begin seg_sck <= LOW; 
          		seg_din <= data[10]; 
          		end
          		6'd11: begin seg_sck <= HIGH; 
          		end
          		6'd12: begin seg_sck <= LOW; 
          		seg_din <= data[9]; end
          		6'd13: begin seg_sck <= HIGH; 
          		end
          		6'd14: begin seg_sck <= LOW; 
          		seg_din <= data[8]; 
          		end
          		6'd15: begin seg_sck <= HIGH; 
          		end
          		6'd16: begin seg_sck <= LOW; 
          		seg_din <= data[7]; end
          		6'd17: begin seg_sck <= HIGH; 
          		end
          		6'd18: begin seg_sck <= LOW; 
          		seg_din <= data[6]; end
          		6'd19: begin seg_sck <= HIGH; 
          		end
          		6'd20: begin seg_sck <= LOW; 
          		seg_din <= data[5]; end
          		6'd21: begin seg_sck <= HIGH; 
          		end
          		6'd22: begin seg_sck <= LOW; 
          		seg_din <= data[4]; end
          		6'd23: begin seg_sck <= HIGH; 
          		end
          		6'd24: begin seg_sck <= LOW; 
          		seg_din <= data[3]; end
          		6'd25: begin seg_sck <= HIGH; 
          		end
          		6'd26: begin seg_sck <= LOW; 
          		seg_din <= data[2]; end
          		6'd27: begin seg_sck <= HIGH; 
          		end
          		6'd28: begin seg_sck <= LOW; 
          		seg_din <= data[1]; 
          		end
          		6'd29: begin seg_sck <= HIGH; 
          		end
          		6'd30: begin seg_sck <= LOW; 
          		seg_din <= data[0]; 
          		end
          		6'd31: begin seg_sck <= HIGH; 
          		end
          		6'd32: begin seg_rck <= HIGH; 
          		end			//當16位數據傳送完成后RCK拉高,輸出生效
          		6'd33: begin seg_rck <= LOW; 
          		state <= MAIN; 
          		end
          		default: ;
          	endcase
          	end

          如果我們設計一個狀態機,將數碼管掃描的程序和74HC595串行驅動程序分別做成兩個狀態MAIN和WRITE,控制數碼管掃描程序每次產生一組控制數據,執行一次74HC595串行通信,就可以完成我們數碼管模塊電路的驅動設計了。

          狀態機設計框架

          8位數碼管刷新1次需要8個數碼管各點亮1次,每個數碼管點亮1次需要16位數據,16位數據通過串行方式傳輸給74HC595需要至少16個SHCP(SCK)周期,按照我們前面說的數碼管刷新率達到125次/秒,掃描方式下每個數碼管會點亮1毫秒,數碼管點亮的時間應該等于1次數碼管控制的時間,也就是16個SHCP(SCK)周期,所以我們可以控制74HC595的SHCP(SCK)時鐘周期計算: SHCP(SCK)周期 = 1ms / 16 = 62.5us 即是說,當 SHCP(SCK)周期小于62.5us,刷新率就應該大于125次/秒(注:以上為估算的結果) 為了計算方便,我們就取SHCP(SCK)周期為50us,那么觸發74HC595串行驅動執行的敏感變量周期應該為25us,我們可以通過分頻產生周期為25us時鐘觸發完成以上所以操作。

          時鐘分頻程序實現如下:

          //計數器對系統時鐘信號進行計數
          reg [9:0] cnt = 1'b0;
          always@(posedge clk or negedge rst_n) begin
          	if(!rst_n) cnt <= 1'b0;
          	else if(cnt>=(CNT_40KHz-1)) cnt <= 1'b0;
          	else cnt <= cnt + 1'b1;
          	end //根據計數器計數的周期產生分頻的脈沖信號
          	reg clk_40khz = 1'b0; 
          	always@(posedge clk or negedge rst_n) begin
          	if(!rst_n) clk_40khz <= 1'b0;
          	else if(cnt<(CNT_40KHz>>1)) clk_40khz <= 1'b0;
          	else clk_40khz <= 1'b1;
          	end

          狀態機狀態轉移圖

          系統總體實現

          按鍵消抖模塊我們前面基礎數字電路實驗中詳細介紹過,這里我們直接調用消抖模塊,記分器邏輯部分其實就是對按鍵按動次數計數,輸出0~999之間的BCD碼制數據,這里也不再贅述,最后例化數碼管模塊將兩隊的比分數據顯示出來。最后顯示的數據為000~999,本實驗例程中為了顯示最小有效數據位,增加了將最高位為0的數據位不顯示的設計,例如當分數為5分時,數碼管本來會顯示005,現在控制高兩位的00不顯示,只顯示最低位5。

          顯示控制程序實現如下:

          wire	[7:0]	dat_en;		//控制數碼管點亮
          assign	dat_en[7] = 1'b0;
          assign	dat_en[6] = red_seg[11:8]? 1'b1:1'b0;
          assign	dat_en[5] = red_seg[11:4]? 1'b1:1'b0;
          assign	dat_en[4] = 1'b1; 
          assign	dat_en[3] = 1'b0;
          assign	dat_en[2] = blue_seg[11:8]? 1'b1:1'b0;
          assign	dat_en[1] = blue_seg[11:4]? 1'b1:1'b0;
          assign	dat_en[0] = 1'b1;

          數碼管顯示模塊例化 程序實現如下:

          //segment_scan display module
          Segment_scan u4
          (
          .clk					(clk			),	//系統時鐘 12MHz
          .rst_n					(rst_n			),	//系統復位 低有效
          .dat_1					(0				),	//SEG1 顯示的數據輸入
          .dat_2					(red_seg[11:8]	),	//SEG2 顯示的數據輸入
          .dat_3					(red_seg[7:4]	),	//SEG3 顯示的數據輸入
          .dat_4					(red_seg[3:0]	),	//SEG4 顯示的數據輸入
          .dat_5					(0				),	//SEG5 顯示的數據輸入
          .dat_6					(blue_seg[11:8]	),	//SEG6 顯示的數據輸入
          .dat_7					(blue_seg[7:4]	),	//SEG7 顯示的數據輸入
          .dat_8					(blue_seg[3:0]	),	//SEG8 顯示的數據輸入
          .dat_en					(dat_en			),	//數碼管數據位顯示使能,[MSB~LSB]=[SEG1~SEG8]
          .dot_en					(8'b0001_0001	),	//數碼管小數點位顯示使能,[MSB~LSB]=[SEG1~SEG8]
          .seg_rck				(seg_rck		),	//74HC595的RCK管腳
          .seg_sck				(seg_sck		),	//74HC595的SCK管腳
          .seg_din				(seg_din		)	//74HC595的SER管腳);

          綜合后的設計框圖如下:

          RTL設計框圖

          實驗步驟

          1. 雙擊打開Quartus Prime工具軟件;
          2. 新建工程:File → New Project Wizard(工程命名,工程目錄選擇,設備型號選擇,EDA工具選擇);
          3. 新建文件:File → New → Verilog HDL File,鍵入設計代碼并保存;
          4. 設計綜合:雙擊Tasks窗口頁面下的Analysis & Synthesis對代碼進行綜合;
          5. 管腳約束:Assignments → Assignment Editor,根據項目需求分配管腳;
          6. 設計編譯:雙擊Tasks窗口頁面下的Compile Design對設計進行整體編譯并生成配置文件;
          7. 程序燒錄:點擊Tools → Programmer打開配置工具,Program進行下載;
          8. 觀察設計運行結果。

          將程序加載到FPGA開發平臺,底板數碼管左邊4位為紅隊比分,右邊4位為藍隊比分,初始都為0分,核心板K3按鍵為紅隊加分按鍵,核心板K4按鍵為藍隊加分按鍵,按動K3、K4按鍵,觀察紅隊和藍隊比分變化。



          評論


          相關推薦

          技術專區

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();