fpga 设计电子时钟(12864 显示)
设计心得:
1,进行分块设计,类似调用函数,脉冲使能
2,充分了解 fpga 的并行特性(c 程序的串行特性,不能并行处理,线性:只有完成了当前
任务,才能进行下一个任务)
设计问题:
1,似乎读有问题,在 char_LR=1 时,写的数据为汉字
(程序中时间没有更改,主要为了调试看波形)
实际板子验证时,将 LCD_clk 模块中的分频调为 50 到 100kHz 左右
整体架构
功能模块
液晶初始化时序
控制时序
时序处理
功能模块
初始化
写汉字
写字符
绘图
非忙应答
1,液晶上电初始化
2,清屏
1,采用绘图模式
2,一次一个汉字
3,位置,编码编号
1,采用 CDRAM 模式
2,一次一个字符
3,位置
1,采用绘图模式
2,大小可变(库编码内存不变)
3,位置,长宽
parameter
Idle
=8'b0000_0001,
=8'b0000_0010,
Basic_com
Disp_set
=8'b0000_0100,
DDRAM_clear =8'b0000_1000,
Wait_clear
=8'b0001_0000,
=8'b0010_0000,
Point_set
Show_on
=8'b0100_0000,
//basic instruction:0x30
//set show curse bling
//colunm address X
Stop
=8'b1000_0000;
写字符的时序
由于字符属于半宽字形,且 DDRAM 形式下,每行只有 8 个地址,而字符可以写 16 个,因此用下面三个来表
示写的地址:
input [1:0]
input [2:0]
input
//row 0-3
//clunm 0-7
Y,
X,
LR,
//0/1
因此当 LR=0 时,直接写地址,然后写一个字符编码即可
LR=1 时,先写地址,读出高位数据,然后写入两个字节(读出的数据,要写的数据)
parameter
Idle
DDRAM
W_addr
Dummy
R_data
W0_data
W1_data
Stop
=8'b0000_0001,
=8'b0000_0010,
=8'b0000_0100,
=8'b0000_1000,
=8'b0001_0000,
=8'b0010_0000,
=8'b0100_0000,
=8'b1000_0000;
//drawing mode
//row address Y
// not really reading
//reading high byte data
# t1:
# t1:
# t1:
0 t2:
2305 t2:
2665 t2:
2305, T:
2665, T:
3265, T:
10,n_init:
10,n_char:
10,n_char:
38
6
10
完成了上述工作,就可以设计一个简单的电子时钟,其要求如下:
在屏幕上显示时间 00:00:00
要动态走
(主要就是控制脉冲信号的产生)
设计思路:
1,按下复位键,系统复位,时间变为 00:00:00
2,每一秒中时分秒数据更改
3,一秒钟时间到,产生 8 个字符写的脉冲,LCD 更新数据显示
00:00:01
00:01:59
1 代码
/*
sign.v
//creat the control sign
clock h:m:s
*/
module sign(
//module LED(
//100kHz
lcd_clk,
sys_rst,
input
input
output reg lcd_char_en,
output reg lcd_init_en,
output reg [7:0]char_data,
output reg [2:0]char_X,
output reg [1:0]char_Y,
output reg char_LR
);
parameter T_w_char = 5,
T_lcd_init = 40;
reg [47:0] time_out;
/* 1s */
reg [16:0] cnt_s;
reg [5:0] cnt0_clk;
reg [3:0] cnt1_clk;
reg [2:0] cnt_char;
reg [5:0] sec,min;
reg [4:0] hour;
reg flag_s,flag_init;
always @ (posedge lcd_clk or negedge sys_rst)
if(!sys_rst)
begin
begin //100kHz
cnt_s
<=0;
cnt0_clk<=0;
cnt1_clk<=0;
cnt_char<=0;
<=0;
sec
<=0;
min
hour
<=0;
flag_s
<=0;
flag_init <=1'b1;
char_Y <= 2'b10;
else
end
begin
if(cnt_s == (40-1))
begin
cnt_s <=0;
flag_s<=1'b1;
data_deal;
//task
end
else
cnt_s <=cnt_s+1'b1;
if(flag_init)
begin
cnt0_clk <= cnt0_clk +1'b1;
case(cnt0_clk)
: begin lcd_init_en <=1'b0; end
: begin lcd_init_en <=1'b1; end
: begin lcd_init_en <=1'b1; end
: begin lcd_init_en <=1'b0; end
1
2
3
4
T_lcd_init: begin
flag_init <=0;
cnt0_clk <=0;
end
default: lcd_init_en <=0;
endcase
end
else
if(flag_s)
begin
cnt1_clk <= cnt1_clk +1'b1;
case(cnt1_clk)
: begin lcd_char_en <=1'b0;end
: begin lcd_char_en <=1'b1;end
: begin lcd_char_en <=1'b1;end
: begin lcd_char_en <=1'b0;end
1
2
3
4
T_w_char:
begin
if(cnt_char == 3'b111)
begin cnt_char<=0; flag_s <=0; end
else
cnt_char <=cnt_char+1'b1;
cnt1_clk <=0;
end
default: lcd_char_en <=0;
endcase
case(cnt_char)
//2 3 4 5
end //x0:00:00
end //0x:00:00
058
end //00:x0:00
end //00:0x:00
058
0
1
2
3
4
5
6
: begin char_X <=3'b000; char_LR <=0; char_data <=time_out[47:40];
: begin char_X <=3'b001; char_LR <=0; char_data <=time_out[39:32];
: begin char_X <=3'b010; char_LR <=0; char_data <=8'h3a; end
//: ascii
: begin char_X <=3'b011; char_LR <=0; char_data <=time_out[31:24];
: begin char_X <=3'b100; char_LR <=0; char_data <=time_out[23:16];
: begin char_X <=3'b101; char_LR <=0; char_data <=8'h3a; end
//: ascii
: begin char_X <=3'b110; char_LR <=0; char_data <=time_out[15: 8]; end
//00:00:x0
7
: begin char_X <=3'b111; char_LR <=0; char_data <=time_out[7 : 0]; end
endcase
end
end
end
task data_deal;
begin
if(sec == 59)
if(min ==59)
if(hour == 23)
begin
hour<=0;min <=0;sec <=0; end
begin
hour<=hour + 1'b1; min <=0; sec<=0; end
else
else
begin min <= min+1'b1; sec <=0; end
else
sec <= sec +1'b1;
time_out[47:40] <= 8'h30+(hour/10);
time_out[39:32] <= 8'h30+(hour%10);
time_out[31:24] <= 8'h30+(min /10);
time_out[23:16] <= 8'h30+(min %10);
time_out[15: 8] <= 8'h30+(sec /10);
time_out[ 7: 0] <= 8'h30+(sec %10);
end
endtask
endmodule
2 代码
module LCD_init(
//module LED(
input
input
input
output
output
output
inout
lcd_clk,
sys_clk,
lcd_en,
reg LCD_RS,
reg LCD_RW,
reg LCD_EN,
[7:0] LCD_DATA,
//1 is actived
output reg
ACK
);
reg flag;
reg [7:0] lcd_data;
reg [7:0] State;
reg link_rs;
reg link_data;
parameter
=8'b0000_0010,
//basic instruction:0x30
//set show curse bling
//colunm address X
=8'b0000_0001,
Idle
Basic_com
Disp_set =8'b0000_0100,
DDRAM_clear =8'b0000_1000,
Wait_clear
=8'b0001_0000,
Point_set =8'b0010_0000,
Show_on
Stop
=8'b1000_0000;
=8'b0100_0000,
reg [9:0] cnt; //16*2*32=2^10 byte(8bits)
/* LCD_RW LCD_DATA*/
assign LCD_DATA = link_data ? lcd_data: 8'hzz;
/* LCD_RW LCD_EN */
always @ (posedge sys_clk) begin
if(flag)
begin
LCD_RW =0;
LCD_EN = lcd_clk;
else
end
begin
LCD_RW =1'bz;
LCD_EN =1'bz;
end
end
/* LCD_RS */
always @ (posedge lcd_clk) begin
if(link_rs)
LCD_RS <=1'b0;
else
LCD_RS <=1'bz;
end
/*-Main state transter-*/
always @ (posedge lcd_clk) begin
case (State)
Idle
: begin
if(lcd_en)
begin link_rs=1; State
<= Basic_com; end