【FPGA】VGA顯示文字、彩條、圖片——基于DE2-115

文章目錄

  • 前言
  • 一、VGA概述
    • 1.1 簡述
    • 1.2 管腳定義
    • 1.3 VGA顯示原理
    • 1.4 VGA時序標準
    • 1.5 VGA 顯示模式及相關參數
  • 二、VGA顯示自定義的漢字字符
    • 2.1 點陣漢字生成
    • 2.2 生成BMP文件
    • 2.3 生成txt文件
    • 2.4 實現效果
  • 三、VGA顯示條紋
    • 3.1 實現流程
    • 3.2 實現效果
  • 四、VGA輸出一幅彩色圖像
    • 4.1 bmp圖片轉hex文件
    • 4.2 引入ROM ip核
    • 4.3 代碼實現
    • 4.4 實現效果
  • 五、代碼
    • 5.1 時鐘分頻
    • 5.2 vga驅動模塊
    • 5.3 顯示數據生成模塊
    • 5.4 按鍵消抖模塊
  • 六、整體實現效果(加入按鍵)
  • 總結
  • 參考

前言

本文內容:

  1. 深入了解VGA協議,理解不同顯示模式下的VGA控制時序參數(行頻、場頻、水平/垂直同步時鐘周期、顯示后沿/前沿等概念和計算方式);

  2. 通過Verilog編程,在至少2種顯示模式下(640480@60Hz,1024768@75Hz)分別實現以下VGA顯示,并對照VGA協議信號做時序分析:1)屏幕上顯示彩色條紋;2)顯示自定義的漢字字符(姓名-學號);3)輸出一幅彩色圖像。

  3. 在Verilog代碼中,將行、場同步信號中,故意分別加入一定 ms延時(用delay命令),觀察會出現什么現象。


一、VGA概述

1.1 簡述

圖像顯示設備在日常生活中隨處可見,例如家庭電視機、計算機顯示屏幕等,這些設備之所以能夠顯示我們需要的數據圖像信息,歸功于視頻傳輸接口。常見的視頻傳輸接口有三種:VGA 接口、 DVI 接口和 HDMI 接口,目前的顯示設備都配有這三種視頻傳輸接口。

三類視頻接口的發展歷程為 VGA → DVI → HDMI 。其中 VGA 接口出現最早,只能傳輸模擬圖像信號; 隨后出現的 DVI 接口又分為三類: DVI-A 、 DVI-D 、 DVI-I ,分別可傳輸純模擬圖像信號、純數字圖像信號和兼容模擬、數字圖像信號;最后的 HDMI 在傳輸數字圖像信號的基礎上又可以傳輸音頻信號。

VGA,英文全稱“ Video Graphics Array ”,譯為視頻圖形陣列,是一種使用模擬信號進行視頻傳輸的標準協議,由 IBM 公司于 1987 年推出,因其分辨率高、顯示速度快、顏色豐富等優點,廣泛應用于彩色顯示器領域。由于 VGA 接口體積較大,與追求小巧便攜的筆記本電腦背道而馳,在筆記本電腦領域,VGA 接口已被逐漸淘汰,但對于體積較大的臺式機,這種情況并未發生,雖然 VGA 標準在當前個人電腦市場中已經過時,但因其在顯示標準中的重要性和良好的兼容性,VGA 仍然是最多制造商所共同支持的一個標準,個人電腦在加載自己獨特驅動程序之前,都必須支持 VGA 的標準。
早期的 CRT 顯示器只能接收模擬信號,不能接收數字信號,計算機內部顯卡將數字信號轉換成模擬信號,通過 VGA 接口傳給 VGA 顯示器,雖然現如今許多種類的顯示器可以直接接收數字信號,但為了兼容顯卡的 VGA 接口,大都支持 VGA 標準。

在這里插入圖片描述

VGA 接口中以針式引出信號線的稱為公頭,以孔式引出信號線的稱為母頭。在計算機VGA 顯示器上一般引出母頭接口,使用兩頭均為公頭的 VGA 連接線將計算機與 VGA顯示器連接起來,兩者圖像傳輸時,使用的是 VGA 圖像傳輸標準,該標準的具體內容在后面博文會詳細說明。VGA 公頭、母頭接口和 VGA 連接線。在這里插入圖片描述

圖2 VGA接口(左邊為母頭,右邊為公頭)

在這里插入圖片描述

圖3 VGA連接線

1.2 管腳定義

下面,我們結合 VGA 接口引腳圖和各引腳定義表格,對 VGA 接口各引腳做一下簡單介紹。

![在這里插入圖片描述](https://img-blog.csdnimg.cn/direct/a669aee5a12343f9807b1bbae8fe3199.png

圖4 VGA接口引腳圖
引腳1:紅基色;引腳2:綠基色;引腳3:藍基色;
引腳6:紅色地;引腳7:綠色地;引腳8:藍色地;引腳10:數字地
引腳11:地址碼0;引腳12:地址碼1;引腳4:地址碼2;引腳15:地址碼3
引腳13:行同步;引腳14:場同步
引腳5:自測試(各廠家定義不同);引腳9:保留(各廠家定義不同)

? ? ? 由圖4可知,VGA 接口共有 15 個引腳,分為 3 排,每排各 5 個, 按照自上而下、從左向右的順序排列。其中第一排的引腳 1 、 2 、 3 和第三排的引腳 13 、 14 最為重要。
? ? ? VGA 使用工業界通用的 RGB 色彩模式作為色彩顯示標準,這種色彩顯示標準是根據三原色中紅色、綠色、藍色所占比例多少及三原色之間的相互疊加得到各式各樣的顏色。引腳 1 紅基色 (RED) 、引腳 2 綠基色 (GREEN) 、引腳 3 藍基色 (BLUE) 就是 VGA 接口中負責傳輸三原色的傳輸通道。要注意的是,這 3 個引腳傳輸的是模擬信號。
? ? ? 引腳 13 行同步信號 (HSYNC) 、引腳 14 場同步信號 (VSYNC) ,這兩個信號,是在 VGA顯示圖像時,負責同步圖像色彩信息的同步信號。在后面博文中,我們會對這兩個信號進行詳細講解。
? ? ? 引腳 5 、 9 :這兩個引腳分別是 VGA 接口的自測試和預留接口,不過不同生產廠家對這兩個接口定義不同,在接線時,兩引腳可懸空不接。
? ? ? 引腳 4 、 11 、 12 、 15 :這四個是 VGA 接口的地址碼,可以懸空不接。
? ? ? 引腳 6 、 7 、 8 、 10 :這四個引腳接地,無需解釋。

1.3 VGA顯示原理

VGA 顯示器顯示圖像,并不是直接讓圖像在顯示器上顯示出來,而是采用掃描的方式,將構成圖像的像素點,在行同步信號和場同步信號的同步下,按照從上到下、由左到右的順序掃描到顯示屏上。VGA 顯示器掃描方式,具體見圖 1 。
在這里插入圖片描述

結合

??結合 VGA 顯示器掃描方式示意圖,我們簡要說明一下 VGA 顯示器的掃描規律。
?? (1) 在行、場同步信號的同步作用下,掃描坐標定位到左上角第一個像素點坐標;
?? (2) 自左上角 ( 第一行 ) 第一個像素點坐標,逐個像素點向右掃描 ( 圖中第一個水平方向箭頭) ;
?? (3) 掃描到第一行最后一個數據,一行圖像掃描完成,進行圖像消隱,掃描坐標自第一行行尾轉移到第二行行首( 圖中第一條虛線 ) ;
?? (4) 重復若干次掃描至最后一行行尾,一幀圖像掃描完成,進行圖像消隱,掃描坐標跳轉回到左上角第一行行首( 圖中對角線箭頭 ) ,開始下一幀圖像的掃描。

?? 在掃描的過程中會對每一個像素點進行單獨賦值,使每個像素點顯示對應色彩信息,
??當一幀圖像掃描結束后,開始下一幀圖像的掃描,循環往復,當掃描速度足夠快,加之人眼的視覺暫留特性,我們會看到一幅完整的圖片,而不是一個個閃爍的像素點。這就是VGA 顯示的原理。

1.4 VGA時序標準

??????為了適應匹配不同廠家的 VGA 顯示器, VGA 視頻傳輸接口有自己的一套 VGA 時序標準,只有遵循 VGA 的時序標準,才能正確的進行圖像信息的顯示。在這里我們以 VESA VGA 時序標準為例,為大家講解一下 VGA 時序標準,具體見圖 2 。
在這里插入圖片描述

??????由 VESA VGA 時序標準圖可知, VGA 時序由兩部分構成,行同步時序與場同步時序,為了方便大家理解,我們將行同步時序與場同步時序分開講解。
???? (1) 行同步時序,具體見圖 3 。

在這里插入圖片描述

圖 3 行同步時序圖

??????圖中 Video 代表傳輸的圖像信息, HSync 表示行同步信號。 HSync 自上升沿起到下一個上升沿止為一個完整周期,我們稱之為行掃描周期。
??????一個完整的行掃描周期,包含 6 部分: Sync (同步)、 Back Porch (后沿)、 Left Border(左邊框)、 Addressable Video (有效圖像)、 Right Border (右邊框)、 Front Porch(前沿),這 6 部分的基本單位是 pixel (像素),即一個像素時鐘周期。在一個完整的行掃描周期中,Video 圖像信息在 HSync 行同步信號的同步下完成一行圖像的掃描顯示,Video 圖像信息只有在 “Addressable” Video (有效圖像)階段,圖像信息有效,其他階段圖像信息無效。
??????HSync 行同步信號在 Sync (同步)階段,維持高電平,其他階段均保持低電平,在下一個行掃描周期的 Sync (同步)階段, HSync 行掃描信號會再次拉高,其他階段拉低,周而復始。
??????(2) 場同步時序,具體見圖 4 。

在這里插入圖片描述

圖 4 場同步時序圖

??????理解了行同步時序,場同步時序就更容易理解了,兩者相類似,如圖所示,圖中Video 代表傳輸的圖像信息, VSync 表示場同步信號VSync 自上升沿起到下一個上升沿止為一個完整周期,我們稱之為場掃描周期
??????一個完整的場掃描周期,也包含 6 部分: Sync (同步)、 Back Porch (后沿)、 Top Border(上邊框)、 “Addressable” Video (有效圖像)、 Bottom Border (底邊框)、 Front Porch(前沿),與行同步信號不同的是,這 6 部分的基本單位是 line (行),即一個完整的行掃描周期。
?????? 在一個完整的場掃描周期中,Video 圖像信息在 HSync (行同步信號)VSync (場同步信號)的共同作用下完成一幀圖像的顯示,Video 圖像信息只有在 “Addressable” Video(有效圖像)階段,圖像信息有效,其他階段圖像信息無效。VSync 行同步信號在 Sync (同步)階段維持高電平,其他階段均保持低電平,完成一個場掃描周期后,進入下一幀圖像的掃描。
?????? 綜上所述,將行同步時序圖與場同步時序圖結合起來就構成了 VGA 時序圖,具體見圖 5。

在這里插入圖片描述

圖 5 VGA時序圖

圖中的紅色區域表示在一個完整的行掃描周期中,Video 圖像信息只在此區域有效,黃色區域表示在一個完整的場掃描周期中,Video 圖像信息只在此區域有效,兩者相交的橙色區域,就是 VGA 圖像的最終顯示區域

1.5 VGA 顯示模式及相關參數

行同步時序可分為 6 個階段,對于這 6 個階段的參數是有嚴格定義的,參數配置不正確,VGA 不能正常顯示。 VGA 顯示器可支持多種分辨率,不同分辨率對應個階段的參數是不同的,常用 VGA 分辨率時序參數,具體見圖 6 。
在這里插入圖片描述
?????? 下面我們以經典 VGA 顯示模式 640x480@60 為例,為讀者講解一下 VGA 顯示的相關參數。

?????? (1) 顯示模式: 640x480@60
?????? ?????? 640x480 是指 VGA 的分辨率, 640 是指有效顯示圖像每一行有 640 個像素點, 480 是指每一幀圖像有 480 行, 640 * 480 = 307200 ≈ 300000 ,每一幀圖片包含約 30 萬個像素點,之前某品牌手機廣告上所說的 30 萬像素指的就是這個; @60 是指 VGA 顯示圖像的刷新頻率,60 就是指 VGA 顯示器每秒刷新圖像 60 次,即每秒鐘需要顯示 60 幀圖像。

?????? (2) 時鐘 (MHz) : 25.175MHz
?????? ?????? 這是 VGA 顯示的工作時鐘,像素點掃描頻率

?????? (3) 行同步信號時序 ( 像素 ) 、場同步信號時序 ( 行數 )
?????? ?????? 行同步信號時序分為 6 段, Sync (同步)、 Back Porch (后沿)、 Left Border (左邊框)、 “Addressable” Video (有效圖像)、 Right Border (右邊框)、 Front Porch (前沿),這 6 段構成一個行掃描周期,單位為像素時鐘周期。
?????? ?????? 同步階段,參數為 96,指在行時序的同步階段,行同步信號需要保持 96 個像素時鐘周期的高電平, 其他幾個階段與此相似。
?????? ?????? 場同步信號時序與其類似,只是單位不再是像素時鐘周期,而是一個完整的行掃描周期,在此不再贅述。
?????? ?????? 在這里,我們看回圖 6,由圖可知,即使 VGA 顯示分辨率相同,但刷新頻率不同的話,相關參數也存在差異,如 640x480@60 、 640x480@75 ,這兩個顯示模式雖然具有相同的分辨率,但是 640x480@75 的刷新頻率更快,所以像素時鐘更快,時序參數也有區別。

?????? 下面我們以顯示模式 640x480@60 、 640x480@75 為例,學習一下時鐘頻率的計算方法。

?????? 行掃描周期 * 場掃描周期 * 刷新頻率 = 時鐘頻率
?????? 640x480@60:
?????? 行掃描周期:800( 像素 ) ,場掃描周期: 525( 行掃描周期 ) 刷新頻率: 60Hz
?????? 800 * 525 * 60 = 25,200,000 ≈ 25.175MHz(誤差忽略不計)
?????? 640x480@75:
?????? 行掃描周期:840( 像素 ) 場掃描周期: 500( 行掃描周期 ) 刷新頻率: 75Hz
?????? 840 * 500 * 75 = 31,500,000 = 31.5MHz
?????? 在計算時鐘頻率時,大家要謹記一點,要使用行掃描周期場掃描周期的參數進行計算,不能使用有效圖像的參數進行計算,雖然在有效圖像外的其他階段圖像信息均無效,但圖像無效階段的掃描也花費了掃描時間。
?????? 以上就是對 VGA 顯示標準中分辨率相關參數的講解,在編寫 VGA 驅動時,我們要根據 VGA 顯示模式的不同調整相關參數,只有這樣 VGA 圖像才能正常顯示。

二、VGA顯示自定義的漢字字符

筆主整篇文章中使用的板子都是 EP4CE115F29C7,使用其他板子問題不大,但引腳綁定不太一樣,可自行對應板子查找更改。

2.1 點陣漢字生成

字模的提取可通過字符取模軟件來實現,在這里我們使用取模軟件“PCtoLCD2002”來獲取漢字 李菊芳-632109160602 的字模。如下圖所示:
在這里插入圖片描述

打開之后會發現軟件中的字體、字寬和字高都是無法設置的,這個時候點擊菜單欄的“模式”,選擇“字符模式”。
切換到字符模式后,就可以設置字體、字寬和字高了。字寬和字高的值越高,顯示在LCD屏上的字符就越大,但是代碼也需要做相應的修改。這里將字體選擇默認的“宋體”,字寬和字高設置成“32”,然后在下方文本框中輸入漢字,如下圖所示:

在這里插入圖片描述

2.2 生成BMP文件

然后點擊文件-另存為,把圖片保存為BMP圖片,再點擊文件-打開,切換到圖形模式,把保存的BMP圖片打開得到整體的字符

在這里插入圖片描述

2.3 生成txt文件

再點擊選項按如下參數設置

在配置界面中,當鼠標懸浮在各配置選項上時,軟件會自動提示當前配置的含義。需要注意的是左下角“每行顯示數據”是以字節(Byte)為單位的,而一個字節的數據為8個bit,即可以表示一行點陣中的8個像素點。由于圖中的點陣每行為304個像素點,所以需要304/8=38個Byte的數據來表示一行,因此將“每行顯示數據—點陣”處設置為38
配置字模選項完成后,點擊“生成字模”,即可得到漢字所對應的點陣數據。
在這里插入圖片描述
最后點擊生成字符并保存字符為文本文件
在這里插入圖片描述

最后得到字符如下
在這里插入圖片描述

把得到的字符在verilog里面使用即可
在這里插入圖片描述

2.4 實現效果

姓名+學號 居中顯示:

在這里插入圖片描述

三、VGA顯示條紋

3.1 實現流程

時鐘分頻模塊
640x480像素的VGA協議所需時鐘頻率25MHZ,使用clk IP核進行時鐘分頻

根據當前行地址判斷需要顯示的顏色即可。

輸出顏色豎條

// 狀態輸出邏輯,根據不同的狀態輸出不同的RGB數據
always @( * ) begincase ( states_current )//彩條states_1 : beginif ( addr_h == 0 ) beginrgb_data = black;endelse if ( addr_h >0 && addr_h <81 ) beginrgb_data = red;endelse if ( addr_h >80 && addr_h <161 ) beginrgb_data = orange;// rgb_data = red;endelse if ( addr_h >160 && addr_h <241 ) beginrgb_data = yellow;endelse if ( addr_h >240 && addr_h <321 ) beginrgb_data = green;endelse if ( addr_h >320 && addr_h <401 ) beginrgb_data = blue;endelse if ( addr_h >400 && addr_h <481 ) beginrgb_data = indigo;endelse if ( addr_h >480 && addr_h <561 ) beginrgb_data = purple;endelse if ( addr_h >560 && addr_h <641 ) beginrgb_data = white;endelse beginrgb_data = black;endend

3.2 實現效果

在這里插入圖片描述

四、VGA輸出一幅彩色圖像

在前面的學習中了解到圖像的格式有多種,例如JPEG,BMP,PNG,JPG等,圖像的位數也有單色、16色、256色、4096色、16位真彩色、24位真彩色、32位真彩色在這里插入圖片描述
這幾種。
VGA的驅動程序顯示的格式為RGB565,我們先找到一張需要顯示的彩色圖片,經過處理,將該圖片轉化為ROM可以存儲的格式,然后VGA驅動程序從ROM中讀取數據,輸出到VGA顯示屏顯示。盡量選一張小的圖片,因為ROM存儲空間有限。

4.1 bmp圖片轉hex文件

使用BMP2Mif軟件將bmp格式圖片轉換為mif文件

在這里插入圖片描述

轉換后的.mif文件:
在這里插入圖片描述

4.2 引入ROM ip核

新建Quartus工程,產生ROM IP核,將生成的mif文件保存在ROM中
雙擊選擇ROM:1-PORT
在這里插入圖片描述

更改設置,words大小設置要大于圖片大小(50x49x24=58800< 65536),然后next
在這里插入圖片描述

取消勾選q
在這里插入圖片描述

如果是16位位圖,就加載HEX文件,然后next

這里因為我們轉換的是24位位圖,所以在ROM里要引入 .mif 文件。(16位位圖不用管)
在這里插入圖片描述

勾選上輸出 inst,方便例化,然后finish

在這里插入圖片描述

這里同時要調用前面的pll ip核生成一個25mHz的時鐘。

4.3 代碼實現

data_drive.v文件里,從ikun_rom取出圖片數據。
在這里插入圖片描述
其他 .v 文件與前文一致。

4.4 實現效果

640*480分辨率顯示下:彩色圖像顯示在正中間

在這里插入圖片描述

五、代碼

5.1 時鐘分頻

分別使用640×480 60HZ和800×600 72HZ,對應時鐘分別為25M和50M,需要使用PLL進行分頻 時鐘頻率 = 行幀長 × 列幀長 * 刷新率

640 ×480 60HZ對應時鐘頻率= 800 ×525 × 60 = 25.2M

ip核里面找到ALTPLL
在這里插入圖片描述

基礎時鐘選擇50M
在這里插入圖片描述

取消勾選輸出使能
在這里插入圖片描述

c0默認輸出50M即可, c1分頻到25M,如需其他時鐘頻率可以自己進行設置
在這里插入圖片描述
勾選如下選項后finish
在這里插入圖片描述

5.2 vga驅動模塊

vga.drive.v

// /*
module vga_dirve (input			wire						clk,            //系統時鐘    input			wire						rst_n,          //復位input			wire		[ 15:0 ]		rgb_data,       //RGB--565,即pixel_data[15:11]控制R、pixel_data[10:5]控制G、pixel_data[4:0]控制Boutput			wire							vga_clk,    //vga時鐘 25Moutput			reg							h_sync,     //行同步信號output			reg							v_sync,     //場同步信號output			reg		[ 11:0 ]				addr_h, //行地址output			reg		[ 11:0 ]				addr_v,  //列地址output			wire		[ 4:0 ]				rgb_r,  //紅基色output			wire		[ 5:0 ]				rgb_g,  //綠基色output			wire		[ 4:0 ]				rgb_b  //藍基色
);// 定義VGA信號的參數,基于640x480 60Hz的VGA模式
// 640 * 480 60HZ
localparam	 H_FRONT = 16; // 行同步前沿信號周期長
localparam	 H_SYNC  = 96; // 行同步信號周期長
localparam	 H_BLACK = 48; // 行同步后沿信號周期長
localparam	 H_ACT   = 640; // 行顯示周期長
localparam	 V_FRONT = 11; // 場同步前沿信號周期長
localparam	 V_SYNC  = 2; // 場同步信號周期長
localparam	 V_BLACK = 31; // 場同步后沿信號周期長
localparam	 V_ACT   = 480; // 場顯示周期長// 800 * 600 72HZ
// localparam	 H_FRONT = 40; // 行同步前沿信號周期長
// localparam	 H_SYNC  = 120; // 行同步信號周期長
// localparam	 H_BLACK = 88; // 行同步后沿信號周期長
// localparam	 H_ACT   = 800; // 行顯示周期長
// localparam	 V_FRONT = 37; // 場同步前沿信號周期長
// localparam	 V_SYNC  = 6; // 場同步信號周期長
// localparam	 V_BLACK = 23; // 場同步后沿信號周期長
// localparam	 V_ACT   = 600; // 場顯示周期長// 計算總的行和場周期
localparam	H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期 16+96+48+640 = 800
localparam	V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期 11+2+6+31+480 = 512
reg			[ 11:0 ]			cnt_h			; // 行計數器 0-799
reg			[ 11:0 ]			cnt_v			; // 場計數器 0-524
reg			[ 15:0 ]			rgb			; // 對應顯示顏色值// 對應計數器開始、結束、計數信號
wire							flag_enable_cnt_h			;
wire							flag_clear_cnt_h			;
wire							flag_enable_cnt_v			;
wire							flag_clear_cnt_v			;
wire							flag_add_cnt_v  			;
wire							valid_area      			;// 25M時鐘 行周期*場周期*刷新率 = 800 * 525 * 60
wire							clk_25			;
// 50M時鐘 1040 * 666 * 72
wire							clk_50			;
//PLL
pll	pll_inst (.areset ( ~rst_n ),.inclk0 ( clk ),.c0 ( clk_50 ), //50M.c1 ( clk_25 ) //25M
);//根據不同分配率選擇不同頻率時鐘
assign vga_clk = clk_25;// 行計數
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) begincnt_h <= 0;endelse if ( flag_enable_cnt_h ) beginif ( flag_clear_cnt_h ) begincnt_h <= 0;endelse begincnt_h <= cnt_h + 1;endendelse begincnt_h <= 0;end
end
assign flag_enable_cnt_h = 1;
assign flag_clear_cnt_h  = cnt_h == H_TOTAL - 1;// 行同步信號
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginh_sync <= 1;endelse if ( cnt_h == H_SYNC - 1 ) begin // 同步周期時為1h_sync <= 0;endelse if ( flag_clear_cnt_h ) begin // 其余為0h_sync <= 1;endelse beginh_sync <= h_sync;end
end// 場計數
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) begincnt_v <= 0;endelse if ( flag_enable_cnt_v ) beginif ( flag_clear_cnt_v ) begincnt_v <= 0;endelse if ( flag_add_cnt_v ) begincnt_v <= cnt_v + 1;endelse begincnt_v <= cnt_v;endendelse begincnt_v <= 0;end
endassign flag_enable_cnt_v = flag_enable_cnt_h;
assign flag_clear_cnt_v  = cnt_v == V_TOTAL - 1;
assign flag_add_cnt_v    = flag_clear_cnt_h;// 場同步信號
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginv_sync <= 1;endelse if ( cnt_v == V_SYNC - 1 ) beginv_sync <= 0;endelse if ( flag_clear_cnt_v ) beginv_sync <= 1;endelse beginv_sync <= v_sync;end
end// 對應有效區域行地址 1-640
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginaddr_h <= 0;endelse if ( valid_area ) beginaddr_h <= cnt_h - H_SYNC - H_BLACK + 1;endelse beginaddr_h <= 0;end
end
// 對應有效區域列地址 1-480
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginaddr_v <= 0;endelse if ( valid_area ) beginaddr_v <= cnt_v -V_SYNC - V_BLACK + 1;endelse beginaddr_v <= 0;end
end
// 有效顯示區域
assign valid_area = cnt_h >= H_SYNC + H_BLACK && cnt_h <= H_SYNC + H_BLACK + H_ACT && cnt_v >= V_SYNC + V_BLACK && cnt_v <= V_SYNC + V_BLACK + V_ACT;// 顯示顏色
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginrgb <= 16'h0;endelse if ( valid_area ) beginrgb <= rgb_data;endelse beginrgb <= 16'b0;end
end
assign rgb_r = rgb[ 15:11 ];
assign rgb_g = rgb[ 10:5 ];
assign rgb_b = rgb[ 4:0 ];
endmodule // vga_dirve
// */

5.3 顯示數據生成模塊

data_drive.v


module data_drive (input			wire						vga_clk,      // VGA時鐘輸入input			wire						rst_n,        // 復位信號,低電平有效input			wire		[ 11:0 ]		addr_h,       // 水平地址輸入input			wire		[ 11:0 ]		addr_v,       // 垂直地址輸入input			wire		[ 2:0 ]		 key,          // 三個按鍵輸入output			reg		[ 15:0 ]				rgb_data      // 輸出的RGB數據);// 定義一些顏色的16位表示
localparam	red    = 16'd63488;
localparam	orange = 16'd64384;
localparam	yellow = 16'd65472;
localparam	green  = 16'd1024;
localparam	blue   = 16'd31;
localparam	indigo = 16'd18448;
localparam	purple = 16'd32784;
localparam	white  = 16'd65503;
localparam	black  = 16'd0;//顯示的名字
// 存儲顯示字符的每一行數據
// reg [ 383:0 ] char_line[ 64:0 ];//李菊芳-632109160602  -16
//16行,每行152個bit
// reg [ 152:0 ] char_line[ 15:0 ];//李菊芳-632109160602 ——32
//32*3+16*13 = 304 304/8 = 38
reg [ 303:0 ] char_line[ 31:0 ];// 定義顯示狀態的參數
localparam	states_1 = 1; // 彩條
localparam	states_2 = 2; // 字符
localparam	states_3 = 3; // 圖片// 圖片的尺寸參數
// parameter	height = 78; // 圖片高度
// parameter	width  = 128; // 圖片寬度//ikun2
parameter	height = 52; // 圖片高度
parameter	width  = 52; // 圖片寬度// 當前狀態和下一個狀態的寄存器
reg			[ 2:0 ]			states_current			; // 當前狀態
reg			[ 2:0 ]			states_next			    ; // 下個狀態// ROM的地址寄存器和數據輸出
reg			[ 13:0 ]		rom_address				; // ROM地址
// wire		[ 15:0 ]		rom_data				; // 圖片數據
wire		[ 23:0 ]		rom_data				; // 顯示彩色圖片數據// 狀態機的標志位
wire							flag_enable_out1			; // 文字有效區域標志
wire							flag_enable_out2			; // 圖片有效區域標志
wire							flag_clear_rom_address		; // ROM地址清零標志
wire							flag_begin_h			    ; // 圖片顯示行開始標志
wire							flag_begin_v			    ; // 圖片顯示列開始標志// 狀態轉移邏輯
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginstates_current <= states_1;// 復位時設置初始狀態為彩條endelse beginstates_current <= states_next;// 否則轉移到下一個狀態end
end// 狀態判斷邏輯,根據按鍵輸入更新下一個狀態
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginstates_next <= states_1;endelse if ( key[ 0 ] ) beginstates_next <= states_1;endelse if ( key[ 1 ] ) beginstates_next <= states_2;endelse if ( key[ 2 ] ) beginstates_next <= states_3;endelse beginstates_next <= states_next;end
end// 狀態輸出邏輯,根據不同的狀態輸出不同的RGB數據
always @( * ) begincase ( states_current )//彩條states_1 : beginif ( addr_h == 0 ) beginrgb_data = black;endelse if ( addr_h >0 && addr_h <81 ) beginrgb_data = red;endelse if ( addr_h >80 && addr_h <161 ) begin// rgb_data = orange;rgb_data = red;endelse if ( addr_h >160 && addr_h <241 ) beginrgb_data = yellow;endelse if ( addr_h >240 && addr_h <321 ) beginrgb_data = green;endelse if ( addr_h >320 && addr_h <401 ) beginrgb_data = blue;endelse if ( addr_h >400 && addr_h <481 ) beginrgb_data = indigo;endelse if ( addr_h >480 && addr_h <561 ) beginrgb_data = purple;endelse if ( addr_h >560 && addr_h <641 ) beginrgb_data = white;endelse beginrgb_data = black;endend//字符states_2 : beginif ( flag_enable_out1 ) begin//480*640// rgb_data = char_line[ addr_v-208 ][ 532 - addr_h ]? white:black;rgb_data = char_line[ addr_v-224 ][ 472 - addr_h ]? white:black;endelse beginrgb_data = black;endend//圖片states_3 : beginif ( flag_enable_out2 ) beginrgb_data = rom_data;endelse beginrgb_data = black;endenddefault: begincase ( addr_h )0 : rgb_data      = black;1 : rgb_data      = red;81 : rgb_data     = orange;161: rgb_data     = yellow;241: rgb_data     = green;321: rgb_data     = blue;401: rgb_data     = indigo;481: rgb_data     = purple;561: rgb_data     = white;default: rgb_data = rgb_data;endcaseendendcase
end//李駿飛的居中顯示參數
//32*3+16*13 = 304 304/8 = 38
// 根據當前狀態和地址范圍設置標志位
parameter ljf_width = 304;  // 字符數據的寬度
parameter ljf_height = 32;  // 字符數據的高度
assign flag_enable_out1 = states_current == states_2 && addr_h >= (640 - ljf_width) / 2 && addr_h <  ((640 - ljf_width) / 2) + ljf_width && addr_v >= (480 - ljf_height) / 2 && addr_v <  ((480 - ljf_height) / 2) + ljf_height;// assign flag_begin_h     = addr_h > ( ( 640 - width ) / 2 ) && addr_h < ( ( 640 - width ) / 2 ) + width + 1;
// assign flag_begin_v     = addr_v > ( ( 480 - height )/2 ) && addr_v <( ( 480 - height )/2 ) + height + 1;
assign flag_begin_h     = addr_h >= ( ( 640 - width ) / 2 ) && addr_h < ( ( 640 - width ) / 2 ) + width ;
assign flag_begin_v     = addr_v >= ( ( 480 - height )/2 ) && addr_v <( ( 480 - height )/2 ) + height ;
assign flag_enable_out2 = states_current == states_3 && flag_begin_h && flag_begin_v;//ROM地址計數器
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginrom_address <= 0;// 復位時清零ROM地址endelse if ( flag_clear_rom_address ) begin //計數滿清零rom_address <= 0;endelse if ( flag_enable_out2 ) begin  //在有效區域內+1rom_address <= rom_address + 1;endelse begin  //無效區域保持rom_address <= rom_address;end
end
assign flag_clear_rom_address = rom_address == height * width - 1 || states_current != states_3;// 初始化顯示文字的邏輯
always@( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) begin//李菊芳-632109160602 ——32//32*3+16*13 = 304 304/8 = 38char_line[0] =  304'h0000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[1] =  304'h0000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[2] =  304'h0003800000101000002008000000000000000000000000000000000000000000000000000000;char_line[3] =  304'h0003C000001C1C0000380E000000000000000000000000000000000000000000000000000000;char_line[4] =  304'h000380100018180000300C000000000000000000000000000000000000000000000000000000;char_line[5] =  304'h000380380018181800300C300000000000000000000000000000000000000000000000000000;char_line[6] =  304'h3FFFFFFC3FFFFFFC1FFFFFF8000001E007C007E0008003C007C0008001E003C001E003C007E0;char_line[7] =  304'h180FE0000098180000300C000000061818600838018006201820018006180620061806200838;char_line[8] =  304'h001FF00000D8180000330C0000000C18303010181F800C3030101F800C180C300C180C301018;char_line[9] =  304'h003FB80000F8180000318C00000008183018200C01801818301801800818181808181818200C;char_line[10] = 304'h 007B9C00019000200030C800000018003018200C01801818600801801800181818001818200C;char_line[11] = 304'h 00F39E0001FFFFF000006000000010003018300C01801808600C01801000180810001808300C;char_line[12] = 304'h 01E38F800300003000004030000010000018300C0180300C600C01801000300C1000300C300C;char_line[13] = 304'h 03C387F0020300301FFFFFF8000030000018000C0180300C600C01803000300C3000300C000C;char_line[14] = 304'h 07838DFE0483083000060000000033E0003000180180300C600C018033E0300C33E0300C0018;char_line[15] = 304'h 1FFFFEF808431C300006000000003630006000180180300C600C01803630300C3630300C0018;char_line[16] = 304'h 38401F3010631830000C00007FFE381803C000300180300C701C01803818300C3818300C0030;char_line[17] = 304'h 60003C0020633030000C008000003808007000600180300C302C01803808300C3808300C0060;char_line[18] = 304'h 0001F00000232330000FFFC00000300C001800C00180300C186C0180300C300C300C300C00C0;char_line[19] = 304'h 0001E0000FFFFFB0000C00C00000300C000801800180300C0F8C0180300C300C300C300C0180;char_line[20] = 304'h 0001E010000F0030000C01800000300C000C03000180300C000C0180300C300C300C300C0300;char_line[21] = 304'h 0001C038000B8030001801800000300C000C02000180300C00180180300C300C300C300C0200;char_line[22] = 304'h 7FFFFFFC001B6030001801800000300C300C04040180180800180180300C1808300C18080404;char_line[23] = 304'h 3801C00000333830003001800000180C300C08040180181800100180180C1818180C18180804;char_line[24] = 304'h 0001C00000631C20003001800000180830081004018018183030018018081818180818181004;char_line[25] = 304'h 0001C00000C30C200060030000000C183018200C01800C30306001800C180C300C180C30200C;char_line[26] = 304'h 0001C0000183046000C0030000000E3018303FF803C0062030C003C00E3006200E3006203FF8;char_line[27] = 304'h 0001C000020300600180C300000003E007C03FF81FF803C00F801FF803E003C003E003C03FF8;char_line[28] = 304'h 003FC0000C030FE002003E000000000000000000000000000000000000000000000000000000;char_line[29] = 304'h 0007C000300303C00C001E000000000000000000000000000000000000000000000000000000;char_line[30] = 304'h 0003800000020080300008000000000000000000000000000000000000000000000000000000;char_line[31] = 304'h 0000000000000000000000000000000000000000000000000000000000000000000000000000;end
end// /*
//ikun
// ROM實例化,根據地址輸出數據
ikun_rom	ikun_rom_inst (
.address ( rom_address ),
.clock ( vga_clk ),
.q ( rom_data )
);
// */endmodule // data_drive

5.4 按鍵消抖模塊

key_debounce.v

module key_debounce(input 	wire	clk,        // 時鐘信號輸入input 	wire 	rst_n,      // 復位信號,低電平有效input 	wire 	key,        // 按鍵輸入output 	reg 	flag,       // 抖動標志,0表示抖動中,1表示抖動結束output 	reg	key_value  // 按鍵穩定后的值
);// 定義參數MAX_NUM,用于設置消抖計數的最大值
parameter MAX_NUM = 20'd1_000_000;// 內部信號聲明
reg [19:0] delay_cnt;  // 用于消抖的計數器,足夠大以覆蓋抖動時間
reg key_reg;            // 上一次按鍵的狀態// 第一個always塊:處理按鍵抖動
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginkey_reg <= 1;        // 復位時,將上一次按鍵狀態設為高電平delay_cnt <= 0;      // 復位時,清零計數器endelse beginkey_reg <= key;      // 非復位時,更新上一次按鍵狀態// 當上一次按鍵狀態與當前按鍵狀態不一致時,認為是抖動開始,重置計數器if(key_reg != key) begindelay_cnt <= MAX_NUM;endelse begin// 如果按鍵狀態一致,開始計數,直到計數器減到0if(delay_cnt > 0)delay_cnt <= delay_cnt - 1;elsedelay_cnt <= 0;endend
end// 第二個always塊:在按鍵穩定后輸出按鍵值和標志
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginflag <= 0;            // 復位時,抖動標志設為0key_value <= 1;       // 復位時,按鍵值設為高電平endelse begin// 當計數器的值減到1時,認為按鍵已經穩定,更新抖動標志和按鍵值if(delay_cnt == 1) beginflag <= 1;key_value <= key;endelse begin// 如果計數器還沒減到1,保持抖動標志為0,按鍵值不變flag <= 0;key_value <= key_value;endend
endendmodule

六、整體實現效果(加入按鍵)

加入按鍵之后的實現效果
在這里插入圖片描述


總結

  • VGA顯示,難點在于顯示驅動模塊,行場同步時序的代碼編寫,可以先寫計數器和大模塊,一些內部信號與標志信號可以逐步完善;其次就是數據顯示中顯示區域代碼的編寫。

  • VGA顯示,顯示彩條部分還可以改進,可以定義不同彩條的顯示區域。顯示文字主要就是顯示位置的確定與漢字點陣的生成,漢字點陣還是費了一些功夫,最開始實在沒找到一個比較合適的轉換工具和方法,后來在朋友的幫助指點下終于可以了。顯示圖片一定要注意24位位圖的話在ROM里面引入的是 .mif 文件,16位位圖的話就引入hex文件。

  • 代碼或哪一部分有問題歡迎留言指正。

參考

VGA顯示接口簡介

基于FPGA的VGA顯示彩條、字符、圖片

【FPGA實驗】基于DE2-115平臺的VGA顯示

FPGA VGA顯示協議

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/15265.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/15265.shtml
英文地址,請注明出處:http://en.pswp.cn/web/15265.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ArcGIS不同圖斑設置不同的透明度

對于設置一個圖層的整體的透明度&#xff0c;我們在 ArcGIS制作帶蒙版的遙感影像地圖http://mp.weixin.qq.com/s?__bizMzIzNjM2NTYxMg&mid2247509080&idx1&sn38dccf0a52bb3bb3758f57114ee38b72&chksme8da161bdfad9f0d363da90959a8524dcf2b60d0e8d999f8ebeef0…

Unity面試八股文之基礎篇

文章目錄 前言1. Unity的生命周期加載第一個場景Editor在第一次幀更新之前幀之間更新順序協程銷毀對象時退出時 2. Unity 協程和線程,進程的區別3. 本地坐標系 世界坐標系4. 碰撞器和觸發器的區別后話 前言 開設這個欄目的博文會寫一些有關unity的面試題目&#xff0c;在面試的…

如何做好軟件項目的溝通管理

如何做好軟件項目的溝通管理 軟件項目的溝通管理是確保項目信息在團隊成員、利益相關者和相關群體之間有效流通的過程。良好的溝通是項目成功的關鍵&#xff0c;在項目開始時&#xff0c;需要制定詳細的溝通計劃&#xff0c;包括溝通的目的、對象、內容、頻率和渠道等信息。 …

【spring】@ResponseBody注解學習

ResponseBody介紹 ResponseBody 是一個Spring框架中的注解&#xff0c;主要用于Web開發&#xff0c;特別是在Spring MVC框架中。它的核心作用是改變Spring MVC處理HTTP請求響應的行為&#xff0c;使得從控制器方法返回的數據直接寫入HTTP響應體&#xff08;Response Body&…

Python面試寶典:Python中與網絡協議基礎和socket編程相關的知識和面試筆試題(1000加面試筆試題助你輕松捕獲大廠Offer)

Python面試寶典:1000加python面試題助你輕松捕獲大廠Offer【第二部分:Python高級特性:第十四章:網絡編程:第一節:網絡協議基礎和socket編程】 第十四章:并發編程第一節:網絡協議基礎和socket編程網絡協議基礎Socket編程創建SocketTCP服務器TCP客戶端數據傳輸關閉Socket…

Python高級進階--slice切片

slice切片?? 在 Python 中&#xff0c;切片操作是一種常見且方便的方式&#xff0c;用于從字符串、列表或元組中獲取部分元素。這種操作通過指定起始索引、結束索引和步長來實現。下面我們來看一些關于切片的簡單介紹以及一些常見用法。 1. 切片簡介 取一個str、list、tup…

【Unity2D:Animator】為角色添加動畫效果

一、添加Animator組件并創建Animator Controller文件 1. 添加Animator組件&#xff1a; 2. 在Assets-Art文件夾中新建一個名為Animations的文件夾&#xff0c;用來存儲所有動畫資源 3. 在Animations文件夾中新建一個名為Player的文件夾&#xff0c;再創建一個名為Animators的文…

LeetCode //C - 119. Pascal‘s Triangle II

119. Pascal’s Triangle II Given an integer rowIndex, return the rowIndexth (0-indexed) row of the Pascal’s triangle. In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown: Example 1: Input: rowIndex 3 Output: …

vue項目移動端商場

一、項目前端頁面展示 二、項目整體目錄結構 三、項目流程 1. vue快速創建基礎項目 創建項目 vue create hk-shop 1 選擇需要的配置 創建基礎文件夾目錄 src文件夾下文件夾目錄&#xff1a; ① views 文件夾存放界面 ② components 文件夾存放界面中局部組件 ③ config 文件夾存…

【排序算法】——歸并排序(遞歸與非遞歸)含動圖

制作不易&#xff0c;三連支持一下吧&#xff01;&#xff01;&#xff01; 文章目錄 前言一.歸并排序遞歸方法實現二.歸并排序非遞歸方法實現 前言 這篇博客我們將介紹歸并排序的原理和實現過程。 一、歸并排序遞歸方法實現 基本思想&#xff1a; 歸并排序&#xff08;MERGE-…

JS(ES_6)_2

1.創建對象的6種方式&#xff1a; 1. obnew Object() ob.nameah ob.age18 2. ob{name:ah,gae:18} 3.工廠模式&#xff1a; 設計一個函數&#xff0c;專門生產Person類型的對象 <script>function createPerson(name,age,family) {var o new Object();o.name name;o.…

軟件設計師備考 | 案例專題之數據流圖 概念與例題

案例分析專題大綱&#xff1a; 數據流圖基本概念 基本圖形元素&#xff1a;外部實體、加工、數據存儲、數據流 數據流&#xff1a;由一組固定成分的數據組成&#xff0c;表示數據的流向。在DFD中&#xff0c;數據流的流向必須經過加工。加工&#xff1a;描述了輸入數據流到輸出…

啊哈!算法-第2章-棧、隊列、鏈表

啊哈!算法-第2章-棧、隊列、鏈表 第1節 解密qq號——隊列第2節 解密回文——棧第3節 紙牌游戲——小貓釣魚第4節 鏈表第5節 模擬鏈表 第1節 解密qq號——隊列 新學期開始了&#xff0c;小哈是小哼的新同桌(小哈是個大帥哥哦~)&#xff0c;小哼向小哈詢問 QQ 號&#xff0c; 小…

算法提高之線段樹

算法提高之線段樹 存儲方式 線段樹除了最后一層葉子節點以外是一個滿二叉樹類似堆的形式 因此可以用堆來存儲線段樹同時注意到 數組是可以模擬堆的 因此我們可以用一位數組來存儲線段樹 節點編號為u&#xff0c;對應左子樹編號為2 * u&#xff0c;右子樹編號為2 * u 1裝逼一…

C++ 學習 指針上

&#x1f64b; 繼續C Primer 第五版的學習 注 后面還會有關于指針進一步的學習 本篇為基礎篇 &#x1f33f;可以先看看這兩篇 或許可以進一步加深一下對指針的理解 指針和數組 指針簡介 &#x1f308; 上一次講了 C中的引用&#xff0c;現在總結一下指針和引用的主要區別。 …

uniapp微信小程序解決open-type獲取用戶頭像,返回臨時路徑問題!

解決 open-type 為 chooseAvatar&#xff0c;返回臨時路徑問題 文章目錄 解決 open-type 為 chooseAvatar&#xff0c;返回臨時路徑問題效果圖Demo獲取頭像回調數據結構效果圖解決方式上傳到服務器轉base64 基于微信小程序獲取頭像昵稱規則調整后&#xff0c;當小程序需要讓用戶…

深入了解FreeRTOS:實時操作系統的核心概念和應用

前言&#xff1a; 在當今數字化世界中&#xff0c;嵌入式系統扮演著至關重要的角色&#xff0c;從工業自動化到智能設備&#xff0c;無所不在。而實時操作系統&#xff08;RTOS&#xff09;則是這些系統的核心引擎&#xff0c;它們負責管理任務、資源和時間&#xff0c;確保系統…

RmlUi 初試,hello world

前言 最近在研究GUI的各個方面&#xff0c;最后被導向了web render&#xff0c;真的是一言難盡。 這里就其中一個比較有意思的項目 RmlUi 淺試一下&#xff0c;沒想要還挺麻煩&#xff01;這里留下note以供后人參考。 環境搭建 Windows VS2022 pre-binary library 需要指…

高通Android 12/13 設置和獲取ADB狀態

/*** 設置ADB狀態** param isEnable*/public void setADB(boolean isEnable) {Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.ADB_ENABLED, isEnable ? 1 : 0);}/*** 獲取ADB狀態** return*/public boolean getADB() {return Settings.Global.getIn…

虛擬化技術[3]之網絡虛擬化

網絡虛擬化 網絡虛擬化簡介核心層網絡虛擬化接入層網絡虛擬化虛擬機網絡虛擬化案例: VMware網絡虛擬化技術虛擬網絡接口卡虛擬交換機vSwitch分布式交換機端口組VLAN 網絡虛擬化簡介 傳統的數據中心&#xff1a;服務器之間操作系統和上層軟件異構、接口與數據格式不統一&#x…