本博文介绍如何向开发板上集成的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=50MHz
input RST; // system reset,high active
input CLR; // Clear display
output [3:0] LCD_DATA; // to lcd
output LCD_E; // Read/write Enable Pulse ,0:Disable ,1:Read/Write Operation enabled
output LCD_RS; // 0: Instruction register ,1: Data for read or write operations
output LCD_RW; // Read/Write control 0:write,1: read
output SF_CE0; // StrataFlash selected,0:enable,1:disable
reg 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;
//r
mem[2] = 4'h7;
mem[3] = 4'h2;
//e
mem[4] = 4'h6;
mem[5] = 4'h5;
//a
mem[6] = 4'h6;
mem[7] = 4'h1;
//t
mem[8] = 4'h7;
mem[9] = 4'h4;
//e
mem[10] = 4'h6;
mem[11] = 4'h5;
//d
mem[12] = 4'h6;
mem[13] = 4'h4;
//blank
mem[14] = 4'hf;
mem[15] = 4'he;
//b
mem[16] = 4'h6;
mem[17] = 4'h2;
//y
mem[18] = 4'h7;
mem[19] = 4'h9;
//l
char[0] = 4'h6;
char[1] = 4'hC;
//u
char[2] = 4'h7;
char[3] = 4'h5;
//l
char[4] = 4'h6;
char[5] = 4'hC;
//i
char[6] = 4'h6;
char[7] = 4'h9;
//p
char[8] = 4'h7;
char[9] = 4'h0;
//e
char[10] = 4'h6;
char[11] = 4'h5;
//n
char[12] = 4'h6;
char[13] = 4'hE;
//g
char[14] = 4'h6;
char[15] = 4'h7;
//c
clear[0] = 4'h6;
clear[1] = 4'h3;
//l
clear[2] = 4'h6;
clear[3] = 4'hC;
//e
clear[4] = 4'h6;
clear[5] = 4'h5;
//a
clear[6] = 4'h6;
clear[7] = 4'h1;
//r
clear[8] = 4'h7;
clear[9] = 4'h2;
//blank
clear[10] = 4'hf;
clear[11] = 4'he;
//l
clear[12] = 4'h6;
clear[13] = 4'hC;
//c
clear[14] = 4'h6;
clear[15] = 4'h3;
//d
clear[16] = 4'h6;
clear[17] = 4'h4;
end
parameter 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 only
assign 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)begin
if(RST)begin
state <= idle;
cnt_num <=25'd0;
end
else if(cnt_num == counter) begin
state <= next_state;
cnt_num <= 25'd0;
end
else cnt_num <= cnt_num + 1'b1;
end
/* initialize the lcd after power on */
always @ (posedge CLK or posedge RST)begin
if(RST)begin
next_state <= idle;
counter <= 25'd0;
end
else if(CLR) begin
next_state <= idle;
flag <= 1;
i <= 0;
end
else begin
case (state)
idle: begin
next_state <= state1;
counter <= 25'd750000; //wait for 15ms
LCD_E <= 0;
LCD_RS <= 0;
end
state1: begin
next_state <= state2;
LCD_E <= 1;
LCD_DATA <= 4'h3; // write 0x3;
counter <= 25'd12; //hold for 12 clocks
end
state2: begin
next_state <= state3;
LCD_E <= 0;
counter <= 25'd205000; //wait for 4.1ms
end
state3: begin
next_state <= state4;
LCD_E <= 1;
LCD_DATA <= 4'h3; // write 0x3;
counter <= 25'd12;//hold for 12 clocks
end
state4: begin
next_state <= state5;
LCD_E <= 0;
counter <= 25'd5000; //wait for 100us
end
state5: begin
next_state <= state6;
LCD_E <= 1;
LCD_DATA <= 4'h3; // write 0x3;
counter <= 25'd12; //hold for 12 clocks
end
state6: begin
next_state <= state7;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
state7: begin
next_state <= state8;
LCD_E <= 1;
LCD_DATA <= 4'h2; // write 0x2;
counter <= 25'd12; //hold for 12 clocks
end
state8: begin
next_state <= state9;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
/* LCD initial finished , config LCD 0X28 */
state9: begin
next_state <= state10;
LCD_E <= 1;
LCD_RS <= 0;
LCD_DATA <= 4'h2; // write 0x2;
counter <= 25'd12; //hold for 12 clocks
end
state10: begin
next_state <= state11;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state11: begin
next_state <= state12;
LCD_E <= 1;
LCD_DATA <= 4'h8; // write 0x8;
counter <= 25'd12; //hold for 12 clocks
end
state12: begin
next_state <= state13;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
/* Set entry mode 0x06 */
state13: begin
next_state <= state14;
LCD_E <= 1;
//LCD_RS <= 0;
LCD_DATA <= 4'h0; // write 0x0;
counter <= 25'd12; //hold for 12 clocks
end
state14: begin
next_state <= state15;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state15: begin
next_state <= state16;
LCD_E <= 1;
LCD_DATA <= 4'h6; // write 0x6;
counter <= 25'd12; //hold for 12 clocks
end
state16: begin
next_state <= state17;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
/* set display on, course off, blinking off 0x0c */
state17: begin
next_state <= state18;
LCD_E <= 1;
//LCD_RS <= 0;
LCD_DATA <= 4'h0; // write 0x0;
counter <= 25'd12; //hold for 12 clocks
end
state18: begin
next_state <= state19;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state19: begin
next_state <= state20;
LCD_E <= 1;
LCD_DATA <= 4'hc; // write 0xc;
counter <= 25'd12; //hold for 12 clocks
end
state20: begin
next_state <= state21;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
/* clear dispaly 0x01 */
state21: begin
next_state <= state22;
LCD_E <= 1;
//LCD_RS <= 0;
LCD_DATA <= 4'h0; // write 0x0;
counter <= 25'd12; //hold for 12 clocks
end
state22: begin
next_state <= state23;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state23: begin
next_state <= state24;
LCD_E <= 1;
LCD_DATA <= 4'h1; // write 0x1;
counter <= 25'd12; //hold for 12 clocks
end
state24: begin
next_state <= state25;
LCD_E <= 0;
counter <= 25'd82000; //wait for 1.64ms
end
/* set DD RAM address 0x80 */
state25: begin
next_state <= state26;
LCD_E <= 1;
//LCD_RS <= 0;
LCD_DATA <= 4'h8; // write 0x8;
counter <= 25'd12; //hold for 12 clocks
end
state26: begin
next_state <= state27;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state27: begin
next_state <= state28;
LCD_E <= 1;
LCD_DATA <= 4'h0; // write 0x0;
counter <= 25'd12; //hold for 12 clocks
end
state28: begin
if ( flag )begin
next_state <= state29;
//flag <= 0; //flag写到这就不能达到切换的效果
end
else begin
next_state <= state48;
end
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
/* send character "Created by" */
state29: begin
flag <= 0; //flag写到这则可以
if(i < longth) begin
next_state <= state30;
LCD_E <= 1;
LCD_RS <= 1;
LCD_DATA <= mem[i]; // write date to lcd
counter <= 25'd12; //hold for 12 clocks
end
else begin
next_state <= state34;
counter <= 25'd2000; //wait for 40us
end
end
state30: begin
next_state <= state31;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state31: begin
next_state <= state32;
LCD_E <= 1;
LCD_DATA <= mem[i+1]; // write date to lcd;
counter <= 25'd12; //hold for 12 clocks
end
state32: begin
next_state <= state33;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
state33: 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
end
state35: begin
next_state <= state36;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state36: begin
next_state <= state37;
LCD_E <= 1;
LCD_DATA <= 4'h8; // write 0x8;
counter <= 25'd12; //hold for 12 clocks
end
state37: begin
next_state <= state38;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
/* send "lulipeng" */
state38: begin
if(i < longth_1) begin
next_state <= state39;
LCD_E <= 1;
LCD_RS <= 1;
LCD_DATA <= char[i]; // write date to lcd;
counter <= 25'd12; //hold for 12 clocks
end
else begin
next_state <= state43;
counter <= 25'd2000; //wait for 40us
end
end
state39: begin
next_state <= state40;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state40: begin
next_state <= state41;
LCD_E <= 1;
LCD_DATA <= char[i+1]; // write date to lcd;
counter <= 25'd12; //hold for 12 clocks
end
state41: begin
next_state <= state42;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
state42: begin
next_state <= state38;
i <= i + 1;
counter <= 25'd1;
end
/* send "clear lcd" */
state48: begin
if(i < longth_2) begin
next_state <= state49;
LCD_E <= 1;
LCD_RS <= 1;
LCD_DATA <= clear[i]; // write date to lcd;
counter <= 25'd12; //hold for 12 clocks
end
else begin
next_state <= state34;
counter <= 25'd2000; //wait for 40us
end
end
state49: begin
next_state <= state50;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state50: begin
next_state <= state51;
LCD_E <= 1;
LCD_DATA <= clear[i+1]; // write date to lcd;
counter <= 25'd12; //hold for 12 clocks
end
state51: begin
next_state <= state52;
LCD_E <= 0;
counter <= 25'd2000; //wait for 40us
end
state52: 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
end
state44: begin
next_state <= state45;
LCD_E <= 0;
counter <= 25'd50; //wait for 1us
end
state45: begin
next_state <= state46;
LCD_E <= 1;
LCD_DATA <= 4'h0; // write 0x0;
counter <= 25'd12; //hold for 12 clocks
end
state46: begin
next_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
end
end
endmodule
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;
// Inputs
reg CLK;
reg RST;
reg CLR;
// Outputs
wire 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 Inputs
CLK = 0;
RST = 1;
CLR = 0;
// Wait 100 ns for global reset to finish
#100;
RST = 0;
// Add stimulus here
end
endmodule
四、开发板的基础资料。对板子上各个设备的用法都有介绍。
2638



被折叠的 条评论
为什么被折叠?



