圖片顯示系統(tǒng)設(shè)計(jì)
實(shí)驗(yàn)任務(wù)
實(shí)驗(yàn)?zāi)康?/h4>擴(kuò)展板卡上集成了1.8寸彩色液晶屏TFT_LCD模塊,大家可以驅(qū)動(dòng)LCD顯示文字、圖片或動(dòng)態(tài)的波形。本實(shí)驗(yàn)主要學(xué)習(xí)1.8寸串行彩色液晶屏的驅(qū)動(dòng)設(shè)計(jì),然后將小腳丫Logo處理顯示,完成圖片顯示系統(tǒng)的總體設(shè)計(jì)。
本文引用地址:http://m.butianyuan.cn/article/202312/453982.htm設(shè)計(jì)框圖
根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)可以拆分成兩個(gè)功能模塊實(shí)現(xiàn),
實(shí)驗(yàn)原理
液晶屏介紹
查看底板上集成的1.8寸串行彩色液晶屏規(guī)格書(shū),屏幕采用ST7735S的驅(qū)動(dòng)芯片,接下來(lái)我們主要根據(jù)ST7735S的芯片手冊(cè)來(lái)了解其工作原理和驅(qū)動(dòng)方法。
ST7735S為132RGB x 162像素點(diǎn) 262K 控制器/驅(qū)動(dòng)器,芯片可以直接跟外部處理器連接,支持串行SPI通信和8/9/16/18位并行通信(本液晶屏集成ST7735S時(shí)沒(méi)有留并行接口,所以只能使用串行通信),詳細(xì)參數(shù)請(qǐng)參考數(shù)據(jù)手冊(cè)。
ST7735S支持不同位寬的并行通信格式。
在控制器給屏幕刷屏?xí)r,根據(jù)MV、MX、MY的配置支持8種不同方向的刷屏模式。
支持大量功能指令,部分系統(tǒng)功能指令列表如下
更多的內(nèi)容這里就不一一介紹了,感興趣的同學(xué)可以詳細(xì)閱讀ST7735S芯片手冊(cè)。
液晶屏硬件連接
STEP BaseBoard V3.0底板上的1.8寸串行彩色液晶屏模塊電路:
底板上的1.8寸串行彩色液晶屏電路和VGA顯示電路復(fù)用部分FPGA管腳,兩者不能同時(shí)使用,當(dāng)使用1.8寸串行彩色液晶屏?xí)r,DISPSEL信號(hào)置高,驅(qū)動(dòng)1.8寸串行彩色液晶屏使能同時(shí)點(diǎn)亮背光,DISP2~ DISP_5分別對(duì)應(yīng)RESET、D/C、SDA、SCK管腳,最后FPGA驅(qū)動(dòng)1.8寸液晶屏完成屏顯示控制即可。
液晶屏驅(qū)動(dòng)設(shè)計(jì)
要驅(qū)動(dòng)液晶屏需要先了解液晶屏的驅(qū)動(dòng)流程,可以從液晶屏驅(qū)動(dòng)芯片ST7735S的芯片手冊(cè)上獲取,也可以到網(wǎng)上找找有沒(méi)有別人使用同類(lèi)液晶屏的案例,或者向賣(mài)方問(wèn)問(wèn)有沒(méi)有相關(guān)資料提供,這里我們找到了一個(gè)用51單片機(jī)驅(qū)動(dòng)的程序例程,例程僅供參考,需要根據(jù)例程中的配置到芯片手冊(cè)中查找確認(rèn),不可以直接套用。
首先完成液晶屏初始化操作,51程序流程如下:
void ST7735_LAIBAO177_INITIAL ()
{
//-----------ST7735R Reset Sequence----------------//
RES =1; delay (1); //Delay 1ms
RES =0; delay (1); //Delay 1ms
RES =1; delay (120); //Delay 120ms
//----------End ST7735R Reset Sequence ------------//
LCD_WriteCommand(0x11); //Sleep out
delay(120); //Delay 120ms
//---------ST7735S Frame Rate-------------------//
LCD_WriteCommand(0xB1); LCD_WriteData(0x05);
LCD_WriteData(0x3C); LCD_WriteData(0x3C);
LCD_WriteCommand(0xB2);
LCD_WriteData(0x05);
LCD_WriteData(0x3C);
LCD_WriteData(0x3C);
LCD_WriteCommand(0xB3);
LCD_WriteData(0x05);
LCD_WriteData(0x3C);
LCD_WriteData(0x3C);
LCD_WriteData(0x05);
LCD_WriteData(0x3C);
LCD_WriteData(0x3C);
//-----------End ST7735S Frame Rate---------------//
LCD_WriteCommand(0xB4); //Dot inversion
LCD_WriteData(0x03);
//-----------ST7735S Power Sequence---------------//
LCD_WriteCommand(0xC0);
LCD_WriteData(0x28);
LCD_WriteData(0x08);
LCD_WriteData(0x04);
LCD_WriteCommand(0xC1);
LCD_WriteData(0XC0);
LCD_WriteCommand(0xC2);
LCD_WriteData(0x0D);
LCD_WriteData(0x00);
LCD_WriteCommand(0xC3);
LCD_WriteData(0x8D);
LCD_WriteData(0x2A);
LCD_WriteCommand(0xC4);
LCD_WriteData(0x8D);
LCD_WriteData(0xEE);
//----------End ST7735S Power Sequence----------//
LCD_WriteCommand(0xC5); //VCOM
LCD_WriteData(0x18); //1a
LCD_WriteCommand(0x36); //MX, MY, RGB mode
LCD_WriteData(0xC0);
//-----------ST7735S Gamma Sequence-----------//
LCD_WriteCommand(0xE0);
LCD_WriteData(0x04); LCD_WriteData(0x22); LCD_WriteData(0x07);
LCD_WriteData(0x0A); LCD_WriteData(0x2E); LCD_WriteData(0x30);
LCD_WriteData(0x25); LCD_WriteData(0x2A); LCD_WriteData(0x28);
LCD_WriteData(0x26); LCD_WriteData(0x2E); LCD_WriteData(0x3A);
LCD_WriteData(0x00); LCD_WriteData(0x01); LCD_WriteData(0x03);
LCD_WriteData(0x13);
LCD_WriteCommand(0xE1);
LCD_WriteData(0x04); LCD_WriteData(0x16); LCD_WriteData(0x06);
LCD_WriteData(0x0D); LCD_WriteData(0x2D); LCD_WriteData(0x26);
LCD_WriteData(0x23); LCD_WriteData(0x27); LCD_WriteData(0x27);
LCD_WriteData(0x25); LCD_WriteData(0x2D); LCD_WriteData(0x3B);
LCD_WriteData(0x00); LCD_WriteData(0x01); LCD_WriteData(0x04);
LCD_WriteData(0x13);
//------------End ST7735S Gamma Sequence----------//
LCD_WriteCommand(0x3A); //65k mode
LCD_WriteData(0x05);
LCD_WriteCommand(0x29); //Display on
}
創(chuàng)建存儲(chǔ)器,將初始化過(guò)程中寫(xiě)的所有指令和數(shù)據(jù)存儲(chǔ),同時(shí)存儲(chǔ)的還有指令或數(shù)據(jù)標(biāo)志,例如初始化第1條指令為8'h11,我們?cè)黾幼罡呶?‘b0組成9位位寬數(shù)據(jù)。存儲(chǔ)器部分指令和數(shù)據(jù)如下:
initial begin //LCD初始化的命令及數(shù)據(jù)
reg_init[ 0] = {1'b0,8'h11}; //最高位為0,表示低8位為指令
reg_init[ 1] = {1'b0,8'hb1};
reg_init[ 2] = {1'b1,8'h05}; //最高位為1,表示低8位為數(shù)據(jù)
reg_init[ 3] = {1'b1,8'h3c};
reg_init[ 4] = {1'b1,8'h3c};
從51例程中可以看到,整個(gè)初始化過(guò)程都在給液晶屏寫(xiě)指令或數(shù)據(jù),通過(guò)查看寫(xiě)指令或?qū)憯?shù)據(jù)的時(shí)序發(fā)現(xiàn),唯一不同的就是對(duì)A0(對(duì)應(yīng)底板液晶屏模塊中的D/C信號(hào))的控制,程序?qū)崿F(xiàn)如下:
void LCD_WriteXXX(uint dat)
{ int i;
A0=0; //寫(xiě)指令,如果寫(xiě)數(shù)據(jù) A0=1;
CSB=0; //液晶屏使能
for(i=0;i<8;i++)
{
if(dat &0x80) SDA=1;
else SDA=0;
SCL=0; SCL=1;
dat <<=1;
}
CSB=1;
}
FPGA驅(qū)動(dòng)液晶屏的設(shè)計(jì)使用狀態(tài)機(jī)完成,將寫(xiě)數(shù)據(jù)與寫(xiě)指令的SPI時(shí)序整合成一個(gè)狀態(tài),另加一位指令數(shù)據(jù)控制位,程序?qū)崿F(xiàn)如下:
WRITE:begin //WRITE狀態(tài),將數(shù)據(jù)按照SPI時(shí)序發(fā)送給屏幕
if(cnt_write >= 6'd17) cnt_write <= 1'b0;
else cnt_write <= cnt_write + 1'b1;
case(cnt_write)
6'd0: begin lcd_dc <= data_reg[8]; end //9位數(shù)據(jù)最高位為命令數(shù)據(jù)控制位
6'd1: begin lcd_clk <= LOW; lcd_din <= data_reg[7]; end //先發(fā)高位數(shù)據(jù)
6'd2: begin lcd_clk <= HIGH; end
6'd3: begin lcd_clk <= LOW; lcd_din <= data_reg[6]; end
6'd4: begin lcd_clk <= HIGH; end
6'd5: begin lcd_clk <= LOW; lcd_din <= data_reg[5]; end
6'd6: begin lcd_clk <= HIGH; end
6'd7: begin lcd_clk <= LOW; lcd_din <= data_reg[4]; end
6'd8: begin lcd_clk <= HIGH; end
6'd9: begin lcd_clk <= LOW; lcd_din <= data_reg[3]; end
6'd10: begin lcd_clk <= HIGH; end
6'd11: begin lcd_clk <= LOW; lcd_din <= data_reg[2]; end
6'd12: begin lcd_clk <= HIGH; end
6'd13: begin lcd_clk <= LOW; lcd_din <= data_reg[1]; end
6'd14: begin lcd_clk <= HIGH; end
6'd15: begin lcd_clk <= LOW; lcd_din <= data_reg[0]; end //后發(fā)低位數(shù)據(jù)
6'd16: begin lcd_clk <= HIGH; end
6'd17: begin lcd_clk <= LOW; state <= DELAY; end //
default: state <= IDLE;
endcase
end
初始化指令和數(shù)據(jù)都放到存儲(chǔ)器中了,數(shù)據(jù)寫(xiě)入的SPI串行時(shí)序也已經(jīng)設(shè)計(jì)成了一個(gè)狀態(tài),初始化狀態(tài)只需要在復(fù)位后將存儲(chǔ)器中的指令或數(shù)據(jù)通過(guò)WRITE狀態(tài)發(fā)送給液晶屏,程序?qū)崿F(xiàn)如下:
INIT:begin //初始化狀態(tài)
if(cnt_init==3'd4) begin
if(cnt==INIT_DEPTH) cnt_init <= 1'b0;
else cnt_init <= cnt_init;
end else cnt_init <= cnt_init + 1'b1;
case(cnt_init)
3'd0: lcd_res <= 1'b0; //復(fù)位有效
3'd1: begin num_delay<=16'd3000; state<=DELAY; state_back<=INIT; end
3'd2: lcd_res <= 1'b1; //復(fù)位恢復(fù)
3'd3: begin num_delay<=16'd3000; state<=DELAY; state_back<=INIT; end
3'd4: if(cnt>=INIT_DEPTH) begin //當(dāng)62條指令及數(shù)據(jù)發(fā)出后,配置完成
cnt <= 16'd0; state <= MAIN;
end else begin
cnt <= cnt + 16'd1; data_reg <= reg_init[cnt];
if(cnt==16'd0) num_delay <= 16'd50000; //第一條指令需要較長(zhǎng)延時(shí)
else num_delay <= 16'd50;
state <= WRITE; state_back <= INIT;
end
default: state <= IDLE;
endcase
end
初始化完成,進(jìn)入刷屏狀態(tài),刷屏數(shù)據(jù)寫(xiě)入前首先進(jìn)行區(qū)域坐標(biāo)的定位,然后刷寫(xiě)數(shù)據(jù),圖片采用單色顯示,圖片ram中每位數(shù)表示一個(gè)液晶屏一個(gè)像素點(diǎn)的亮還是滅,彩色液晶屏本實(shí)驗(yàn)采用16bit格式,即需要16bit數(shù)據(jù)決定像素的顏色,16bit數(shù)據(jù)分兩次發(fā)送,最終從ram模塊中獲取的數(shù)據(jù)每位數(shù)據(jù)都要轉(zhuǎn)換成16bit的數(shù)據(jù),0轉(zhuǎn)換成背景色對(duì)應(yīng)的數(shù)據(jù),1轉(zhuǎn)換成頂層色對(duì)應(yīng)的數(shù)據(jù),程序?qū)崿F(xiàn)如下:
SCAN:begin //刷屏狀態(tài),從RAM中讀取數(shù)據(jù)刷屏
case(cnt_scan)
3'd0: if(cnt >= 11) begin //確定刷屏的區(qū)域坐標(biāo),這里為全屏
cnt <= 16'd0;
cnt_scan <= cnt_scan + 1'b1;
end else begin
cnt <= cnt + 16'd1;
data_reg <= reg_setxy[cnt];
num_delay <= 16'd50;
state <= WRITE; state_back <= SCAN;
end
3'd1: begin ram_clk_en<=HIGH;ram_addr<=y_cnt;cnt_scan<=cnt_scan+1'b1; end
3'd2: begin cnt_scan <= cnt_scan + 1'b1; end //延時(shí)一個(gè)時(shí)鐘
3'd3: begin ram_clk_en<=LOW;ram_data_r<=ram_data;cnt_scan<=cnt_scan+1'b1; end
3'd4: begin //每個(gè)像素點(diǎn)需要16bit的數(shù)據(jù),SPI每次傳8bit,兩次分別傳送高8位和低8位
if(x_cnt>=LCD_W) begin //當(dāng)一個(gè)數(shù)據(jù)(一行屏幕)寫(xiě)完后,
x_cnt <= 8'd0;
if(y_cnt>=LCD_H) begin y_cnt <= 8'd0; cnt_scan <= cnt_scan + 1'b1; end //如果是最后一行就跳出循環(huán)
else begin y_cnt <= y_cnt + 1'b1; cnt_scan <= 3'd1; end //否則跳轉(zhuǎn)至RAM時(shí)鐘使能,循環(huán)刷屏
end else begin
if(high_word)
//根據(jù)相應(yīng)bit的狀態(tài)判定顯示頂層色或背景色,根據(jù)high_word的狀態(tài)判定寫(xiě)高8位或低8位
data_reg <= {1'b1,(ram_data_r[x_cnt]? color_t[15:8]:color_b[15:8])};
else begin
data_reg <= {1'b1,(ram_data_r[x_cnt]? color_t[7:0]:color_b[7:0])};
x_cnt <= x_cnt + 1'b1;
end //
high_word <= ~high_word; //high_word的狀態(tài)翻轉(zhuǎn)
num_delay <= 16'd50; //設(shè)定延時(shí)時(shí)間
state <= WRITE; //跳轉(zhuǎn)至WRITE狀態(tài)
state_back <= SCAN; //執(zhí)行完WRITE及DELAY操作后返回SCAN狀態(tài)
end
end
3'd5: begin cnt_scan <= 1'b0; state <= MAIN; end
default: state <= IDLE;
endcase
end
系統(tǒng)總體實(shí)現(xiàn)
液晶屏驅(qū)動(dòng)模塊的數(shù)據(jù)來(lái)源于圖片數(shù)據(jù)的ram模塊,這些數(shù)據(jù)由圖片取模得到,使用圖片取模軟件,將圖片載入軟件,輸出數(shù)據(jù)類(lèi)型選擇C語(yǔ)言數(shù)組,根據(jù)液晶屏驅(qū)動(dòng)實(shí)際情況配置對(duì)應(yīng)的掃描模式,輸出灰度選擇單色,調(diào)整最大寬度和高度符合液晶屏要求,最后點(diǎn)擊保存生成需要的文件。
打開(kāi)生成的文件,數(shù)據(jù)格式如下,是C語(yǔ)言的格式
const unsigned char gImage_11[1990] = { 0X10,0X01,0X00,0X80,0X00,0X7C,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
使用編輯器的查找替換功能,將數(shù)據(jù)處理成下圖格式
132'h00000000000000000000000000000000,
132'h00000000000000000000000000000000,
132'h00000000000000000000000000000000,
132'h0000000000000000F800000000000000,
132'h0000000000000007FF00000000000000,
創(chuàng)建ram模塊,將圖片數(shù)據(jù)初始化到ram中,程序?qū)崿F(xiàn)圖下:
module LCD_RAM (input wire [7:0] Address, output reg [131:0] Q);
always @ (*)
case(Address)
8'd0 : Q = 132'h00000000000000000000000000000000;
8'd1 : Q = 132'h00000000000000000000000000000000;
8'd2 : Q = 132'h00000000000000000000000000000000;
8'd3 : Q = 132'h0000000000000000F800000000000000;
8'd4 : Q = 132'h0000000000000007FF00000000000000;
存儲(chǔ)圖片數(shù)據(jù)的ram本實(shí)驗(yàn)采用分布式ram搭建,前面波形信號(hào)發(fā)生器實(shí)驗(yàn)中講過(guò)ram IP核的例化及使用方法,有興趣的同學(xué)可以自己嘗試一下。
在頂層模塊中,將兩個(gè)模塊例化并連接,最終完成圖片顯示系統(tǒng)的總體設(shè)計(jì)。
實(shí)驗(yàn)步驟
實(shí)驗(yàn)現(xiàn)象
將設(shè)計(jì)加載到FPGA中,觀察底板液晶屏顯示,小腳丫的Logo被顯示出來(lái)了,前面說(shuō)了1.8寸串行液晶屏支持不同的刷新方向,大家可以調(diào)整圖片顯示的方向
擴(kuò)展板卡上集成了1.8寸彩色液晶屏TFT_LCD模塊,大家可以驅(qū)動(dòng)LCD顯示文字、圖片或動(dòng)態(tài)的波形。本實(shí)驗(yàn)主要學(xué)習(xí)1.8寸串行彩色液晶屏的驅(qū)動(dòng)設(shè)計(jì),然后將小腳丫Logo處理顯示,完成圖片顯示系統(tǒng)的總體設(shè)計(jì)。
本文引用地址:http://m.butianyuan.cn/article/202312/453982.htm根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)可以拆分成兩個(gè)功能模塊實(shí)現(xiàn),
查看底板上集成的1.8寸串行彩色液晶屏規(guī)格書(shū),屏幕采用ST7735S的驅(qū)動(dòng)芯片,接下來(lái)我們主要根據(jù)ST7735S的芯片手冊(cè)來(lái)了解其工作原理和驅(qū)動(dòng)方法。
ST7735S為132RGB x 162像素點(diǎn) 262K 控制器/驅(qū)動(dòng)器,芯片可以直接跟外部處理器連接,支持串行SPI通信和8/9/16/18位并行通信(本液晶屏集成ST7735S時(shí)沒(méi)有留并行接口,所以只能使用串行通信),詳細(xì)參數(shù)請(qǐng)參考數(shù)據(jù)手冊(cè)。
ST7735S支持不同位寬的并行通信格式。
在控制器給屏幕刷屏?xí)r,根據(jù)MV、MX、MY的配置支持8種不同方向的刷屏模式。
支持大量功能指令,部分系統(tǒng)功能指令列表如下
更多的內(nèi)容這里就不一一介紹了,感興趣的同學(xué)可以詳細(xì)閱讀ST7735S芯片手冊(cè)。
STEP BaseBoard V3.0底板上的1.8寸串行彩色液晶屏模塊電路:
底板上的1.8寸串行彩色液晶屏電路和VGA顯示電路復(fù)用部分FPGA管腳,兩者不能同時(shí)使用,當(dāng)使用1.8寸串行彩色液晶屏?xí)r,DISPSEL信號(hào)置高,驅(qū)動(dòng)1.8寸串行彩色液晶屏使能同時(shí)點(diǎn)亮背光,DISP2~ DISP_5分別對(duì)應(yīng)RESET、D/C、SDA、SCK管腳,最后FPGA驅(qū)動(dòng)1.8寸液晶屏完成屏顯示控制即可。
要驅(qū)動(dòng)液晶屏需要先了解液晶屏的驅(qū)動(dòng)流程,可以從液晶屏驅(qū)動(dòng)芯片ST7735S的芯片手冊(cè)上獲取,也可以到網(wǎng)上找找有沒(méi)有別人使用同類(lèi)液晶屏的案例,或者向賣(mài)方問(wèn)問(wèn)有沒(méi)有相關(guān)資料提供,這里我們找到了一個(gè)用51單片機(jī)驅(qū)動(dòng)的程序例程,例程僅供參考,需要根據(jù)例程中的配置到芯片手冊(cè)中查找確認(rèn),不可以直接套用。
首先完成液晶屏初始化操作,51程序流程如下:
void ST7735_LAIBAO177_INITIAL () { //-----------ST7735R Reset Sequence----------------// RES =1; delay (1); //Delay 1ms RES =0; delay (1); //Delay 1ms RES =1; delay (120); //Delay 120ms //----------End ST7735R Reset Sequence ------------// LCD_WriteCommand(0x11); //Sleep out delay(120); //Delay 120ms //---------ST7735S Frame Rate-------------------// LCD_WriteCommand(0xB1); LCD_WriteData(0x05); LCD_WriteData(0x3C); LCD_WriteData(0x3C); LCD_WriteCommand(0xB2); LCD_WriteData(0x05); LCD_WriteData(0x3C); LCD_WriteData(0x3C); LCD_WriteCommand(0xB3); LCD_WriteData(0x05); LCD_WriteData(0x3C); LCD_WriteData(0x3C); LCD_WriteData(0x05); LCD_WriteData(0x3C); LCD_WriteData(0x3C); //-----------End ST7735S Frame Rate---------------// LCD_WriteCommand(0xB4); //Dot inversion LCD_WriteData(0x03); //-----------ST7735S Power Sequence---------------// LCD_WriteCommand(0xC0); LCD_WriteData(0x28); LCD_WriteData(0x08); LCD_WriteData(0x04); LCD_WriteCommand(0xC1); LCD_WriteData(0XC0); LCD_WriteCommand(0xC2); LCD_WriteData(0x0D); LCD_WriteData(0x00); LCD_WriteCommand(0xC3); LCD_WriteData(0x8D); LCD_WriteData(0x2A); LCD_WriteCommand(0xC4); LCD_WriteData(0x8D); LCD_WriteData(0xEE); //----------End ST7735S Power Sequence----------// LCD_WriteCommand(0xC5); //VCOM LCD_WriteData(0x18); //1a LCD_WriteCommand(0x36); //MX, MY, RGB mode LCD_WriteData(0xC0); //-----------ST7735S Gamma Sequence-----------// LCD_WriteCommand(0xE0); LCD_WriteData(0x04); LCD_WriteData(0x22); LCD_WriteData(0x07); LCD_WriteData(0x0A); LCD_WriteData(0x2E); LCD_WriteData(0x30); LCD_WriteData(0x25); LCD_WriteData(0x2A); LCD_WriteData(0x28); LCD_WriteData(0x26); LCD_WriteData(0x2E); LCD_WriteData(0x3A); LCD_WriteData(0x00); LCD_WriteData(0x01); LCD_WriteData(0x03); LCD_WriteData(0x13); LCD_WriteCommand(0xE1); LCD_WriteData(0x04); LCD_WriteData(0x16); LCD_WriteData(0x06); LCD_WriteData(0x0D); LCD_WriteData(0x2D); LCD_WriteData(0x26); LCD_WriteData(0x23); LCD_WriteData(0x27); LCD_WriteData(0x27); LCD_WriteData(0x25); LCD_WriteData(0x2D); LCD_WriteData(0x3B); LCD_WriteData(0x00); LCD_WriteData(0x01); LCD_WriteData(0x04); LCD_WriteData(0x13); //------------End ST7735S Gamma Sequence----------// LCD_WriteCommand(0x3A); //65k mode LCD_WriteData(0x05); LCD_WriteCommand(0x29); //Display on }
創(chuàng)建存儲(chǔ)器,將初始化過(guò)程中寫(xiě)的所有指令和數(shù)據(jù)存儲(chǔ),同時(shí)存儲(chǔ)的還有指令或數(shù)據(jù)標(biāo)志,例如初始化第1條指令為8'h11,我們?cè)黾幼罡呶?‘b0組成9位位寬數(shù)據(jù)。存儲(chǔ)器部分指令和數(shù)據(jù)如下:
initial begin //LCD初始化的命令及數(shù)據(jù) reg_init[ 0] = {1'b0,8'h11}; //最高位為0,表示低8位為指令 reg_init[ 1] = {1'b0,8'hb1}; reg_init[ 2] = {1'b1,8'h05}; //最高位為1,表示低8位為數(shù)據(jù) reg_init[ 3] = {1'b1,8'h3c}; reg_init[ 4] = {1'b1,8'h3c};
從51例程中可以看到,整個(gè)初始化過(guò)程都在給液晶屏寫(xiě)指令或數(shù)據(jù),通過(guò)查看寫(xiě)指令或?qū)憯?shù)據(jù)的時(shí)序發(fā)現(xiàn),唯一不同的就是對(duì)A0(對(duì)應(yīng)底板液晶屏模塊中的D/C信號(hào))的控制,程序?qū)崿F(xiàn)如下:
void LCD_WriteXXX(uint dat) { int i; A0=0; //寫(xiě)指令,如果寫(xiě)數(shù)據(jù) A0=1; CSB=0; //液晶屏使能 for(i=0;i<8;i++) { if(dat &0x80) SDA=1; else SDA=0; SCL=0; SCL=1; dat <<=1; } CSB=1; }
FPGA驅(qū)動(dòng)液晶屏的設(shè)計(jì)使用狀態(tài)機(jī)完成,將寫(xiě)數(shù)據(jù)與寫(xiě)指令的SPI時(shí)序整合成一個(gè)狀態(tài),另加一位指令數(shù)據(jù)控制位,程序?qū)崿F(xiàn)如下:
WRITE:begin //WRITE狀態(tài),將數(shù)據(jù)按照SPI時(shí)序發(fā)送給屏幕 if(cnt_write >= 6'd17) cnt_write <= 1'b0; else cnt_write <= cnt_write + 1'b1; case(cnt_write) 6'd0: begin lcd_dc <= data_reg[8]; end //9位數(shù)據(jù)最高位為命令數(shù)據(jù)控制位 6'd1: begin lcd_clk <= LOW; lcd_din <= data_reg[7]; end //先發(fā)高位數(shù)據(jù) 6'd2: begin lcd_clk <= HIGH; end 6'd3: begin lcd_clk <= LOW; lcd_din <= data_reg[6]; end 6'd4: begin lcd_clk <= HIGH; end 6'd5: begin lcd_clk <= LOW; lcd_din <= data_reg[5]; end 6'd6: begin lcd_clk <= HIGH; end 6'd7: begin lcd_clk <= LOW; lcd_din <= data_reg[4]; end 6'd8: begin lcd_clk <= HIGH; end 6'd9: begin lcd_clk <= LOW; lcd_din <= data_reg[3]; end 6'd10: begin lcd_clk <= HIGH; end 6'd11: begin lcd_clk <= LOW; lcd_din <= data_reg[2]; end 6'd12: begin lcd_clk <= HIGH; end 6'd13: begin lcd_clk <= LOW; lcd_din <= data_reg[1]; end 6'd14: begin lcd_clk <= HIGH; end 6'd15: begin lcd_clk <= LOW; lcd_din <= data_reg[0]; end //后發(fā)低位數(shù)據(jù) 6'd16: begin lcd_clk <= HIGH; end 6'd17: begin lcd_clk <= LOW; state <= DELAY; end // default: state <= IDLE; endcase end
初始化指令和數(shù)據(jù)都放到存儲(chǔ)器中了,數(shù)據(jù)寫(xiě)入的SPI串行時(shí)序也已經(jīng)設(shè)計(jì)成了一個(gè)狀態(tài),初始化狀態(tài)只需要在復(fù)位后將存儲(chǔ)器中的指令或數(shù)據(jù)通過(guò)WRITE狀態(tài)發(fā)送給液晶屏,程序?qū)崿F(xiàn)如下:
INIT:begin //初始化狀態(tài) if(cnt_init==3'd4) begin if(cnt==INIT_DEPTH) cnt_init <= 1'b0; else cnt_init <= cnt_init; end else cnt_init <= cnt_init + 1'b1; case(cnt_init) 3'd0: lcd_res <= 1'b0; //復(fù)位有效 3'd1: begin num_delay<=16'd3000; state<=DELAY; state_back<=INIT; end 3'd2: lcd_res <= 1'b1; //復(fù)位恢復(fù) 3'd3: begin num_delay<=16'd3000; state<=DELAY; state_back<=INIT; end 3'd4: if(cnt>=INIT_DEPTH) begin //當(dāng)62條指令及數(shù)據(jù)發(fā)出后,配置完成 cnt <= 16'd0; state <= MAIN; end else begin cnt <= cnt + 16'd1; data_reg <= reg_init[cnt]; if(cnt==16'd0) num_delay <= 16'd50000; //第一條指令需要較長(zhǎng)延時(shí) else num_delay <= 16'd50; state <= WRITE; state_back <= INIT; end default: state <= IDLE; endcase end
初始化完成,進(jìn)入刷屏狀態(tài),刷屏數(shù)據(jù)寫(xiě)入前首先進(jìn)行區(qū)域坐標(biāo)的定位,然后刷寫(xiě)數(shù)據(jù),圖片采用單色顯示,圖片ram中每位數(shù)表示一個(gè)液晶屏一個(gè)像素點(diǎn)的亮還是滅,彩色液晶屏本實(shí)驗(yàn)采用16bit格式,即需要16bit數(shù)據(jù)決定像素的顏色,16bit數(shù)據(jù)分兩次發(fā)送,最終從ram模塊中獲取的數(shù)據(jù)每位數(shù)據(jù)都要轉(zhuǎn)換成16bit的數(shù)據(jù),0轉(zhuǎn)換成背景色對(duì)應(yīng)的數(shù)據(jù),1轉(zhuǎn)換成頂層色對(duì)應(yīng)的數(shù)據(jù),程序?qū)崿F(xiàn)如下:
SCAN:begin //刷屏狀態(tài),從RAM中讀取數(shù)據(jù)刷屏 case(cnt_scan) 3'd0: if(cnt >= 11) begin //確定刷屏的區(qū)域坐標(biāo),這里為全屏 cnt <= 16'd0; cnt_scan <= cnt_scan + 1'b1; end else begin cnt <= cnt + 16'd1; data_reg <= reg_setxy[cnt]; num_delay <= 16'd50; state <= WRITE; state_back <= SCAN; end 3'd1: begin ram_clk_en<=HIGH;ram_addr<=y_cnt;cnt_scan<=cnt_scan+1'b1; end 3'd2: begin cnt_scan <= cnt_scan + 1'b1; end //延時(shí)一個(gè)時(shí)鐘 3'd3: begin ram_clk_en<=LOW;ram_data_r<=ram_data;cnt_scan<=cnt_scan+1'b1; end 3'd4: begin //每個(gè)像素點(diǎn)需要16bit的數(shù)據(jù),SPI每次傳8bit,兩次分別傳送高8位和低8位 if(x_cnt>=LCD_W) begin //當(dāng)一個(gè)數(shù)據(jù)(一行屏幕)寫(xiě)完后, x_cnt <= 8'd0; if(y_cnt>=LCD_H) begin y_cnt <= 8'd0; cnt_scan <= cnt_scan + 1'b1; end //如果是最后一行就跳出循環(huán) else begin y_cnt <= y_cnt + 1'b1; cnt_scan <= 3'd1; end //否則跳轉(zhuǎn)至RAM時(shí)鐘使能,循環(huán)刷屏 end else begin if(high_word) //根據(jù)相應(yīng)bit的狀態(tài)判定顯示頂層色或背景色,根據(jù)high_word的狀態(tài)判定寫(xiě)高8位或低8位 data_reg <= {1'b1,(ram_data_r[x_cnt]? color_t[15:8]:color_b[15:8])}; else begin data_reg <= {1'b1,(ram_data_r[x_cnt]? color_t[7:0]:color_b[7:0])}; x_cnt <= x_cnt + 1'b1; end // high_word <= ~high_word; //high_word的狀態(tài)翻轉(zhuǎn) num_delay <= 16'd50; //設(shè)定延時(shí)時(shí)間 state <= WRITE; //跳轉(zhuǎn)至WRITE狀態(tài) state_back <= SCAN; //執(zhí)行完WRITE及DELAY操作后返回SCAN狀態(tài) end end 3'd5: begin cnt_scan <= 1'b0; state <= MAIN; end default: state <= IDLE; endcase end
液晶屏驅(qū)動(dòng)模塊的數(shù)據(jù)來(lái)源于圖片數(shù)據(jù)的ram模塊,這些數(shù)據(jù)由圖片取模得到,使用圖片取模軟件,將圖片載入軟件,輸出數(shù)據(jù)類(lèi)型選擇C語(yǔ)言數(shù)組,根據(jù)液晶屏驅(qū)動(dòng)實(shí)際情況配置對(duì)應(yīng)的掃描模式,輸出灰度選擇單色,調(diào)整最大寬度和高度符合液晶屏要求,最后點(diǎn)擊保存生成需要的文件。
打開(kāi)生成的文件,數(shù)據(jù)格式如下,是C語(yǔ)言的格式
const unsigned char gImage_11[1990] = { 0X10,0X01,0X00,0X80,0X00,0X7C, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
使用編輯器的查找替換功能,將數(shù)據(jù)處理成下圖格式
132'h00000000000000000000000000000000, 132'h00000000000000000000000000000000, 132'h00000000000000000000000000000000, 132'h0000000000000000F800000000000000, 132'h0000000000000007FF00000000000000,
創(chuàng)建ram模塊,將圖片數(shù)據(jù)初始化到ram中,程序?qū)崿F(xiàn)圖下:
module LCD_RAM (input wire [7:0] Address, output reg [131:0] Q); always @ (*) case(Address) 8'd0 : Q = 132'h00000000000000000000000000000000; 8'd1 : Q = 132'h00000000000000000000000000000000; 8'd2 : Q = 132'h00000000000000000000000000000000; 8'd3 : Q = 132'h0000000000000000F800000000000000; 8'd4 : Q = 132'h0000000000000007FF00000000000000;
存儲(chǔ)圖片數(shù)據(jù)的ram本實(shí)驗(yàn)采用分布式ram搭建,前面波形信號(hào)發(fā)生器實(shí)驗(yàn)中講過(guò)ram IP核的例化及使用方法,有興趣的同學(xué)可以自己嘗試一下。
在頂層模塊中,將兩個(gè)模塊例化并連接,最終完成圖片顯示系統(tǒng)的總體設(shè)計(jì)。
將設(shè)計(jì)加載到FPGA中,觀察底板液晶屏顯示,小腳丫的Logo被顯示出來(lái)了,前面說(shuō)了1.8寸串行液晶屏支持不同的刷新方向,大家可以調(diào)整圖片顯示的方向
評(píng)論