|
module Lcd12864(//针对型号为RT12864-S
input Sys_Clk,
input Rst,
output reg LCD_RS,
output LCD_RW,
output LCD_E,
output reg [7:0]LCD_Data
// output PSB//串并控制端口,H为并行,L为串行,直接接5v
// output LCD_Rst,//液晶的复位端口,低电平有效
//由于端口不够,暂时让其悬空
);
reg LCD_Clk;
reg[7:0] state;//状态机寄存器
reg [23:0] cnt;//计数器
reg flag;//显示完成标志
reg[5:0]char_cnt;
reg[7:0]data_disp;//一个字节是八位,一个英文字符是一个字节,中文是俩个字节
parameter T500KHZ=24'd49999;
// parameter T500KHZ=24'd24_999_999;//测试低频现象
// parameter T500KHZ=24'd24_9;//仿真专用
//首先先对系统频率分频,液晶所需频率不用这么高,但是是多少呢?由datasheet可得出该液晶的最大频率是590kHZ
//典型值为530KH,为了好算取个值500KHZ,50M/500KHZ=10HZ,计数5M/2变化一次方向
always@(posedge Sys_Clk or negedge Rst)
begin
if(!Rst)
begin
cnt<=24'd0;
LCD_Clk<=1'b0;
end
else if(cnt==T500KHZ)
begin
cnt<=24'd0;
LCD_Clk<=~LCD_Clk;
end
else
cnt<=cnt+1'b1;
end
//state machine description,8个状态 只要用把位二进制就可以全部表示
parameter IDLE=8'b00_000_000;//初始状态
parameter SETFUNCTION=8'b00_000_001;//功能设置,8-bit+基本指令集0x30
// parameter SETFUNCTION2=8'b00_000_010;//同上
parameter SWITCHMODE=8'b00_000_100;//设置显示开和光标闪烁关闭
parameter CLEAR=8'b00_001_000;//清屏操作
parameter SETMODE=8'b00_010_000;//点设置
parameter SETDDRAM=8'b00_100_000;//起始行设置
parameter WRITERAM=8'b01_000_000;//写设置
parameter STOP=8'b10_000_000;//LCD操作停止,释放其控制
initial
begin
cnt=24'd0;
state=IDLE;
flag=1'b1;
LCD_Clk=1'b10;
char_cnt=6'd0;
data_disp=8'd32;
end
//设置好RS、RW、E
always@(posedge LCD_Clk or negedge Rst)
begin
if(!Rst)
LCD_RS<=1'b0;
else if(state==WRITERAM)
LCD_RS<=1'b1;
else
LCD_RS<=1'b0;
end
//如果定义了LCD_Rst俩个端口的话,可做如下设置
//assign LCD_Rst=1'b1;
//assign PSB=1'b1;
assign LCD_RW=1'b0;//只是写操作,不需要读操作
assign LCD_E=(flag==1)?LCD_Clk:1'b0;//使能信号与液晶时钟同步
//descible the state machine
always@(posedge LCD_Clk or negedge Rst)
begin
if(!Rst)
begin
state<=IDLE;
LCD_Data<=8'bzz_zzz_zzz;
end
else
begin
case(state)
IDLE:
begin
state<=SETFUNCTION;
LCD_Data<=8'h30;
end
SETFUNCTION:
begin
state<=SWITCHMODE;
// state<=SETFUNCTION2;
LCD_Data<=8'h30;
end
// SETFUNCTION2:
// begin
// state<=SWITCHMODE;
// LCD_Data<=8'h30;
// end
SWITCHMODE:
begin
state<=CLEAR;
LCD_Data<=8'h0c;//显示设置,全显示开,光标和闪烁关
end
CLEAR:
begin
state<=SETMODE;
LCD_Data<=8'h01;//清屏、
end
SETMODE:
begin
state<=SETDDRAM;
LCD_Data<=8'h06;//点设置,光标右移,地址加一,整体不动
end
SETDDRAM://设置起始位置
begin
state<=WRITERAM;
if(char_cnt==6'd0)
LCD_Data<=8'h80;//line1
else
LCD_Data<=9'h90;//line2
end
WRITERAM:
begin
if(char_cnt<=6'd11)
begin
char_cnt<=char_cnt+1'b1;
LCD_Data<=data_disp;
if(char_cnt==6'd11)
state<=SETDDRAM;//第一行写完后从新返回设置地址
else
state<=WRITERAM;
end
else if(char_cnt>=6'd12&&char_cnt<=6'd25)
begin
if(char_cnt==6'd25)
begin
state<=STOP;
char_cnt=6'd0;
flag<=1'b0;
end
else
begin
LCD_Data<=data_disp;//不管到没到第25个都要继续写数
state<=WRITERAM;
char_cnt<=char_cnt+1'b1;
end
end
end
STOP: state<=STOP;
default: state<=IDLE;
endcase
end
end
always@(char_cnt)
begin
case(char_cnt)
6'd0:data_disp="G";
6'd1:data_disp="U";
6'd2:data_disp="X";
6'd3:data_disp="I";
6'd4:data_disp="A";
6'd5:data_disp="N";
6'd6:data_disp="Y";
6'd7:data_disp="I";
6'd8:data_disp="L";
6'd9:data_disp="C";
6'd10:data_disp="D";
6'd11:data_disp="!";
6'd12:data_disp="H";
6'd13:data_disp="E";
6'd14:data_disp="L";
6'd15:data_disp="L";
6'd16:data_disp="O";
6'd17:data_disp="E";
6'd18:data_disp="V";
6'd19:data_disp="E";
6'd20:data_disp="R";
6'd21:data_disp="Y";
6'd22:data_disp="O";
6'd23:data_disp="N";
6'd24:data_disp="E";
// default:data_disp=8'h32;
endcase
end
endmodule |
|