目錄
總體設(shè)計(jì)
?讀顯示屏ID
?讀顯示屏ID代碼
時(shí)鐘分頻
?時(shí)鐘分頻代碼
?LCD顯示
lcd顯示模塊
LCD驅(qū)動(dòng)模塊
lcd驅(qū)動(dòng)代碼
頂層模塊
頂層模塊代碼
總體設(shè)計(jì)
系統(tǒng)總體分為五個(gè)模塊,分別是:rd_id(讀顯示屏ID模塊),clk_div(時(shí)鐘分頻模塊),lcd_display(lcd屏顯示模塊),lcd_driver(lcd屏驅(qū)動(dòng)模塊),和頂層模塊lcd_rgb。
總體框圖如下:
?讀顯示屏ID
?因?yàn)椴煌腖CD屏有著不同的分辨率,并對(duì)應(yīng)了不同的時(shí)序參數(shù),我們需要讀取LCD_B7/G7/R7這三個(gè)管腳的狀態(tài),來判斷當(dāng)前顯示屏的型號(hào)。
查找IO分配表可知LCD_B7/G7/R7分別為lcd_rgb[4],lcd_rgb[10],lcd_rgb[15]。

?讀顯示屏ID代碼
module rd_id(
input wire sys_clk, //系統(tǒng)時(shí)鐘
input wire sys_rst_n, //系統(tǒng)復(fù)位
input wire [15:0] lcd_rgb, //初始像素?cái)?shù)據(jù),用于讀取ID
output reg [15:0] lcd_id //讀取到的ID
);
reg rd_flag; //讀ID標(biāo)志
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
rd_flag <= 1'b0;
lcd_id <= 16'b0;
end
else begin
if(rd_flag == 1'b0) begin //說明開始上電
rd_flag <= 1'b1;
case({lcd_rgb[4],lcd_rgb[10],lcd_rgb[15]})
3'b000: lcd_id <= 16'h4342; //4.3’ RES 480*272
3'b001: lcd_id <= 16'h7084; //7’ RES 800*480
3'b010: lcd_id <= 16'h7016; //7’ RES 1024*600
3'b100: lcd_id <= 16'h4384; //4.3’ RES 800*480
3'b101: lcd_id <= 16'h1018; //10’ RES 1280*800
default : lcd_id <= 16'b0;
endcase
end
end
end
endmodule
時(shí)鐘分頻
不同分辨率有著不同的時(shí)序參數(shù),為了提高兼容性,我增加了時(shí)鐘分頻模塊,能根據(jù)傳入的ID號(hào)來產(chǎn)生對(duì)應(yīng)所需的時(shí)鐘。
其中時(shí)鐘分頻模塊采用了quartus的IP核。
?時(shí)鐘分頻代碼
module clk_div(
input wire sys_clk, //系統(tǒng)時(shí)鐘50MHz
input wire sys_rst_n, //系統(tǒng)復(fù)位
input wire [15:0] lcd_id, //ID號(hào)
output reg lcd_pclk //lcd驅(qū)動(dòng)時(shí)鐘
);
wire clk_10;
wire clk_34;
wire clk_50;
wire clk_70;
wire locked;
pll_clk pll_clk_inst (
.areset ( ~sys_rst_n ), //鎖相環(huán)高電平復(fù)位
.inclk0 ( sys_clk ),
.c0 ( clk_10 ),
.c1 ( clk_34 ),
.c2 ( clk_50 ),
.c3 ( clk_70 ),
.locked ( locked )
);
//---------根據(jù)分辨率選擇對(duì)應(yīng)的時(shí)鐘-----------//
always @(*) begin
if(locked) begin
case(lcd_id)
16'h4342 : lcd_pclk = clk_10; //9M
16'h7084 : lcd_pclk = clk_34; //33.3M
16'h7016 : lcd_pclk = clk_50; //50M
16'h4384 : lcd_pclk = clk_34; //33.3M
16'h1018 : lcd_pclk = clk_70; //70M
default : lcd_pclk = 1'b0;
endcase
end
else begin
lcd_pclk = 1'b0;
end
end
endmodule
?LCD顯示
顯示的圖案可以根據(jù)自己喜好設(shè)置,需要注意的就是h_disp和v_disp這兩個(gè)信號(hào),可以理解成LCD屏的有效顯示邊框/范圍。原來是根據(jù)例程寫了五等分的彩條(注釋部分),后來圖好玩改成了法國(guó)國(guó)旗,參數(shù)中的藍(lán)色和紅色我也改過了。
因?yàn)殡娔X自帶畫板顯示的一般都是RGB888,但是LCD顯示屏用的是RGB565,兩者的位寬不一樣。但RGB888轉(zhuǎn)RGB565的方法也很簡(jiǎn)單,就是分別取8位紅綠藍(lán)的高位。
lcd顯示模塊代碼
module lcd_display(
input wire lcd_pclk, //不同分辨率對(duì)應(yīng)的時(shí)鐘
input wire sys_rst_n, //系統(tǒng)復(fù)位信號(hào)
input wire [10:0] pixel_xpos, //當(dāng)前像素點(diǎn)橫坐標(biāo) (像素點(diǎn)數(shù)最大為1440,11位)
input wire [10:0] pixel_ypos, //當(dāng)前像素點(diǎn)縱坐標(biāo)
input wire [10:0] h_disp, //LCD屏水平分辨率
input wire [10:0] v_disp, //LCD屏垂直分辨率
output reg [15:0] pixel_data //像素?cái)?shù)據(jù)
);
//parameter define
parameter WHITE = 16'b11111_111111_11111; //白色
parameter BLACK = 16'b00000_000000_00000; //黑色
parameter RED = 16'b11111_001111_00110; //紅色
parameter GREEN = 16'b00000_111111_00000; //綠色
parameter BLUE = 16'b00000_010101_10100; //藍(lán)色
parameter YELLOW = 16'b11111_111111_00000; //黃色
always @(posedge lcd_pclk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
pixel_data <= BLACK;
end
else begin
// if(pixel_xpos > 11'b0 && pixel_xpos < h_disp/5*1)
// pixel_data <= RED;
// else if(pixel_xpos > h_disp/5*1 && pixel_xpos < h_disp/5*2)
// pixel_data <= YELLOW;
// else if(pixel_xpos > h_disp/5*2 && pixel_xpos < h_disp/5*3)
// pixel_data <= BLUE;
// else if(pixel_xpos > h_disp/5*3 && pixel_xpos < h_disp/5*4)
// pixel_data <= GREEN;
// else
// pixel_data <= WHITE;
if(pixel_xpos > 11'b0 && pixel_xpos < h_disp/3*1)
pixel_data <= BLUE;
else if(pixel_xpos > h_disp/3*1 && pixel_xpos < h_disp/3*2)
pixel_data <= WHITE;
else
pixel_data <= RED;
end
end
endmodule
LCD驅(qū)動(dòng)模塊
每個(gè)時(shí)鐘內(nèi)會(huì)掃描一個(gè)像素點(diǎn),所以需要設(shè)置計(jì)數(shù)器對(duì)掃到的像素點(diǎn)進(jìn)行計(jì)數(shù)。根據(jù)計(jì)數(shù)值可以圈定LCD屏的有效區(qū)域,當(dāng)處在這個(gè)范圍之內(nèi)時(shí),lcd_de拉高,將傳入的像素?cái)?shù)據(jù)pixel_data通過數(shù)據(jù)端口lcd_rgb傳出至屏幕。
?在這里加一段別的博主對(duì)于lcd_req設(shè)置的理解,里面提到的子母計(jì)數(shù)器是h_cnt和v_cnt。
? ? //...此處做一個(gè)簡(jiǎn)單的分析,lcd_de拉高,lcd_rgb[15:0]的值瞬間到達(dá)屏幕的對(duì)應(yīng)像素點(diǎn)上。
? ? // ? 我們最開始的分析是:cnt值->產(chǎn)生坐標(biāo)->根據(jù)坐標(biāo)確認(rèn)有效范圍->再往范圍里放顏色值
? ? // ? 所以說我們?cè)谏厦鎸懙哪莻€(gè)就是有效范圍,由于觸發(fā)器的特性,所以要提前一個(gè)時(shí)鐘周期將坐標(biāo)值送出,才來的及在lcd_en為1時(shí)候準(zhǔn)確的送出顏色值
? ? // ? 而一場(chǎng)是由很多行組成的,母計(jì)數(shù)器,要比子計(jì)數(shù)器慢。子計(jì)數(shù)器變很多次,母計(jì)數(shù)器才變一次。所以對(duì)子計(jì)數(shù)器需要提前一個(gè)時(shí)鐘周期發(fā)送出坐標(biāo)。
? ? // ? PS:如果沒懂的話也沒關(guān)系,因?yàn)槲乙脖容^暈。但只要時(shí)序?qū)Γ聊痪湍艹霈F(xiàn)顏色然后進(jìn)行simulation或者實(shí)物調(diào)試
————————————————
版權(quán)聲明:本文為CSDN博主「搞IC的那些年」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/helloworld573/article/details/113773634
lcd驅(qū)動(dòng)代碼
module lcd_driver(
input wire lcd_pclk, //不同分辨率對(duì)應(yīng)的時(shí)鐘
input wire sys_rst_n, //系統(tǒng)復(fù)位信號(hào)
input wire [15:0] lcd_id, //不同顯示屏對(duì)應(yīng)的ID
input wire [15:0] pixel_data, //像素?cái)?shù)據(jù)
output wire [10:0] pixel_xpos, //當(dāng)前像素點(diǎn)橫坐標(biāo) (像素點(diǎn)數(shù)最大為1440,11位)
output wire [10:0] pixel_ypos, //當(dāng)前像素點(diǎn)縱坐標(biāo)
output reg [10:0] h_disp, //LCD屏水平分辨率
output reg [10:0] v_disp, //LCD屏垂直分辨率
output wire lcd_de, //RGB LCD數(shù)據(jù)使能
output wire lcd_hs, //RGB LCD行同步
output wire lcd_vs, //RGB LCD場(chǎng)同步
output wire lcd_clk, //RGB LCD像素時(shí)鐘
output wire lcd_bl, //RGB LCD背光控制
output wire lcd_rst, //RGB LCD系統(tǒng)復(fù)位,低有效
output wire [15:0] lcd_rgb //RGB565顏色數(shù)據(jù)
);
wire lcd_en;
wire data_req;
//reg define
reg [10:0] h_sync ;
reg [10:0] h_back ;
reg [10:0] h_total;
reg [10:0] v_sync ;
reg [10:0] v_back ;
reg [10:0] v_total;
reg [10:0] h_cnt ;
reg [10:0] v_cnt ;
//數(shù)據(jù)使能
assign lcd_de = lcd_en;
//行場(chǎng)同步
assign lcd_hs = 1'b1;
assign lcd_vs = 1'b1;
//像素時(shí)鐘
assign lcd_clk = lcd_pclk;
//復(fù)位和背光
assign lcd_rst = (sys_rst_n == 1'b0) ? 1'b0 : 1'b1;
assign lcd_bl = (sys_rst_n == 1'b0) ? 1'b0 : 1'b1;
//parameter define
// 4.3' 480*272
parameter H_SYNC_4342 = 11'd41; //行同步
parameter H_BACK_4342 = 11'd2; //行顯示后沿
parameter H_DISP_4342 = 11'd480; //行有效數(shù)據(jù)
parameter H_FRONT_4342 = 11'd2; //行顯示前沿
parameter H_TOTAL_4342 = 11'd525; //行掃描周期
parameter V_SYNC_4342 = 11'd10; //場(chǎng)同步
parameter V_BACK_4342 = 11'd2; //場(chǎng)顯示后沿
parameter V_DISP_4342 = 11'd272; //場(chǎng)有效數(shù)據(jù)
parameter V_FRONT_4342 = 11'd2; //場(chǎng)顯示前沿
parameter V_TOTAL_4342 = 11'd286; //場(chǎng)掃描周期
// 7' 800*480
parameter H_SYNC_7084 = 11'd128; //行同步
parameter H_BACK_7084 = 11'd88; //行顯示后沿
parameter H_DISP_7084 = 11'd800; //行有效數(shù)據(jù)
parameter H_FRONT_7084 = 11'd40; //行顯示前沿
parameter H_TOTAL_7084 = 11'd1056; //行掃描周期
parameter V_SYNC_7084 = 11'd2; //場(chǎng)同步
parameter V_BACK_7084 = 11'd33; //場(chǎng)顯示后沿
parameter V_DISP_7084 = 11'd480; //場(chǎng)有效數(shù)據(jù)
parameter V_FRONT_7084 = 11'd10; //場(chǎng)顯示前沿
parameter V_TOTAL_7084 = 11'd525; //場(chǎng)掃描周期
// 7' 1024*600
parameter H_SYNC_7016 = 11'd20; //行同步
parameter H_BACK_7016 = 11'd140; //行顯示后沿
parameter H_DISP_7016 = 11'd1024; //行有效數(shù)據(jù)
parameter H_FRONT_7016 = 11'd160; //行顯示前沿
parameter H_TOTAL_7016 = 11'd1344; //行掃描周期
parameter V_SYNC_7016 = 11'd3; //場(chǎng)同步
parameter V_BACK_7016 = 11'd20; //場(chǎng)顯示后沿
parameter V_DISP_7016 = 11'd600; //場(chǎng)有效數(shù)據(jù)
parameter V_FRONT_7016 = 11'd12; //場(chǎng)顯示前沿
parameter V_TOTAL_7016 = 11'd635; //場(chǎng)掃描周期
// 10.1' 1280*800
parameter H_SYNC_1018 = 11'd10; //行同步
parameter H_BACK_1018 = 11'd80; //行顯示后沿
parameter H_DISP_1018 = 11'd1280; //行有效數(shù)據(jù)
parameter H_FRONT_1018 = 11'd70; //行顯示前沿
parameter H_TOTAL_1018 = 11'd1440; //行掃描周期
parameter V_SYNC_1018 = 11'd3; //場(chǎng)同步
parameter V_BACK_1018 = 11'd10; //場(chǎng)顯示后沿
parameter V_DISP_1018 = 11'd800; //場(chǎng)有效數(shù)據(jù)
parameter V_FRONT_1018 = 11'd10; //場(chǎng)顯示前沿
parameter V_TOTAL_1018 = 11'd823; //場(chǎng)掃描周期
// 4.3' 800*480
parameter H_SYNC_4384 = 11'd128; //行同步
parameter H_BACK_4384 = 11'd88; //行顯示后沿
parameter H_DISP_4384 = 11'd800; //行有效數(shù)據(jù)
parameter H_FRONT_4384 = 11'd40; //行顯示前沿
parameter H_TOTAL_4384 = 11'd1056; //行掃描周期
parameter V_SYNC_4384 = 11'd2; //場(chǎng)同步
parameter V_BACK_4384 = 11'd33; //場(chǎng)顯示后沿
parameter V_DISP_4384 = 11'd480; //場(chǎng)有效數(shù)據(jù)
parameter V_FRONT_4384 = 11'd10; //場(chǎng)顯示前沿
parameter V_TOTAL_4384 = 11'd525; //場(chǎng)掃描周期
//行場(chǎng)時(shí)序參數(shù)
always @(posedge lcd_pclk) begin
case(lcd_id)
16'h4342 : begin
h_sync <= H_SYNC_4342;
h_back <= H_BACK_4342;
h_disp <= H_DISP_4342;
h_total <= H_TOTAL_4342;
v_sync <= V_SYNC_4342;
v_back <= V_BACK_4342;
v_disp <= V_DISP_4342;
v_total <= V_TOTAL_4342;
end
16'h7084 : begin
h_sync <= H_SYNC_7084;
h_back <= H_BACK_7084;
h_disp <= H_DISP_7084;
h_total <= H_TOTAL_7084;
v_sync <= V_SYNC_7084;
v_back <= V_BACK_7084;
v_disp <= V_DISP_7084;
v_total <= V_TOTAL_7084;
end
16'h7016 : begin
h_sync <= H_SYNC_7016;
h_back <= H_BACK_7016;
h_disp <= H_DISP_7016;
h_total <= H_TOTAL_7016;
v_sync <= V_SYNC_7016;
v_back <= V_BACK_7016;
v_disp <= V_DISP_7016;
v_total <= V_TOTAL_7016;
end
16'h4384 : begin
h_sync <= H_SYNC_4384;
h_back <= H_BACK_4384;
h_disp <= H_DISP_4384;
h_total <= H_TOTAL_4384;
v_sync <= V_SYNC_4384;
v_back <= V_BACK_4384;
v_disp <= V_DISP_4384;
v_total <= V_TOTAL_4384;
end
16'h1018 : begin
h_sync <= H_SYNC_1018;
h_back <= H_BACK_1018;
h_disp <= H_DISP_1018;
h_total <= H_TOTAL_1018;
v_sync <= V_SYNC_1018;
v_back <= V_BACK_1018;
v_disp <= V_DISP_1018;
v_total <= V_TOTAL_1018;
end
default : begin
h_sync <= H_SYNC_4342;
h_back <= H_BACK_4342;
h_disp <= H_DISP_4342;
h_total <= H_TOTAL_4342;
v_sync <= V_SYNC_4342;
v_back <= V_BACK_4342;
v_disp <= V_DISP_4342;
v_total <= V_TOTAL_4342;
end
endcase
end
//行計(jì)數(shù)器對(duì)行像素點(diǎn)計(jì)數(shù)
always @(posedge lcd_pclk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
h_cnt <= 11'b0;
end
else begin
h_cnt <= (h_cnt == h_total - 1'b1) ? 11'b0 : h_cnt + 1'b1;
end
end
//場(chǎng)計(jì)數(shù)器對(duì)場(chǎng)像素點(diǎn)進(jìn)行計(jì)數(shù)
always @(posedge lcd_pclk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
v_cnt <= 11'b0;
end
else if(h_cnt == h_total - 1'b1)begin
v_cnt <= (v_cnt == v_total - 1'b1) ? 11'b0 : v_cnt + 1'b1;
end
end
//使能RGB565數(shù)據(jù)輸出,lcd_en表示區(qū)域內(nèi)像素點(diǎn)有效
assign lcd_en = (h_cnt >= h_sync + h_back) && (h_cnt < h_sync + h_back + h_disp)
&& (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp) ? 1'b1 : 1'b0;
//請(qǐng)求像素點(diǎn)顏色數(shù)據(jù)輸入,提前一時(shí)鐘將數(shù)據(jù)載入到lcd驅(qū)動(dòng)模塊
assign data_req = (h_cnt >= h_sync + h_back - 1'b1) && (h_cnt < h_sync + h_back + h_disp - 1'b1)
&& (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp) ? 1'b1 : 1'b0;
//RGB565數(shù)據(jù)輸出
assign lcd_rgb = lcd_en ? pixel_data : 16'b0;
//像素點(diǎn)坐標(biāo)
assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 11'b0;
assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'b0;
endmodule
頂層模塊
比較需要注意的就是這里要把lcd_rgb定義為inout類型。當(dāng)lcd_de信號(hào)為高電平時(shí),此時(shí)輸出的像素?cái)?shù)據(jù)有效,將lcd_rgb的引腳方向切換成輸出,并將LCD驅(qū)動(dòng)模塊輸出的lcd_rgb_o(像素?cái)?shù)據(jù))連接至lcd_rgb引腳;當(dāng)lcd_de信號(hào)為低電平時(shí),此時(shí)輸出的像素?cái)?shù)據(jù)無效,將lcd_rgb 的引腳方向切換成輸入。代碼中將高阻狀態(tài)“Z”賦值給lcd_rgb的引腳,表示此時(shí)lcd_rgb的引腳電平由外圍電路決定,此時(shí)可以讀取lcd_rgb的引腳電平,從而獲取到LCD屏的ID。
頂層模塊代碼
module lcd_rgb(
input wire sys_clk, //系統(tǒng)時(shí)鐘
input wire sys_rst_n, //系統(tǒng)復(fù)位信號(hào)
output wire lcd_de, //RGB LCD數(shù)據(jù)使能
output wire lcd_hs, //RGB LCD行同步
output wire lcd_vs, //RGB LCD場(chǎng)同步
output wire lcd_clk, //RGB LCD像素時(shí)鐘
output wire lcd_bl, //RGB LCD背光控制
output wire lcd_rst, //RGB LCD系統(tǒng)復(fù)位,低有效
inout wire [15:0] lcd_rgb //RGB565顏色數(shù)據(jù)
);
wire [15:0] lcd_rgb_i;
wire [15:0] lcd_rgb_o;
wire [15:0] lcd_id;
wire lcd_pclk; //分頻時(shí)鐘
wire [10:0] pixel_xpos;
wire [10:0] pixel_ypos;
wire [10:0] h_disp;
wire [10:0] v_disp;
wire [15:0] pixel_data;
//數(shù)據(jù)雙向端口
assign lcd_rgb = lcd_de ? lcd_rgb_o : 16'bz;
assign lcd_rgb_i = lcd_rgb;
rd_id u_rd_id(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.lcd_rgb(lcd_rgb_i),
.lcd_id(lcd_id)
);
clk_div u_clk_div(
.sys_clk(sys_clk), //50MHz
.sys_rst_n(sys_rst_n),
.lcd_id(lcd_id),
.lcd_pclk(lcd_pclk)
);
lcd_display u_lcd_display(
.lcd_pclk(lcd_pclk), //不同分辨率對(duì)應(yīng)的時(shí)鐘
.sys_rst_n(sys_rst_n), //系統(tǒng)復(fù)位信號(hào)
.pixel_xpos(pixel_xpos), //當(dāng)前像素點(diǎn)橫坐標(biāo) (像素點(diǎn)數(shù)最大為1440,11位)
.pixel_ypos(pixel_ypos), //當(dāng)前像素點(diǎn)縱坐標(biāo)
.h_disp(h_disp), //LCD屏水平分辨率
.v_disp(v_disp), //LCD屏垂直分辨率
.pixel_data(pixel_data) //像素?cái)?shù)據(jù)
);
lcd_driver u_lcd_driver(
.lcd_pclk(lcd_pclk), //不同分辨率對(duì)應(yīng)的時(shí)鐘
.sys_rst_n(sys_rst_n), //系統(tǒng)復(fù)位信號(hào)
.lcd_id(lcd_id), //不同顯示屏對(duì)應(yīng)的ID
.pixel_data(pixel_data), //像素?cái)?shù)據(jù)
.pixel_xpos(pixel_xpos), //當(dāng)前像素點(diǎn)橫坐標(biāo) (像素點(diǎn)數(shù)最大為1440,11位)
.pixel_ypos(pixel_ypos), //當(dāng)前像素點(diǎn)縱坐標(biāo)
.h_disp(h_disp), //LCD屏水平分辨率
.v_disp(v_disp), //LCD屏垂直分辨率
.lcd_de(lcd_de), //RGB LCD數(shù)據(jù)使能
.lcd_hs(lcd_hs), //RGB LCD行同步
.lcd_vs(lcd_vs), //RGB LCD場(chǎng)同步
.lcd_clk(lcd_clk), //RGB LCD像素時(shí)鐘
.lcd_bl(lcd_bl), //RGB LCD背光控制
.lcd_rst(lcd_rst), //RGB LCD系統(tǒng)復(fù)位,低有效
.lcd_rgb(lcd_rgb_o) //RGB565顏色數(shù)據(jù)
);
endmodule
附一張野火畫的框圖文章來源:http://www.zghlxwxcb.cn/news/detail-593447.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-593447.html
到了這里,關(guān)于FPGA實(shí)現(xiàn)LCD顯示屏顯示彩條的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!