基于FPGA的lcd1602闹钟

基于FPGA的lcd1602闹钟

一、关于lcd的设置,以及命令格式见博主的另一篇转载的博客:https://blog.csdn.net/chengfengwenalan/article/details/80070058

二、设计思路

本例程主要是利用lcd实现了闹钟功能

第一行显示Alarm:00-00       

第二行显示Clock:00-00-00

按下key1按键是进入adjust模式,按下key2是加,按下key3是减,这3个按键都支持连按和快速单击。系统框图如下:

基于FPGA的lcd1602闹钟_第1张图片

图1.系统框图

    由系统框图可以看出,本项目主要由debounce,alarm,lcd,led模块组成。

其中

debounce是按键消抖模块,他支持连续按,快速单击

alarm模块主要产生sec,min,hour,alarm_min,alarm_hour的信号,提供给lcd模块显示

lcd模块则是lcd1602的驱动,主要负责lcd1602的显示

led模块则是闹钟时,led闪烁

三、核心代码解说

lcd的驱动主要是用状态机实现的

//status_c
always@(posedge lcd_clk or negedge rst_n)begin
    if(!rst_n)begin
        status_c <= IDLE;
    end
    else begin
        status_c <= status_n;
    end
end

//status_n
always@(*)begin
    case(status_c)
        //----------------初始化------------------
        IDLE:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'h38;
            if(flag)                   //上电后等待15ms,电平稳定了再下一步
                status_n    <=      INIT; 
            else
                status_n    <=      status_c;
        end
        INIT:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'h38;
            status_n    <=      S0; 
        end
        S0:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'h08;
            status_n    <=      S1; 
        end
        S1:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'h01;
            status_n    <=      S2; 
        end
        S2:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'h06;
            status_n    <=      S3; 
        end
        S3:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'h0c;
            status_n    <=      ROW1; 
        end
        //-----------第一行DDRAM首地址------------
        ROW1:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'h80;
            status_n    <=      ONE0; 
        end
        //------------第一行数据-----------------
        ONE0:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_0;
            status_n    <=      ONE1; 
        end
        ONE1:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_1;
            status_n    <=      ONE2; 
        end
        ONE2:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_2;
            status_n    <=      ONE3; 
        end
        ONE3:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_3;
            status_n    <=      ONE4; 
        end
        ONE4:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_4;
            status_n    <=      ONE5; 
        end
        ONE5:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_5;
            status_n    <=      ONE6; 
        end
        ONE6:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_6;
            status_n    <=      ONE7; 
        end
        ONE7:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_7;
            status_n    <=      ONE8; 
        end
        ONE8:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_8;
            status_n    <=      ONE9; 
        end
        ONE9:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_9;
            status_n    <=      ONE10; 
        end
        ONE10:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_10;
            status_n    <=      ONE11; 
        end
        ONE11:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_11;
            status_n    <=      ONE12; 
        end
        ONE12:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_12;
            status_n    <=      ONE13; 
        end
        ONE13:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_13;
            status_n    <=      ONE14; 
        end
        ONE14:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_14;
            status_n    <=      ONE15; 
        end
        ONE15:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      one_15;
            status_n    <=      ROW2; 
        end
        //---------------第二行首地址---------------
        ROW2:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'hc0;
            status_n    <=      TWO0; 
        end
        //-------------第二行数据-------------------
        TWO0:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_0;
            status_n    <=      TWO1; 
        end
        TWO1:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_1;
            status_n    <=      TWO2; 
        end
        TWO2:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_2;
            status_n    <=      TWO3; 
        end
        TWO3:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_3;
            status_n    <=      TWO4; 
        end
        TWO4:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_4;
            status_n    <=      TWO5; 
        end
        TWO5:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_5;
            status_n    <=      TWO6; 
        end
        TWO6:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_6;
            status_n    <=      TWO7; 
        end
        TWO7:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_7;
            status_n    <=      TWO8; 
        end
        TWO8:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_8;
            status_n    <=      TWO9; 
        end
        TWO9:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_9;
            status_n    <=      TWO10; 
        end
        TWO10:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_10;
            status_n    <=      TWO11; 
        end
        TWO11:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_11;
            status_n    <=      TWO12; 
        end
        TWO12:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_12;
            status_n    <=      TWO13; 
        end
        TWO13:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_13;
            status_n    <=      TWO14; 
        end
        TWO14:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_14;
            status_n    <=      TWO15; 
        end
        TWO15:begin
            rs          <=      1'b1;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      two_15;
            status_n    <=      ROW1; 
        end
        default:begin
            rs          <=      1'b0;  //rs高是数据寄存器,rs低是指令寄存器
            data        <=      8'h00;
            status_n    <=      IDLE; 
        end
    endcase
end

由上面的代码可以看出,在空闲状态时,等待15ms,则进入INIT状态,等待15ms是为了使电平稳定,紧接着则是发送一些配置的指令,配置指令分别为8'h38,8'h08,8'h01,8'h06,8'h0c,这些指令是什么意思见前面的链接。接着发送第一行的DDRAM的首地址,再就是第一行的16个数据显示,然后再发送第二行的首地址,再就是第二行的16个数据显示,然后再回到发送第一行的DDRAM首地址,如此循环。其中较为关键的地方是要设置lcd的en为500hz的周期信号,因为lcd是个慢设备,500hz符合他的时序要求。当然设置其他频率也是可以的,只要符合时序要求就可以。

四、实验效果


五、源码

源码链接:https://download.csdn.net/download/chengfengwenalan/10371699

你可能感兴趣的:(FPGA,FPGA教学实验)