微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > DE2-70实现1602LCD的时钟显示,按键可调

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

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top