|
module disp1602(clk,en,rs,rw,lcd_data,rst);
input clk,rst; //20MHz输入时钟
output en,rs,rw; //使能信号,数据/指令选择端(H/L),读写选择端
output [7:0] lcd_data;
reg lcd_clk; //1602时钟信号 500Hz
reg [14:0] c0; //将 clk(20MHz) 分频到 500Hz: 2ms
reg [3:0] state;//定义 状态
reg [7:0] lcd_data;
reg [127:0] data_first_buf,data_second_buf; //液晶显示的数据缓存
reg rs,lcd_en_sel;
reg [4:0] disp_count;
/******* 定义各状态名及编码 ******/
parameter Clear_Lcd = 4'b0000, //清屏和光标恢复
Set_Disp_Mode = 4'b0001, //设置显示模式:8位2行5x7点阵
Disp_On = 4'b0010, //显示器开、光标不显示、光标不允许闪烁
Auto_ad_address = 4'b0011,
Write_Addr = 4'b0100, //写入显示起始地址
Write_Data_First = 4'b0101, //写入第一行显示的数据
Write_Data_Second = 4'b0110, //写入第二行显示的数据
SJMP = 4'B0111; //原地跳转
parameter Data_First = " good good study ", //液晶显示的第一行的数据
Data_Second = " day day up "; //液晶显示的第二行的数据
/***********************************/
assign rw=1'b0; //选择 写 选通
assign en=lcd_en_sel?lcd_clk:1'b0;//通过lcd_en_sel来控制 en 的选通
/*********** 状态机变化部分 ********/
/* 1602液晶功能设置,数据写入 */
/**************************************/
always @(posedge lcd_clk or negedge rst)
begin
if(!rst)
begin
state<=Clear_Lcd;
lcd_data<=8'b0000_0000;
rs <=1'b0;
lcd_en_sel<=1;
disp_count<=4'b0000;
end
else
case(state)
Clear_Lcd:
begin
state<=Set_Disp_Mode;
lcd_data=8'b0000_0001; //清屏指令
end
Set_Disp_Mode:
begin
state<=Disp_On;
lcd_data=8'b0011_1000; //1602显示设置
end
Disp_On:
begin
state<=Auto_ad_address;
lcd_data=8'b0000_1110;//开 显示和光标
end
Auto_ad_address:
begin
state<=Write_Addr;
lcd_data=8'b0000_0110;//写1个字符,地址指针和光标都加 1
end
Write_Addr:
begin
state<=Write_Data_First;
lcd_data=8'b1000_0000;//设置数据指针的首地址
data_first_buf<=Data_First;//将第一行14个字符(112位)赋给 data_first_buf
// data_second_buf=Data_Second;//将第二行14个字符(112位)赋给 data_second_buf
end
Write_Data_First:
begin
if(disp_count==16)
begin
rs=0;
lcd_data=8'b1100_0000;
disp_count=0;
data_second_buf<=Data_Second;//将第二行14个字符(112位)赋给 data_second_buf
state<=Write_Data_Second;
end
else
begin
rs=1;
lcd_data=data_first_buf[127:120];
data_first_buf=(data_first_buf<<8);
disp_count=disp_count+1;
state<=Write_Data_First;
end
end
Write_Data_Second:
begin
if(disp_count<16)
begin
rs=1;
lcd_data=data_second_buf[127:120];
data_second_buf=(data_second_buf<<8);
disp_count=disp_count+1;
state<=Write_Data_Second;
end
else state=SJMP;
end
SJMP:
state<=SJMP;
default:state<=SJMP;
endcase
end
/**** clk分频为 500Hz ****/
always @(posedge clk)
if(c0<25000)
c0=c0+1;
else
begin
c0=0;lcd_clk=~lcd_clk;
end
endmodule |
|