一、关于lcd的设置,以及命令格式见博主的另一篇转载的博客:https://blog.csdn.net/chengfengwenalan/article/details/80070058
二、设计思路
本例程主要是利用lcd实现了闹钟功能
第一行显示Alarm:00-00
第二行显示Clock:00-00-00
按下key1按键是进入adjust模式,按下key2是加,按下key3是减,这3个按键都支持连按和快速单击。系统框图如下:
图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