本博文介紹如何向開發板上整合的LCD顯示器寫資料以顯示。
一、實驗效果
1、LCD顯示器可以顯示
Created by 和 clear lcd lulipeng lulipeng
2、通過滑動開關SW0(L13)和SW1(L14)可以在兩種顯示之間任意切換。
二、設計過程
1、LCD的控制器內部有DD RAM(顯示字元儲存空間),使用者就是向其中寫入要顯示的字元編碼的(ASCII碼)。
CG ROM內部已儲存了字元集,每個字元的索引也就是其ASCII碼。比如u的索引就是0111 0101。
2、在寫之前就要把資料都存放到指定的位置。也就是要使用者指定儲存地址儲存字元以便將來寫。
3、LCD加電後其初始化是有一定的過程的。
初始化的第一步驟是建立FPGA與LCD的4位的資料介面,具體如下:
A:等待15ms或更長,儘管FPGA完成配置後顯示屏一般處於準備就緒狀態。在50MHz時,15ms時間等於750000刻度。
B:寫SF_D<11:8>=0x3,LCD_E保持高電平12刻度。
C:等待4.1ms或更長,即在50MHz時,205000刻度。
D:寫SF_D<11:8>=0x3,LCD_E保持高電平12刻度。
E:等待100us或更長,即在50MHz時,5000刻度。
F:寫SF_D<11:8>=0x3,LCD_E保持高電平12刻度。
G:等待40us或更長,即在50MHz時,2000刻度。
H:寫SF_D<11:8>=0x2,LCD_E保持高電平12刻度。
I:等待40us或更長,即在50MHz時,2000刻度。
4、初始化之後要配置顯示屏
上電初始化完成後,4位的資料介面就建立了。下一步就是配置顯示屏了:
A:發一個功能設定命令,0x28,配置顯示屏。
B:發一個進入模式命令,0X06,設定顯示屏自動增地址指標。
C:發一個顯示開/斷命令,0x0c,開顯示屏並失能指標和游標。
D:最後,發清屏命令,此後等待至少1.64ms(82000刻度)。
5、此外,還要設定字元是否滾動顯示,還是靜止。大家可以參考使用者指導手冊自行決定。
三、代碼集錦
1、verilog源碼
module lcd_display(CLK, RST, LCD_E, LCD_RS, LCD_RW, SF_CE0, LCD_DATA, CLR );input CLK; // System clk=50MHzinput RST; // system reset,high activeinput CLR; // Clear displayoutput [3:0] LCD_DATA; // to lcdoutput LCD_E; // Read/write Enable Pulse ,0:Disable ,1:Read/Write Operation enabledoutput LCD_RS; // 0: Instruction register ,1: Data for read or write operationsoutput LCD_RW; // Read/Write control 0:write,1: readoutput SF_CE0; // StrataFlash selected,0:enable,1:disablereg LCD_E;reg LCD_RS;reg [3:0] LCD_DATA;reg [24:0] cnt_num;reg [24:0] counter;reg [5:0] state;reg [5:0] next_state;reg flag;integer i;parameter longth_1 = 15;parameter longth = 19;parameter longth_2 = 17;reg [3:0] mem [longth:0];reg [3:0] char [longth_1:0];reg [3:0] clear [longth_2:0];initial begin i = 0; flag = 0; /*date to be writed to lcd Created by lulipeng*/// C mem[0] = 4'h4;mem[1] = 4'h3;//rmem[2] = 4'h7; mem[3] = 4'h2;//emem[4] = 4'h6;mem[5] = 4'h5;//amem[6] = 4'h6;mem[7] = 4'h1;//tmem[8] = 4'h7;mem[9] = 4'h4;//emem[10] = 4'h6;mem[11] = 4'h5;//dmem[12] = 4'h6;mem[13] = 4'h4;//blankmem[14] = 4'hf;mem[15] = 4'he;//bmem[16] = 4'h6;mem[17] = 4'h2;//ymem[18] = 4'h7;mem[19] = 4'h9;//lchar[0] = 4'h6;char[1] = 4'hC;//uchar[2] = 4'h7;char[3] = 4'h5;//lchar[4] = 4'h6;char[5] = 4'hC;//ichar[6] = 4'h6;char[7] = 4'h9;//pchar[8] = 4'h7;char[9] = 4'h0;//echar[10] = 4'h6;char[11] = 4'h5;//nchar[12] = 4'h6;char[13] = 4'hE;//gchar[14] = 4'h6;char[15] = 4'h7;//cclear[0] = 4'h6;clear[1] = 4'h3;//lclear[2] = 4'h6;clear[3] = 4'hC;//eclear[4] = 4'h6;clear[5] = 4'h5;//aclear[6] = 4'h6;clear[7] = 4'h1;//rclear[8] = 4'h7;clear[9] = 4'h2;//blankclear[10] = 4'hf;clear[11] = 4'he;//lclear[12] = 4'h6;clear[13] = 4'hC;//cclear[14] = 4'h6;clear[15] = 4'h3;//dclear[16] = 4'h6;clear[17] = 4'h4;endparameter idle = 6'b000000, state1 = 6'd1, state2 = 6'd2, state3 = 6'd3, state4 = 6'd4, state5 = 6'd5, state6 = 6'd6, state7 = 6'd7, state8 = 6'd8, state9 = 6'd9, state10 = 6'd10, state11 = 6'd11, state12 = 6'd12, state13 = 6'd13, state14 = 6'd14, state15 = 6'd15, state16 = 6'd16, state17 = 6'd17, state18 = 6'd18, state19 = 6'd19, state20 = 6'd20, state21 = 6'd21, state22 = 6'd22, state23 = 6'd23, state24 = 6'd24, state25 = 6'd25, state26 = 6'd26, state27 = 6'd27, state28 = 6'd28, state29 = 6'd29, state30 = 6'd30, state31 = 6'd31, state32 = 6'd32, state33 = 6'd33, state34 = 6'd34, state35 = 6'd35, state36 = 6'd36, state37 = 6'd37, state38 = 6'd38, state39 = 6'd39, state40 = 6'd40, state41 = 6'd41, state42 = 6'd42, state43 = 6'd43, state44 = 6'd44, state45 = 6'd45, state46 = 6'd46, state47 = 6'd47, state48 = 6'd48, state49 = 6'd49, state50 = 6'd50, state51 = 6'd51, state52 = 6'd52; assign LCD_RW = 0; // Write data to lcd onlyassign SF_CE0 = 1; //Disable the StrataFlash/* time delay, when cnt_num equals to counter, the state changes to the next state specified by next_state */always @ (posedge CLK or posedge RST)beginif(RST)beginstate <= idle;cnt_num <=25'd0;endelse if(cnt_num == counter) begin state <= next_state; cnt_num <= 25'd0;endelse cnt_num <= cnt_num + 1'b1;end/* initialize the lcd after power on */always @ (posedge CLK or posedge RST)beginif(RST)beginnext_state <= idle;counter <= 25'd0;endelse if(CLR) beginnext_state <= idle;flag <= 1;i <= 0;endelse begincase (state)idle: begin next_state <= state1; counter <= 25'd750000; //wait for 15ms LCD_E <= 0; LCD_RS <= 0; endstate1: beginnext_state <= state2;LCD_E <= 1;LCD_DATA <= 4'h3; // write 0x3;counter <= 25'd12; //hold for 12 clocks endstate2: beginnext_state <= state3;LCD_E <= 0;counter <= 25'd205000; //wait for 4.1ms endstate3: beginnext_state <= state4;LCD_E <= 1;LCD_DATA <= 4'h3; // write 0x3;counter <= 25'd12;//hold for 12 clocks end state4: beginnext_state <= state5;LCD_E <= 0;counter <= 25'd5000; //wait for 100us end state5: beginnext_state <= state6;LCD_E <= 1;LCD_DATA <= 4'h3; // write 0x3;counter <= 25'd12; //hold for 12 clocks endstate6: beginnext_state <= state7;LCD_E <= 0;counter <= 25'd2000; //wait for 40us endstate7: beginnext_state <= state8;LCD_E <= 1;LCD_DATA <= 4'h2; // write 0x2;counter <= 25'd12; //hold for 12 clocks endstate8: beginnext_state <= state9;LCD_E <= 0;counter <= 25'd2000; //wait for 40us end/* LCD initial finished , config LCD 0X28 */ state9: beginnext_state <= state10;LCD_E <= 1;LCD_RS <= 0;LCD_DATA <= 4'h2; // write 0x2;counter <= 25'd12; //hold for 12 clocks endstate10: beginnext_state <= state11;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state11: beginnext_state <= state12;LCD_E <= 1;LCD_DATA <= 4'h8; // write 0x8;counter <= 25'd12; //hold for 12 clocks endstate12: beginnext_state <= state13;LCD_E <= 0;counter <= 25'd2000; //wait for 40us end /* Set entry mode 0x06 */ state13: beginnext_state <= state14;LCD_E <= 1;//LCD_RS <= 0;LCD_DATA <= 4'h0; // write 0x0;counter <= 25'd12; //hold for 12 clocks endstate14: beginnext_state <= state15;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state15: beginnext_state <= state16;LCD_E <= 1;LCD_DATA <= 4'h6; // write 0x6;counter <= 25'd12; //hold for 12 clocks endstate16: beginnext_state <= state17;LCD_E <= 0;counter <= 25'd2000; //wait for 40us end/* set display on, course off, blinking off 0x0c */ state17: beginnext_state <= state18;LCD_E <= 1;//LCD_RS <= 0;LCD_DATA <= 4'h0; // write 0x0;counter <= 25'd12; //hold for 12 clocks endstate18: beginnext_state <= state19;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state19: beginnext_state <= state20;LCD_E <= 1;LCD_DATA <= 4'hc; // write 0xc;counter <= 25'd12; //hold for 12 clocks endstate20: beginnext_state <= state21;LCD_E <= 0;counter <= 25'd2000; //wait for 40us end/* clear dispaly 0x01 */ state21: beginnext_state <= state22;LCD_E <= 1;//LCD_RS <= 0;LCD_DATA <= 4'h0; // write 0x0;counter <= 25'd12; //hold for 12 clocks endstate22: beginnext_state <= state23;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state23: beginnext_state <= state24;LCD_E <= 1;LCD_DATA <= 4'h1; // write 0x1;counter <= 25'd12; //hold for 12 clocks endstate24: beginnext_state <= state25;LCD_E <= 0;counter <= 25'd82000; //wait for 1.64ms end/* set DD RAM address 0x80 */ state25: beginnext_state <= state26;LCD_E <= 1;//LCD_RS <= 0;LCD_DATA <= 4'h8; // write 0x8;counter <= 25'd12; //hold for 12 clocks endstate26: beginnext_state <= state27;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state27: beginnext_state <= state28;LCD_E <= 1;LCD_DATA <= 4'h0; // write 0x0;counter <= 25'd12; //hold for 12 clocks endstate28: beginif ( flag )begin next_state <= state29;//flag <= 0; //flag寫到這就不能達到切換的效果endelse beginnext_state <= state48;endLCD_E <= 0;counter <= 25'd2000; //wait for 40us end/* send character "Created by" */ state29: beginflag <= 0; //flag寫到這則可以 if(i < longth) beginnext_state <= state30;LCD_E <= 1;LCD_RS <= 1;LCD_DATA <= mem[i]; // write date to lcdcounter <= 25'd12; //hold for 12 clocksendelse begin next_state <= state34; counter <= 25'd2000; //wait for 40usend endstate30: beginnext_state <= state31;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state31: beginnext_state <= state32;LCD_E <= 1;LCD_DATA <= mem[i+1]; // write date to lcd;counter <= 25'd12; //hold for 12 clocks endstate32: beginnext_state <= state33;LCD_E <= 0;counter <= 25'd2000; //wait for 40us endstate33: begin next_state <= state29; i <= i + 1; counter <= 25'd1; end/* set DDRAM address 0xd8 */state34: begin i <= 0;next_state <= state35;LCD_E <= 1;LCD_RS <= 0;LCD_DATA <= 4'hc; // write 0xc;counter <= 25'd12; //hold for 12 clocks endstate35: beginnext_state <= state36;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state36: beginnext_state <= state37;LCD_E <= 1;LCD_DATA <= 4'h8; // write 0x8;counter <= 25'd12; //hold for 12 clocks endstate37: beginnext_state <= state38;LCD_E <= 0;counter <= 25'd2000; //wait for 40us end/* send "lulipeng" */ state38: begin if(i < longth_1) beginnext_state <= state39;LCD_E <= 1;LCD_RS <= 1;LCD_DATA <= char[i]; // write date to lcd;counter <= 25'd12; //hold for 12 clocksendelse begin next_state <= state43; counter <= 25'd2000; //wait for 40usend endstate39: beginnext_state <= state40;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state40: beginnext_state <= state41;LCD_E <= 1;LCD_DATA <= char[i+1]; // write date to lcd;counter <= 25'd12; //hold for 12 clocks endstate41: beginnext_state <= state42;LCD_E <= 0;counter <= 25'd2000; //wait for 40us endstate42: begin next_state <= state38; i <= i + 1; counter <= 25'd1; end/* send "clear lcd" */ state48: begin if(i < longth_2) beginnext_state <= state49;LCD_E <= 1;LCD_RS <= 1;LCD_DATA <= clear[i]; // write date to lcd;counter <= 25'd12; //hold for 12 clocksendelse begin next_state <= state34; counter <= 25'd2000; //wait for 40usend endstate49: beginnext_state <= state50;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state50: beginnext_state <= state51;LCD_E <= 1;LCD_DATA <= clear[i+1]; // write date to lcd;counter <= 25'd12; //hold for 12 clocks endstate51: beginnext_state <= state52;LCD_E <= 0;counter <= 25'd2000; //wait for 40us endstate52: begin next_state <= state48; i <= i + 1; counter <= 25'd1; end/* set course and display shift ,0x10 */ state43: begin i <= 0;next_state <= state44;LCD_E <= 1;LCD_RS <= 0;LCD_DATA <= 4'h1; // write 0x1;counter <= 25'd12; //hold for 12 clocks endstate44: beginnext_state <= state45;LCD_E <= 0;counter <= 25'd50; //wait for 1us end state45: beginnext_state <= state46;LCD_E <= 1;LCD_DATA <= 4'h0; // write 0x0;counter <= 25'd12; //hold for 12 clocks endstate46: beginnext_state <= state47;LCD_E <= 0;counter <= 25'd2000; //wait for 40us end/* delay for a while */ state47: begin next_state <= state43; counter <= 25'd25000000; end default: next_state <= idle; endcase endendendmodule
2、ucf檔案
NET "CLK" LOC = "C9" | IOSTANDARD = LVTTL ; NET "RST" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP | DRIVE = 2 ;NET "CLR" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP | DRIVE = 2 ;NET "SF_CE0" LOC = "D16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; NET "LCD_E" LOC = "M18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ;NET "LCD_RS" LOC = "L18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ;NET "LCD_RW" LOC = "L17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ;NET "LCD_DATA[0]" LOC = "R15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ;NET "LCD_DATA[1]" LOC = "R16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ;NET "LCD_DATA[2]" LOC = "P17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ;NET "LCD_DATA[3]" LOC = "M15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ;
3、激勵檔案
module test;// Inputsreg CLK;reg RST;reg CLR;// Outputswire LCD_E;wire LCD_RS;wire LCD_RW;wire SF_CE0;wire [3:0] LCD_DATA;// Instantiate the Unit Under Test (UUT)lcd_display uut (.CLK(CLK), .RST(RST), .LCD_E(LCD_E), .LCD_RS(LCD_RS), .LCD_RW(LCD_RW), .SF_CE0(SF_CE0), .LCD_DATA(LCD_DATA), .CLR(CLR)); always #5 CLK = ~CLK;initial begin// Initialize InputsCLK = 0;RST = 1;CLR = 0;// Wait 100 ns for global reset to finish#100; RST = 0; // Add stimulus hereend endmodule
四、開發板的基礎資料。對板子上各個裝置的用法都有介紹。
Spartan-3E_Starter_Kit_Board_User_Guide