DE2-70实现1602LCD的时钟显示,按键可调
时间:10-02
整理:3721RD
点击:
/*******************************************************************
/
/ 模块功能:LCD1602显示测试
/
/序号 指令 RS R/W D7 D6 D5 D4 D3 D2 D1 D0
/ 1 清显示 0 0 0 0 0 0 0 0 0 1/ 2 光标返回 0 0 0 0 0 0 0 0 1 *
/ 3 置输入模式 0 0 0 0 0 0 0 1 I/D S
/ 4 显示开/关控制 0 0 0 0 0 0 1 D C B
/ 5 光标或字符移位 0 0 0 0 0 1 S/C R/L * *
/ 6 置功能 0 0 0 0 1 DL N F * *
/ 7 置字符发生存贮器地址 0 0 0 1 字符发生存贮器地址
/ 8 置数据存贮器地址 0 0 1 显示数据存贮器地址
/ 9 读忙标志或地址 0 1 BF 计数器地址
/ 10 写数到CGRAM或DDRAM)1 0 要写的数据内容
/ 11 从CGRAM或DDRAM读数 1 1 读出的数据内容
/
/ 第一行初始地址 1000_0000
/ 第二行初始地址 1100_0000
/
/******************************************************************/
module LCD_1602
(
input CLK,
input RSTn,
input SW1,
input SW2,
input SW3,
input SW4,
output LCD_EN, //使能信号
output LCD_RW, //读、写选择信号
output LCD_RS, //数据、命令选择信号
output LCD_BLON, //背光灯亮灭
output LCD_ON, //电源开关
output [7:0]Data //总线
);
// RS R/W D7 D6 D5 D4 D3 D2 D1 D0
parameter IDLE = 10'b00_0000_0000; //空闲
parameter CLEAR = 10'b00_0000_0001; //清屏
parameter RETURNCURSOR = 10'b00_0000_0010; //光标返回 归home位
parameter SETMODE = 10'b00_0000_0110; //输入方式设置 读写数据后ram地址增/减1,画面动/不动
//光标移动方向 I/D: 1右移 0左移 S: 屏幕上文字移动 1有效 0无效
parameter SWITCHMODE = 10'b00_0000_1111; //显示状态设置 1DCB D:控制整体显示的开与关 1开 0关 C:控制光标的开与关 1开 0关
//B:控制光标是否闪烁 1闪 0不闪
parameter SHIFT = 10'b00_0001_1000; //光标画面滚动 第四位S/C 第三位R/L S/C:画面/光标平移一位;R/L:左右/平移一位
parameter SETFUNCTION = 10'b00_0011_1000; //设置功能 第五位DL:高电平时为4位总线,低电平时为8位总线 第四位N:低电平时为单行显示,//高电平时双行显示 第三位F:低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符
parameter SETCGRAM = 10'b00_0100_0000; //设置CGRAM 字符发生存贮器
parameter SETDDRAM1 = 10'b00_1000_0000; //设置DDRAM 数据存贮器 ===//第一行首地址
parameter SETDDRAM2 = 10'b00_1100_0000; //设置DDRAM 数据存贮器 ===//第二行首地址
parameter READFLAG = 10'b01_0000_0000; //设置度状态 正数第三位BF 高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙
parameter WRITERAM1 = 10'b10_0000_0001; //设置写RAM
parameter WRITERAM2 = 10'b10_0000_0010; //设置写RAM
parameter READRAM = 10'b11_0000_0000; //读RAM
assign LCD_ON = 1'b1;
assign LCD_BLON = 1'b1;
//======================产生1602时钟======================
parameter T0P2US = 19'd050000;
reg [22:0]Cnt;
reg CLK_500Hz;
always@(posedge CLK or negedge RSTn)
begin
if(!RSTn)
begin
Cnt <= 19'd0;
CLK_500Hz <= 1'b0;
end
else if(Cnt == T0P2US)
begin
Cnt <= 19'd0;
CLK_500Hz <= ~CLK_500Hz;
end
else
Cnt <= Cnt+1'b1;
end
assign LCD_EN = CLK_500Hz; //上升沿之后为高电平 使能有效 数据已稳定
//============================按键控制=========================
reg[3:0]key_rst;
always@(posedge CLK or negedge RSTn)
begin
if(!RSTn) key_rst <= 4'b1111;
else key_rst <= {SW4,SW3,SW2,SW1};
end
reg[3:0]key_rst_r;
always@(posedge CLK or negedge RSTn)
begin
if(!RSTn) key_rst_r <= 4'b1111;
else key_rst_r <= key_rst;
end
wire key_an; //抖动标志位
assign key_an = key_rst_r&(~key_rst); //边沿检测
reg [17:0] cnt_k;
always @ (posedge CLK or negedge RSTn)
begin
if(!RSTn) cnt_k <= 18'd0;
else if(key_an) cnt_k <= 18'd0; //一旦有抖动,计数器马上清零
else cnt_k <= cnt_k +1'b1;
end
reg [3:0] key;
always @ (posedge CLK or negedge RSTn)
begin
if(!RSTn) key <= 4'b1111;
else if(cnt_k == 18'd250000) //等待5ms,再记录按键状态
key <= {SW4,SW3,SW2,SW1};
end
reg [3:0]key_r;
always @ (posedge CLK or negedge RSTn)
begin
if(!RSTn) key_r <= 4'b1111;
else key_r <= key; //送到二级锁存器
end
wire [3:0] key_state = key_r& (~key); //边沿检测算法
//--------------------------时钟暂停----------------------------
reg flag;
always @ (posedge CLK or negedge RSTn) begin
if(!RSTn) flag <= 1'b1;
else if(key_state == 3'b0001) // 如果键4按下,那么时钟暂停
flag <= ~flag;
end
//======================产生时分秒数值=====================
parameter T1S = 26'd50000000;
reg[25:0]Time_Cnt;
reg[5:0]Second;
reg[5:0]Minute;
reg[4:0]Hour;
reg[3:0]Second_H;
reg[3:0]Minute_H;
reg[3:0]Hour_H;
reg[3:0]Second_L;
reg[3:0]Minute_L;
reg[3:0]Hour_L;
always@(posedge CLK or negedge RSTn)
begin
if(!RSTn)
begin
Time_Cnt <= 26'd0;
Second <= 6'd0;
Minute <= 6'd0;
Hour <=5'd0;
end
else if(flag == 1'b1) //================没有调整按键按下时================
begin
if(Time_Cnt == 26'd50000000)
begin
Time_Cnt <= 26'd0;
if(Second == 6'd59)
begin
Second <= 6'd0;
if(Minute == 6'd59)
begin
Minute <= 6'd0;
if(Hour == 5'd23)
Hour <= 5'd0;
else
Hour <= Hour + 1'b1;
end
else
Minute <= Minute + 1'b1;
end
else
Second <= Second + 1'b1;
end
else Time_Cnt <= Time_Cnt + 1'b1;
end
else //================有调整按键按下时================
begin
if(key_state == 4'b0010)
begin
if(Second == 6'd59) Second <= 6'd0;
else Second <= Second + 1'b1;
end
if(key_state == 4'b0100)
begin
if(Minute == 6'd59) Minute <= 6'd0;
else Minute <= Minute + 1'b1;
end
if(key_state == 4'b1000)
begin
if(Hour == 5'd23) Hour <= 5'd0;
else Hour <= Hour + 1'b1;
end
end
end
//============================================================
always@(posedge CLK_500Hz or negedge RSTn)
begin
if(!RSTn)
begin
Second_H <= 4'd0;
Second_L <= 4'd0;
Minute_H <= 4'd0;
Minute_L <= 4'd0;
Hour_H <= 4'd0;
Hour_L <= 4'd0;
end
else
begin
Second_H <= Second/10;
Second_L <= Second%10;
Minute_H <= Minute/10;
Minute_L <= Minute%10;
Hour_H <= Hour/10;
Hour_L <= Hour%10;
end
end
//========================LCD初始化以及数据显示控制=========================
reg [9:0]STATE;
reg LCD_RW_Reg;
reg LCD_RS_Reg;
reg [7:0]Data_Reg;
reg [3:0]Cnt_T;
always@(posedge CLK_500Hz or negedge RSTn)
begin
if(!RSTn)
begin
STATE <= IDLE;
Data_Reg <= 8'd0;
LCD_RS_Reg<= 1'b0;
LCD_RW_Reg<= 1'b0;
Cnt_T <= 4'd0;
end
else
begin
case(STATE)
IDLE:
begin STATE <= CLEAR; Data_Reg <= 8'bzzzz_zzzz; end
CLEAR:
begin STATE <= SETFUNCTION; LCD_RS_Reg <= 1'b0; LCD_RW_Reg <= 1'b0; Data_Reg <= 8'h01; end
SETFUNCTION:
begin STATE <= SWITCHMODE; LCD_RS_Reg <= 1'b0; LCD_RW_Reg <= 1'b0; Data_Reg <= 8'h38; end
SWITCHMODE:
begin STATE <= SETMODE; LCD_RS_Reg <= 1'b0; LCD_RW_Reg <= 1'b0; Data_Reg <= 8'h0c; end
SETMODE:
begin STATE <= SETDDRAM1; LCD_RS_Reg <= 1'b0; LCD_RW_Reg <= 1'b0; Data_Reg <= 8'h06; end
SETDDRAM1:
begin STATE <= WRITERAM1; LCD_RS_Reg <= 1'b0; LCD_RW_Reg <= 1'b0; Data_Reg <= 8'b1000_0000; end
WRITERAM1:
begin
case(Cnt_T)
4'd0: //=========小时高=========
begin
LCD_RS_Reg <= 1'b1;
LCD_RW_Reg <= 1'b0;
Data_Reg <= Hour_H + 8'b0011_0000;
STATE <= WRITERAM1;
Cnt_T <= Cnt_T + 1'b1;
end
4'd1: //=========小时低========
begin
LCD_RS_Reg <= 1'b1;
LCD_RW_Reg <= 1'b0;
Data_Reg <= Hour_L + 8'b0011_0000;
STATE <= WRITERAM1;
Cnt_T <= Cnt_T + 1'b1;
end
4'd2: //========冒号========
begin
LCD_RS_Reg <= 1'b1;
LCD_RW_Reg <= 1'b0;
Data_Reg <= 8'b0011_1010;
STATE <= WRITERAM1;
Cnt_T <= Cnt_T + 1'b1;
end
4'd3: //=========分钟高========
begin
LCD_RS_Reg <= 1'b1;
LCD_RW_Reg <= 1'b0;
Data_Reg <= Minute_H + 8'b0011_0000;
STATE <= WRITERAM1;
Cnt_T <= Cnt_T + 1'b1;
end
4'd4: //=======分钟低========
begin
LCD_RS_Reg <= 1'b1;
LCD_RW_Reg <= 1'b0;
Data_Reg <= Minute_L + 8'b0011_0000;
STATE <= WRITERAM1;
Cnt_T <= Cnt_T + 1'b1;
end
4'd5: //=========冒号=======
begin
LCD_RS_Reg <= 1'b1;
LCD_RW_Reg <= 1'b0;
Data_Reg <= 8'b0011_1010;
STATE <= WRITERAM1;
Cnt_T <= Cnt_T + 1'b1;
end
4'd6: //=========秒高========
begin
LCD_RS_Reg <= 1'b1;
LCD_RW_Reg <= 1'b0;
Data_Reg <= Second_H + 8'b0011_0000;
STATE <= WRITERAM1;
Cnt_T <= Cnt_T + 1'b1;
end
4'd7: //===========秒低========
&nbs