本章導讀
電子系統中常用的顯示設備有數碼管、LCD液晶以及VGA顯示器等。其中數碼管又可分為段式顯示(7段、米字型等)以及點陣顯示(8*8、16*16等),LCD液晶的應用可以分為字符式液晶(1602、12864等)以及真彩液晶屏,VGA顯示器一般是現在的電腦顯示器。芯航線開發板對以上三種設備均提供了硬件接口。
本章將實現FPGA驅動數碼管動態顯示並提取出實現的電路結構,從電路結構入手編寫代碼,仿真對設計進行驗證。最終板級調試時使用In system sources and probes editor(ISSP,系統的源和探測器工具),輸入需要顯示的數據,數碼管則顯示對應數值。本節課核心不再是代碼,而是電路結構,電路結構確定后編寫代碼只是照圖施工的過程。這也是越來越接近FPGA設計本質的硬件思維。
數碼管驅動原理
其中8段數碼管的結構圖如圖15.1所示,
圖15.1 8段數碼管結構圖
由上圖可以看出數碼管有兩種結構:共陰極與共陽極。這兩者的區別在於,公共端是連接到地還是高電平,對於共陰數碼管需要給對應段以高電平才會使其點亮,而對於共陽極數碼管則需要給低電平才會點亮。AC620上板載的是共陽數碼管。同時為了顯示數字或字符,必須對數字或字符進行編碼譯碼。這里先不考慮小數點也就是簡化為7段數碼管,其編碼譯碼格式如表15.1所示:
表15.1 數碼管編碼譯碼表
段式數碼管工作方式有兩種:靜態顯示方式和動態顯示方式。靜態顯示的特點是每個數碼管的段選必須接一個8位數據線來保持顯示的字形碼。當送入一次字形碼后,顯示字形可一直保持,直到送入新字形碼為止。這種方法由於每一個數碼管均需要獨立的數據線因此硬件電路比較復雜,成本較高,很少使用。
為了節約IO以及成本一般采用如圖15.2所示的電路結構,這樣3個數碼管接在一起就比靜態的少了7*2個I/O。
圖15.2三位數碼管等效電路圖
這樣就實現了另一種顯示模式,動態顯示。動態顯示的特點是將所有位數碼管的段選線並聯在一起,由位選線控制是哪一位數碼管有效。選亮數碼管采用動態掃描顯示。所謂動態掃描顯示即輪流向各位數碼管送出字形碼和相應的位選,利用發光管的余輝和人眼視覺暫留作用,使人的感覺好像各位數碼管同時都在顯示。
現在舉例假設將掃描時間定為1S,這三個數碼管分成3s,第1秒時sel數據線上為`b100,這時數碼管0被選中,這時a=0,數碼管0的LED0就可以點亮;第2秒時sel數據線上為`b010,這時數碼管1被選中,這時b=0,數碼管1的LED1就可以點亮;第3秒時sel數據線上為`b001,這時數碼管2被選中,這時c=0,數碼管2的LED2就可以點亮。這時的效果就會是數碼管0的LED0亮一秒后數碼管1的LED1亮一秒最后是數碼管2的LED2亮一秒,這樣再次循環。
這樣如果使用1ms刷新時間的話由於數碼管的余輝效應以及人的視覺暫留這樣就會出現數碼管0的LED0、數碼管1的LED1以及數碼管2的LED2 "同時"亮,並不會有閃爍感。
圖15.3 7段8位的數碼管原理圖
三線制數碼管電路設計
AC620開發板上配備的是8段8位的數碼管,如果按照圖15.3電路進行設計,可以看出仍需要16個IO進行驅動。下面提出另外一種三線制數碼電路設計方法,其電路圖如圖15.4。這樣的電路設計仍舊屬於動態顯示,但是這里通過外接了由兩片8位74HC595移位寄存器級聯后構成16位移位寄存器並將級聯后的輸出連接到位選及段選口,可以直接通過三個IO即可控制8位8段數碼管。
圖15.4 三線制數碼管電路圖
74HC595是8位串行移位寄存器,帶有存儲寄存器和三態寄存器,其中移位寄存器和存儲寄存器分別采用不同的時鍾。其內部結構圖如圖15.5所示,其可以把串行的信號轉為並行的信號,因此常用做各種數碼管以及點陣屏的驅動芯片。芯片的IO功能描述如表15.2所示。
圖15.5 74HC595內部結構圖
表15.2 74HC595 IO功能描述
數碼管動態掃描驅動設計
模塊接口設計及內部功能划分
由上面的分析可以得出圖15.4的框圖,其接口列表如表15.2所示:
圖15.4 數碼管模塊框圖
表15.2 模塊接口列表
根據以上的分析可知,首先要有一個周期為1ms的驅動時鍾,因此需要一個分頻電路;在進行數碼管的位選時,需要一個循環移位;在選擇位后,需要選擇器來選通數據輸入位;要實現表15.1的功能需要一個由譯碼器。
數碼管驅動模塊邏輯電路圖可以簡化成如圖15.5所示的,其中每一部分的作用如表15.3所示。
圖15.5 數碼管驅動模塊邏輯電路圖
表15.3 子功能塊功能描述
名稱 |
功能描述 |
divder |
分頻產生1KHz的掃描時鍾 |
Shift8 |
8位循環移位寄存器 |
MUX8 |
數據輸入選擇 |
MUX2 |
使能選擇 |
LUT |
數據譯碼器 |
掃描時鍾模塊設計
從系統時鍾50M分頻得到1KHz的掃描時鍾,計數器值即為25000d,這樣計數器的位寬定義為15位即可。
1 reg [14:0]divider_cnt; 2 reg clk_1K; 3 4 always@(posedge Clk or negedge Rst_n) 5 if(!Rst_n) 6 divider_cnt <= 15'd0; 7 else if(!En) 8 divider_cnt <= 15'd0; 9 else if(divider_cnt == 15'd24999) 10 divider_cnt <= 15'd0; 11 else 12 divider_cnt <= divider_cnt + 1'b1; 13 14 always@(posedge Clk or negedge Rst_n) 15 if(!Rst_n) 16 clk_1K <= 1'b0; 17 else if(divider_cnt == 15'd24999) 18 clk_1K <= ~clk_1K; 19 else 20 clk_1K <= clk_1K;
數碼管位選模塊設計
接下來編寫8位循環移位寄存器,這里利用循環移位寄存器實現0000_0001b→1000_0000b的變化,進而實現數碼管的位選,即實現每個掃描時鍾周期選擇一個數碼管。移位寄存器輸出值與數碼管選通的對應關系如表15.4所示,其中sel7為高位。
表15.4 移位寄存器與數碼管對應關系
sel0 |
sel1 |
sel2 |
sel3 |
sel4 |
sel5 |
sel6 |
sel7 |
被選通數碼管 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
數碼管0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
數碼管1 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
數碼管2 |
…… |
||||||||
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
數碼管7 |
1 reg [7:0]sel_r; 2 3 always@(posedge clk_1K or negedge Rst_n) 4 if(!Rst_n) 5 sel_r <= 8'b0000_0001; 6 else if(sel_r == 8'b1000_0000) 7 sel_r <= 8'b0000_0001; 8 else 9 sel_r <= sel_r << 1;
數碼管數據顯示設計
利用8選1多路器,選擇端為當前掃描到的數碼管也就是循環移位寄存器的輸出端,利用多路器將待顯示數據輸送到對應到數碼管上。
1 reg [3:0]data_tmp; 2 always@(*) 3 case(sel_r) 4 8'b0000_0001:data_tmp = disp_data[3:0]; 5 8'b0000_0010:data_tmp = disp_data[7:4]; 6 8'b0000_0100:data_tmp = disp_data[11:8]; 7 8'b0000_1000:data_tmp = disp_data[15:12]; 8 8'b0001_0000:data_tmp = disp_data[19:16]; 9 8'b0010_0000:data_tmp = disp_data[23:20]; 10 8'b0100_0000:data_tmp = disp_data[27:24]; 11 8'b1000_0000:data_tmp = disp_data[31:28]; 12 default:data_tmp = 4'b0000; 13 endcase
顯示數據譯碼設計
前面所說如果要使數碼管顯示數字或字符,須對數字或字符進行編碼譯碼。這里利用一個4輸入查找表,來實現7位的輸出顯示譯碼。
1 always@(*) 2 case(data_tmp) 3 4'h0:seg = 7'b1000000; 4 4'h1:seg = 7'b1111001; 5 4'h2:seg = 7'b0100100; 6 4'h3:seg = 7'b0110000; 7 4'h4:seg = 7'b0011001; 8 4'h5:seg = 7'b0010010; 9 4'h6:seg = 7'b0000010; 10 4'h7:seg = 7'b1111000; 11 4'h8:seg = 7'b0000000; 12 4'h9:seg = 7'b0010000; 13 4'ha:seg = 7'b0001000; 14 4'hb:seg = 7'b0000011; 15 4'hc:seg = 7'b1000110; 16 4'hd:seg = 7'b0100001; 17 4'he:seg = 7'b0000110; 18 4'hf:seg = 7'b0001110; 19 endcase
模塊使能設計
模塊化的設計理念是,使得每個模塊獨立化,其端口設計要便於以后被調用與控制。基於這種理念,這里需要加入使能信號。關於使能子模塊,直接利用一個二選一多路器即可實現。
assign sel = (En)?sel_r:8'b0000_0000; |
數碼管顯示模塊仿真測試
以下生成了復位信號以及使能信號、待顯示數據的初始化以及切換,分別在數碼管上顯示"87654321"以及"89abcdef"。
1 initial begin 2 Rst_n = 1'b0; 3 En = 1; 4 disp_data = 32'h12345678; 5 #(`clk_period*20); 6 Rst_n = 1; 7 #(`clk_period*20); 8 #20000000; 9 disp_data = 32'h87654321; 10 #20000000; 11 disp_data = 32'h89abcdef; 12 #20000000; 13 $stop; 14 end
設置好仿真腳本后進行功能仿真,可以看到如圖15.6所示的局部波形文件,可以看出在復位信號置高之前數碼管均顯示0,在復位結束后數碼管才開始正常顯示,且當待顯示數據為89ABCDEFh(MSB)后,數碼管從1到8依次被選通且分別顯示為FEDCBA98h(LSB)。即仿真通過。
圖15.6 數碼管功能仿真波形圖
74HC595驅動設計
在數據手冊中可以看出,不同工作溫度和工作電壓下的芯片工作頻率值不相同,分別如表15.5與15.6所示。由於在學習板中芯片采用3.3V供電,這樣在設計其工作頻率時,直接使用50M晶振四分頻后的時鍾作為其工作時鍾。
表15.5 芯片工作頻率與溫度對照
SYMBOL |
PARAMETER |
Vcc(V) |
MIN |
TYP |
MAX |
UNIT |
maximum clock frequency SH_CP and ST_CP |
2.0 |
9 |
30 |
- |
MHz |
|
4.5 |
30 |
91 |
- |
MHz |
||
6.0 |
35 |
108 |
- |
MHz |
||
表15.6芯片工作頻率與溫度對照
SYMBOL |
PARAMETER |
Vcc(V) |
MIN |
TYP |
MAX |
UNIT |
maximum clock frequency SH_CP and ST_CP |
2.0 |
4.8 |
- |
- |
MHz |
|
4.5 |
24 |
- |
- |
MHz |
||
6.0 |
28 |
- |
- |
MHz |
||
74HC595模塊接口設計
從上面的分析可得出如圖15.10所示的框圖,其接口列表15.7如所示
圖15.10 74HC595驅動模塊框圖
表15.7 74HC595驅動模塊接口功能描述
信號名稱 |
I/O |
功能描述 |
Clk |
I |
50M時鍾 |
Rst_n |
I |
復位信號 |
En |
I |
數碼管使能信號1使能,0關閉 |
Data[15:0] |
I |
8個數碼管待顯示數據,每四位組成一個BCD碼 |
DS |
O |
串行數據輸出 |
SH_CP |
O |
移位寄存器的時鍾輸出 |
ST_CP |
O |
存儲寄存器的時鍾輸出 |
74HC595驅動模塊設計
首先工作時鍾產生,對50M時鍾進行4分頻。
1 parameter CNT_MAX = 4; //分頻數 2 reg [15:0] divider_cnt;//分頻計數器 3 4 always@(posedge Clk or negedge Rst_n) 5 if(!Rst_n) 6 divider_cnt <= 16'd0; 7 else if(divider_cnt == CNT_MAX) 8 divider_cnt <= 16'd0; 9 else 10 divider_cnt <= divider_cnt + 1'b1; 11 12 wire sck_pluse; 13 assign sck_pluse = (divider_cnt == CNT_MAX);
對sck_pluse進行計數,用於查找表實現數據的串行輸入以及移位時鍾SH_CP與存儲時鍾ST_CP的產生。
1 reg [4:0]SHCP_EDGE_CNT;//SH_CP EDGE counter 2 3 always@(posedge Clk or negedge Rst_n) 4 if(!Rst_n) 5 SHCP_EDGE_CNT <= 5'd0; 6 else if(sck_pluse)begin 7 if(SHCP_EDGE_CNT == 5'd31) 8 SHCP_EDGE_CNT <= 5'd0; 9 else 10 SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'd1; 11 end 12 else 13 SHCP_EDGE_CNT <= SHCP_EDGE_CNT;
查找表實現狀態輸出。
1 always@(posedge Clk or negedge Rst_n) 2 if(!Rst_n)begin 3 SH_CP <= 1'b0; 4 ST_CP <= 1'b0; 5 DS <= 1'b0; 6 end 7 else begin 8 case(SHCP_EDGE_CNT) 9 5'd0:begin SH_CP <= 1'b0; ST_CP <= 1'b1; DS <= r_data[15]; end 10 5'd1:begin SH_CP <= 1'b1; ST_CP <= 1'b0;end 11 5'd2:begin SH_CP <= 1'b0; DS <= r_data[14];end 12 5'd3:begin SH_CP <= 1'b1; end 13 5'd4:begin SH_CP <= 1'b0; DS <= r_data[13];end 14 5'd5:begin SH_CP <= 1'b1; end 15 5'd6:begin SH_CP <= 1'b0; DS <= r_data[12];end 16 5'd7:begin SH_CP <= 1'b1; end 17 5'd8:begin SH_CP <= 1'b0; DS <= r_data[11];end 18 5'd9:begin SH_CP <= 1'b1; end 19 5'd10:begin SH_CP <= 1'b0; DS <= r_data[10];end 20 5'd11:begin SH_CP <= 1'b1; end 21 5'd12:begin SH_CP <= 1'b0; DS <= r_data[9];end 22 5'd13:begin SH_CP <= 1'b1; end 23 5'd14:begin SH_CP <= 1'b0; DS <= r_data[8];end 24 5'd15:begin SH_CP <= 1'b1; end 25 5'd16:begin SH_CP <= 1'b0; DS <= r_data[7];end 26 5'd17:begin SH_CP <= 1'b1; end 27 5'd18:begin SH_CP <= 1'b0; DS <= r_data[6];end 28 5'd19:begin SH_CP <= 1'b1; end 29 5'd20:begin SH_CP <= 1'b0; DS <= r_data[5];end 30 5'd21:begin SH_CP <= 1'b1; end 31 5'd22:begin SH_CP <= 1'b0; DS <= r_data[4];end 32 5'd23:begin SH_CP <= 1'b1; end 33 5'd24:begin SH_CP <= 1'b0; DS <= r_data[3];end 34 5'd25:begin SH_CP <= 1'b1; end 35 5'd26:begin SH_CP <= 1'b0; DS <= r_data[2];end 36 5'd27:begin SH_CP <= 1'b1; end 37 5'd28:begin SH_CP <= 1'b0; DS <= r_data[1];end 38 5'd29:begin SH_CP <= 1'b1; end 39 5'd30:begin SH_CP <= 1'b0; DS <= r_data[0];end 40 5'd31:begin SH_CP <= 1'b1; end 41 endcase 42 end
74HC595驅動模塊仿真測試
此處仿真與前面類似,不再重復。部分波形如圖15.11所示,可以看出在模塊復位結束后每在移位時鍾SH_CP上升沿時串行數據依次輸出且高位在前。移位結束后ST_CP產生一個高電平更新顯示數據,因此各信號工作正常。
圖15.11 74HC595驅動仿真
ISSP生成及使用
為了更便捷地進行板級調試,這里介紹Qusrtus Prime自帶的的In system sources and probes editor(ISSP)調試工具,測試數碼管可以只用其提供的源,而至於其探針功能的使用會在后面的RAM章節再做詳細介紹。這樣測試整體模塊框圖就可以簡化為如圖15.12所示。
圖15.12 整體測試框圖
這里ISSP是以IP核的形式提供的,因此第一步單擊Tools來啟動IP Catalog來新建一個定制IP核。這里需要指出的是這里與Quartus II不同,在Quartus Prime中與qsys相關的IP核均集中到Qsys中。在Quartus II的使用方法在本節末也有相應講解,可以對比參考。
在彈出的圖15.13 IP目錄中,找到Simulation;Debug and Verification下的Altera In-System Source & Probes,並將輸出目錄確定為工程文件夾下的ip文件夾,並以hex_data保存,單擊Next。
圖15.13 新建ISSP
圖15.14設置ISSP名稱及文件位置
在彈出的圖15.15配置界面中將源位寬定義為32,探針位寬定義為0,然后單擊Next並將語言類型選擇為Verilog HDL。
圖15.15 ISSP配置界面
圖15.16 語言選擇成Verilog HDL並啟動轉換
在圖15.16點擊Generate后軟件會將ISSP先保存為Qsys系統。在提示系統保存成功后點擊Close會自動啟動轉換。彈出如圖15.18界面,標志完成。
圖15.17 Qsys系統保存完成
圖15.18 轉換完成
單擊Close,然后在主界面點擊Finish。此時會彈出如圖15.19所示的匯總信息,確認無誤后單擊Close即可。
圖15.19 匯總信息
這時會彈出圖15.20提示需要手動將Qsys系統添加到工程中。這樣直接在Files右鍵選擇Add/Remove Files in Project,找到對應的文件即可。
圖15.20 添加qsys到工程
圖15.21 手動添加qsys到工程
ISSP依舊屬於IP核,因此在使用前需要將其在工程文件中進行例化。ISSP在生成的文件中含有例化模板可以直接打開進行復制修改。可以打開生成的IP目錄下的hex_data_inst.v文件。
圖15.22 例化文件所在文件夾位置
圖15.23 例化模板
板級調試與驗證
新建頂層文件HEX_top.v,並將編寫好的數碼管驅動模塊以及ISSP例化到頂層文件中。
1 module HXE_top(Clk,Rst_n,SH_CP,ST_CP,DS); 2 3 input Clk; //50M 4 input Rst_n; 5 6 output SH_CP; //shift clock 7 output ST_CP; //latch data clock 8 output DS; //shift serial data 9 10 wire[31:0]disp_data; 11 wire [7:0] sel;//數碼管位選(選擇當前要顯示的數碼管) 12 wire [6:0] seg;//數碼管段選(當前要顯示的內容) 13 14 hex_data hex_data( 15 .probe(), 16 .source(disp_data) 17 ); 18 19 20 HXE8 HXE8( 21 .Clk(Clk), 22 .Rst_n(Rst_n), 23 .En(1'b1), 24 .disp_data(disp_data), 25 .sel(sel), 26 .seg(seg) 27 ); 28 29 30 HC595_Driver HC595_Driver( 31 .Clk(Clk), 32 .Rst_n(Rst_n), 33 .Data({1'b1,seg,sel}), 34 .S_EN(1'b1), 35 .SH_CP(SH_CP), 36 .ST_CP(ST_CP), 37 .DS(DS) 38 ); 39 40 endmodule
分配引腳並全編譯無誤后下載到開發板中。這時可以看到數碼管全顯示0,與設計一致。在Quartus Prime中點擊Tools→In-System Source and Probes Editor啟動ISSP,啟動后的界面如圖15.24所示。這里需手動選擇下載器,並將數據格式改為設計中的hex格式。
圖15.24 啟動ISSP
圖15.25 ISSP操作界面
圖15.26 切換數據格式
這樣ISSP界面的Data中輸入相應的數據即可在數碼管上看到與之對應的顯示,如圖15.27所示。至此完成了數碼管的動態顯示。
圖15.27 數碼管顯示數據
本章中介紹了數碼管的兩種驅動方式,靜態掃描與動態掃描。最終實現了三線制數碼管的驅動顯示。得益於模塊化設計的優勢,如果需要實現FPGA直接驅動數碼管,只需直接調用HEX8文件即可。在板級驗證中使用了In system sources and probes editor(ISSP)調試工具。
在本章的基礎上,可以結合第14章的內容,設計一款具有清零及暫停功能的秒表。
Quartus II中ISSP使用方法
在Quartus II中使用方式如下所示:
這里ISSP是以IP核的形式提供的,因此第一步單擊Tools→Mega Wizard Plug-In Manager來啟動Mega Wizard插件管理器,並新建一個定制IP核;
圖15.28 啟動Mega Wizard插件管理器
在彈出的圖15.29 Mega Wizard插件管理器的參數設置界面中,找到JTAG-accessible Extensions下選擇In-System Source and Probes,並將輸出目錄確定為工程文件夾下的ip文件夾,並以hex_data保存,單擊Next。
在彈出的圖15.30配置界面中將源位寬定義為32,探針位寬定義為0,然后單擊Next即可。
圖15.29 Mega Wizard插件管理器參數設置
圖15.30.1 ISSP配置界面
圖15.30.2 ISSP配置界面
圖15. 30.3 ISSP配置界面
在調用時打開生成后的hex_data.v復制端口並進行相應修改即可。剩余使用方式就與Quartus Prime一致了。
1 hex_data hex_data( 2 3 .probe(), 4 5 .source(disp_data) 6 7 );