FPGA实验三:液晶屏的显示设计

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

课程名称:_____FPGA实验______指导老师:__竺红卫/陈宏__成绩:__________________
实验名称:____液晶屏的显示设计______实验类型:_FPGA实验_同组学生姓名:__
一、实验目的
1. 熟悉实验板上液晶屏的工作原理;
2. 熟悉驱动电路的源代码。

二、实验装置
1. 电脑一台;
2. 实验板一块;
3. 实验板电源一只;
4. 实验板连接电脑的下载线一根。

三、实验原理
实验板显著的特征是2 线16 字符液晶显示器LCD。

尽管LCD 支持8 位的数据接口,为了与其它的XILINX 的开发板保持兼容并且尽可能减少针脚数,FPGA 仅通过4 位的数据接口线控制LCD,LCD 通过使用ASCII 标准和自定义字符可以有效地显示多种信息。

但是,这些显示速度并不是很快。

每半秒扫描一次以测试实际清晰度的界限。

与50MHz 时钟频率相比,这样的显示速度是慢的。

PicoBlaze 处理器
可以有效地控制显示时间和显示内容。

字符LCD 的供电电压是+5V。

FPGA 的I/O 口信号的电压是3.3V。

但是,FPGA 的输出电平是通过LCD 来识别是有效的低电平还是高电平。

LCD 控制器接收5V TTL 信号电平,FPGA输出3.3V 的LCMOS 以满足5V TTL 电压要求。

数据线上的390 欧串联电阻,当LCD 驱动一个逻辑高电平时,其用来防止了FPGA 和SrtataFlsah I/O 管脚的超负载。

当LCD_RW 为高时,LCD驱动数据线。

在绝大多数应用中,LCD作为只读外围设备,几乎没有从显示器读数据。

四、操作方法和实验步骤
对于程序的各个步骤,如新建项目、新建Verilog HDL、新建.ucf文件、Synthesize、Implement Design、Generate Programming File、Configure Target Device等等,在实验一中已经展示过,每一次实验的基本操作步骤都是差不多的,故这里不再重复阐述。

本次实验总共需要做三份程序并观察现象:
1)例程
2)设计按键拨动时显示小时、分钟和秒,中间分别空一格。

3)按键拨动开始显示,10秒钟显示结束,结束时LCD上显示ABCDEF,同时八只LED灯亮。

五、实验源代码和现象
1)例程
UCF文件如下:
NET "CLK_50MHZ" LOC="C9";
NET "LCD_D<0>" LOC="R15";
NET "LCD_D<1>" LOC="R16";
NET "LCD_D<2>" LOC="P17";
NET "LCD_D<3>" LOC="M15";
NET "LCD_E" LOC="M18";
NET "LCD_RS" LOC="L18";
NET "LCD_RW" LOC="L17";
源代码如下:
module lcd_write_number_test
(
input CLK_50MHZ,
output LCD_E,
output LCD_RS,
output LCD_RW,
output [3:0] LCD_D
);
wire if_ready;
reg if_write;
reg [31:0] if_data;
reg [1:0] state;
reg [31:0] cntr;
parameter IDLE = 2'b00,
IF_WRITE_1 = 2'b01,
SET_IF_WRITE_0 = 2'b10,
WAIT = 2'b11;
// Instantiate the Unit Under Test (UUT)
lcd_write_number uut
(
.CLK_50MHZ(CLK_50MHZ),
.LCD_E(LCD_E),
.LCD_RS(LCD_RS),
.LCD_RW(LCD_RW),
.LCD_D(LCD_D),
.if_data(if_data),
.if_write(if_write),
.if_ready(if_ready)
);
initial begin
if_data <= 32'habba0123;
state <= IDLE;
if_write <= 1'b0;
cntr <= 32'b0;
end
always@ (posedge CLK_50MHZ) begin
case (state)
IDLE:
if (if_ready) begin
if_data <= if_data + 1'b1;
if_write <= 1'b1;
state <= IF_WRITE_1;
cntr <= 32'b0;
end
IF_WRITE_1: // this state to keep if_write up for 2 cycles state <= SET_IF_WRITE_0;
SET_IF_WRITE_0: // set if_write 0 and start the counter begin
if_write <= 1'b0;
state <= WAIT;
cntr <= 32'b0;
end
WAIT:
if (cntr < 25000000) // wait for 0.5 seconds
cntr <= cntr + 32'b1;
else
state <= IDLE;
endcase
end
endmodule
`timescale 1ns / 1ps
module lcd_write_number
(
input CLK_50MHZ,
output LCD_E,
output LCD_RS,
output LCD_RW,
output [3:0] LCD_D,
input [31:0] if_data,
input if_write,
output if_ready
);
reg [7:0] disp_data;
reg disp_rs;
reg [31:0] disp_delay;
reg disp_write;
wire disp_ready;
reg disp_b8;
reg [7:0] char;
reg [1:0] state;
reg [31:0] number;
reg init_done;
reg running;
reg [4:0] shift_cntr;
reg if_ready_r;
assign if_ready = if_ready_r; lcd_display display
(.clk(CLK_50MHZ),
.rst(1'b0),
.lcd_e(LCD_E),
.lcd_rw(LCD_RW),
.lcd_rs(LCD_RS),
.lcd_d(LCD_D),
.if_data(disp_data),
.if_rs(disp_rs),
.if_delay(disp_delay),
.if_write(disp_write),
.if_ready(disp_ready),
.if_8bit(disp_b8)
);
parameter NB_CHARS = 8'd12; parameter START = 2'b00, WAIT_WRITE_0 = 2'b01, WRITE_1 = 2'b10,
WAIT_WRITE_1 = 2'b11;
initial begin
state <= 2'b00;
char <= 8'b0;
init_done <= 1'b0;
if_ready_r <= 1'b0;
shift_cntr <= 5'b0;
end
always@ (posedge CLK_50MHZ) begin
if (init_done && char > 8'd16) begin
if (disp_ready)
if_ready_r <= 1'b1;
if (if_write) begin
char <= 4'd8; // reset the display
end
end else if (char <= 8'd16) begin
if_ready_r <= 1'b0;
case (state)
START:
if (disp_ready) begin
disp_write <= 1'b1;
state <= WAIT_WRITE_0;
end
WAIT_WRITE_0:
state <= WRITE_1;
WRITE_1:
begin
disp_write <= 1'b0;
state <= 2'b11;
end
WAIT_WRITE_1:
begin
state <=START;
char <= char + 8'b1;
end
endcase // case (state)
end // else: !if(!running)
end // always@ (posedge CLK_50MHZ) always@ (negedge CLK_50MHZ) begin
// these next steps initialize the LCD display: case (char)
0:
begin
disp_b8 <= 1'b0;
disp_data <= 8'h30;
disp_delay <= 32'd1*******;
disp_rs <= 1'b0;
end
1: disp_data <= 8'h30;
2:
begin
disp_data <= 8'h30;
disp_delay <= 32'd1000000;
end
3:
begin
disp_data <= 8'h20;
disp_delay <= 32'd20000;
end
4:
begin
disp_b8 <= 1'b1;
disp_data <= 8'h28;
end
5: disp_data <= 8'h06;
6: disp_data <= 8'h0C;
7:
begin
disp_data <= 8'h01;
disp_delay <= 32'd1000000;
init_done <= 1'b1;
shift_cntr <= 5'd9;
end
8: // this state provides an entry point to reset the display and then // go on to the default state that writes the number
begin
disp_rs <= 1'b0;
disp_data <= 8'h01;
disp_delay <= 32'd1000000;
shift_cntr <= 5'b0;
number <= if_data;
end
default:
// state machine to print a 32-bit number out
if (disp_ready && state == START) begin
if (shift_cntr < 5'd8) begin
disp_rs <= 1'b1;
disp_delay <= 32'd20000;
if (number[31:28] < 4'b1010)
disp_data <= number[31:28] + 8'h30; else
disp_data <= number[31:28] + 8'h37; number <= number << 4;
shift_cntr <= shift_cntr + 5'b1;
end
end
endcase // case (char)
end // always@ (negedge CLK_50MHZ) endmodule
`timescale 1ns / 1ps
module lcd_display
(input clk,
input rst,
output lcd_e,
output lcd_rw,
output lcd_rs,
output [3:0] lcd_d,
input [7:0] if_data,
input if_rs,
input [31:0] if_delay,
input if_write,
output if_ready,
input if_8bit);
reg [2:0] state;
reg lcdr_e;
reg [3:0] lcdr_d;
reg [31:0] wait_cntr;
reg ready;
reg init_done;
parameter IDLE = 3'b000,
WAIT_PULSE_E_0 = 3'b001,
LOAD_LOWER_NIBBLE = 3'b010, WAIT_PULSE_E_1 = 3'b011,
WAIT_COMMAND = 3'b100; parameter PULSE_E_DLY = 32'd12; parameter INIT_TIME = 32'd2*******; assign lcd_d = lcdr_d;
assign lcd_rs = if_rs;
assign lcd_rw = 1'b0;
assign lcd_e = lcdr_e;
assign if_ready = ready;
state <= IDLE;
ready <= 1'b0;
lcdr_e <= 1'b0;
init_done <= 1'b0;
end
always@ (posedge clk) begin
if (rst) begin
state <= IDLE;
end else if (!init_done) begin
if (wait_cntr < INIT_TIME)
wait_cntr <= wait_cntr + 1;
else begin
init_done <= 1'b1;
ready <= 1'b1;
end
end else begin
case (state)
IDLE:
begin
if (if_write) begin
lcdr_e <= 1'b1;
lcdr_d <= if_data[7:4]; // upper nibble first ready <= 1'b0;
wait_cntr <= 32'b0;
state <= WAIT_PULSE_E_0;
end
end
WAIT_PULSE_E_0:
if (wait_cntr < PULSE_E_DLY) begin wait_cntr <= wait_cntr + 1;
end else begin
lcdr_e <= 1'b0;
wait_cntr <= 0;
if (if_8bit)
state <= LOAD_LOWER_NIBBLE;
else
state <= WAIT_COMMAND;
end
LOAD_LOWER_NIBBLE:
if (wait_cntr < PULSE_E_DLY) begin wait_cntr <= wait_cntr + 1;
end else begin
wait_cntr <= 0;
lcdr_d <= if_data[3:0]; // lower nibble
state <= WAIT_PULSE_E_1;
end
WAIT_PULSE_E_1:
if (wait_cntr < PULSE_E_DLY) begin
wait_cntr <= wait_cntr + 1;
end else begin
lcdr_e <= 1'b0;
wait_cntr <= 0;
state <= WAIT_COMMAND;
end
WAIT_COMMAND:
if (wait_cntr < if_delay) begin
wait_cntr <= wait_cntr + 32'b1;
end else begin
wait_cntr <= 0;
if (!if_write) begin
state <= IDLE;
ready <= 1'b1;
end
end
endcase // case (state)
end
end
endmodule
共有三个module,它们的包含关系为lcd_write_number_test包含lcd_write_number,lcd_write_number 包含lcd_display,下同。

实验现象:
如下图,刚烧录程序完时,LCD前8位依次显示十六进制数“ABBA0123”,然后每过0.5秒,该数值增一,满十六进位。

2)设计按键拨动时显示小时、分钟和秒,中间分别空一格。

UCF文件如下:
NET "CLK_50MHZ" LOC="C9";
NET "LCD_D<0>" LOC="R15";
NET "LCD_D<1>" LOC="R16";
NET "LCD_D<2>" LOC="P17";
NET "LCD_D<3>" LOC="M15";
NET "LCD_E" LOC="M18";
NET "LCD_RS" LOC="L18";
NET "LCD_RW" LOC="L17";
NET "SW1" LOC="L14";
源代码如下:
module lcd_write_number_test
(
input SW1,
input CLK_50MHZ,
output LCD_E,
output LCD_RS,
output LCD_RW,
output [3:0] LCD_D
);
wire if_ready;
reg if_write;
reg [31:0] if_data;
reg [1:0] state;
reg [31:0] cntr;
parameter IDLE = 2'b00,
IF_WRITE_1 = 2'b01,
SET_IF_WRITE_0 = 2'b10,
WAIT = 2'b11;
// Instantiate the Unit Under Test (UUT)
lcd_write_number uut
(
.SW1(SW1),
.CLK_50MHZ(CLK_50MHZ),
.LCD_E(LCD_E),
.LCD_RS(LCD_RS),
.LCD_RW(LCD_RW),
.LCD_D(LCD_D),
.if_data(if_data),
.if_write(if_write),
.if_ready(if_ready)
);
initial
begin
if_data <= 32'h19044012;
state <= IDLE;
if_write <= 1'b0;
cntr <= 32'b0;
end
always@ (posedge CLK_50MHZ)
begin
case (state)
IDLE:
if (if_ready)
begin
if(if_data[31:0]==32'h23059059)if_data <= 32'h0;
else if(if_data[27:0]==28'h9059059)if_data <= if_data + 32'h6fa6fa7; else if(if_data[19:0]==20'h59059)if_data <= if_data + 32'hfa6fa7; else if(if_data[15:0]==16'h9059)if_data <= if_data + 32'h6fa7;
else if(if_data[7:0]==8'h59)if_data <= if_data + 32'hfa7;
else if(if_data[3:0]==4'h9)if_data <= if_data + 32'h7;
else if_data <= if_data + 1'b1;
if_write <= 1'b1;
state <= IF_WRITE_1;
cntr <= 32'b0;
end
IF_WRITE_1: // this state to keep if_write up for 2 cycles
state <= SET_IF_WRITE_0;
SET_IF_WRITE_0: // set if_write 0 and start the counter
begin
if_write <= 1'b0;
state <= WAIT;
cntr <= 32'b0;
end
WAIT:
if (cntr < 50000000) // wait for 1 seconds
cntr <= cntr + 32'b1;
else
state <= IDLE;
endcase
end
endmodule
`timescale 1ns / 1ps
module lcd_display
(input clk,
input rst,
output lcd_e,
output lcd_rw,
output lcd_rs,
output [3:0] lcd_d,
input [7:0] if_data,
input if_rs,
input [31:0] if_delay,
input if_write,
output if_ready,
input if_8bit);
reg [2:0] state;
reg lcdr_e;
reg [3:0] lcdr_d;
reg [31:0] wait_cntr;
reg ready;
reg init_done;
parameter IDLE = 3'b000,
WAIT_PULSE_E_0 = 3'b001,
LOAD_LOWER_NIBBLE = 3'b010, WAIT_PULSE_E_1 = 3'b011,
WAIT_COMMAND = 3'b100;
parameter PULSE_E_DLY = 32'd12; parameter INIT_TIME = 32'd2*******; assign lcd_d = lcdr_d;
assign lcd_rs = if_rs;
assign lcd_rw = 1'b0;
assign lcd_e = lcdr_e;
assign if_ready = ready;
initial begin
state <= IDLE;
ready <= 1'b0;
lcdr_e <= 1'b0;
init_done <= 1'b0;
end
always@ (posedge clk) begin
if (rst) begin
state <= IDLE;
end else if (!init_done) begin
if (wait_cntr < INIT_TIME)
wait_cntr <= wait_cntr + 1;
else begin
init_done <= 1'b1;
ready <= 1'b1;
end
end else begin
case (state)
IDLE:
begin
if (if_write) begin
lcdr_e <= 1'b1;
lcdr_d <= if_data[7:4]; // upper nibble first ready <= 1'b0;
wait_cntr <= 32'b0;
state <= WAIT_PULSE_E_0;
end
end
WAIT_PULSE_E_0:
if (wait_cntr < PULSE_E_DLY) begin wait_cntr <= wait_cntr + 1;
end else begin
lcdr_e <= 1'b0;
wait_cntr <= 0;
if (if_8bit)
state <= LOAD_LOWER_NIBBLE;
else
state <= WAIT_COMMAND;
end
LOAD_LOWER_NIBBLE:
if (wait_cntr < PULSE_E_DLY) begin wait_cntr <= wait_cntr + 1;
end else begin
wait_cntr <= 0;
lcdr_e <= 1'b1;
lcdr_d <= if_data[3:0]; // lower nibble state <= WAIT_PULSE_E_1;
end
WAIT_PULSE_E_1:
if (wait_cntr < PULSE_E_DLY) begin
wait_cntr <= wait_cntr + 1; end else begin
lcdr_e <= 1'b0;
wait_cntr <= 0;
state <= WAIT_COMMAND; end
WAIT_COMMAND:
if (wait_cntr < if_delay) begin wait_cntr <= wait_cntr + 32'b1; end else begin
wait_cntr <= 0;
if (!if_write) begin
state <= IDLE;
ready <= 1'b1;
end
end
endcase // case (state)
end
end
endmodule
`timescale 1ns / 1ps
module lcd_write_number (
input CLK_50MHZ,
input SW1,
output LCD_E,
output LCD_RS,
output LCD_RW,
output [3:0] LCD_D,
input [31:0] if_data,
input if_write,
output if_ready
);
reg [7:0] disp_data;
reg disp_rs;
reg [31:0] disp_delay;
reg disp_write;
wire disp_ready;
reg disp_b8;
reg [7:0] char;
reg [1:0] state;
reg [31:0] number;
reg init_done;
reg running;
reg [4:0] shift_cntr;
reg if_ready_r;
assign if_ready = if_ready_r;
lcd_display display
(.clk(CLK_50MHZ),
.rst(1'b0),
.lcd_e(LCD_E),
.lcd_rw(LCD_RW),
.lcd_rs(LCD_RS),
.lcd_d(LCD_D),
.if_data(disp_data),
.if_rs(disp_rs),
.if_delay(disp_delay),
.if_write(disp_write),
.if_ready(disp_ready),
.if_8bit(disp_b8)
);
parameter NB_CHARS = 8'd12; parameter START = 2'b00,
WAIT_WRITE_0 = 2'b01,
WRITE_1 = 2'b10,
WAIT_WRITE_1 = 2'b11;
initial
begin
state <= 2'b00;
char <= 8'b0;
init_done <= 1'b0;
if_ready_r <= 1'b0;
shift_cntr <= 5'b0;
end
always@ (posedge CLK_50MHZ) begin
if (init_done && char > 8'd16)
begin
if (disp_ready)
if_ready_r <= 1'b1;
if (if_write)
begin
char <= 4'd8; // reset the display
end
end
else if (char <= 8'd16) begin
if_ready_r <= 1'b0;
case (state)
START:
if (disp_ready) begin
disp_write <= 1'b1;
state <= WAIT_WRITE_0;
end
WAIT_WRITE_0:
state <= WRITE_1;
WRITE_1:
begin
disp_write <= 1'b0;
state <= 2'b11;
end
WAIT_WRITE_1:
begin
state <= START;
char <= char + 8'b1;
end
endcase // case (state)
end // else: !if(!running)
end // always@ (posedge CLK_50MHZ)
always@ (negedge CLK_50MHZ) begin
// these next steps initialize the LCD display: case (char)
0:
begin
disp_b8 <= 1'b0;
disp_data <= 8'h30;
disp_delay <= 32'd1*******;
disp_rs <= 1'b0;
end
1: disp_data <= 8'h30;
2:
begin
disp_data <= 8'h30;
disp_delay <= 32'd1000000;
end
3:
begin
disp_data <= 8'h20;
disp_delay <= 32'd20000;
end
4:
begin
disp_b8 <= 1'b1;
disp_data <= 8'h28;
end
5: disp_data <= 8'h06;
6: disp_data <= 8'h0C;
7:
begin
disp_data <= 8'h01;
disp_delay <= 32'd1000000;
init_done <= 1'b1;
shift_cntr <= 5'd9;
end
8: // this state provides an entry point to reset the display and then // go on to the default state that writes the number
begin
disp_rs <= 1'b0;
disp_data <= 8'h01;
disp_delay <= 32'd1000000;
shift_cntr <= 5'b0;
number <= if_data;
end
default:
// state machine to print a 32-bit number out
if (SW1)
begin
if (disp_ready && state == START) begin
if (shift_cntr < 5'd8) begin
disp_rs <= 1'b1;
disp_delay <= 32'd20000;
if((shift_cntr == 5'd2) || (shift_cntr == 5'd5))
begin
disp_data <= 8'h20;
end
else
begin
if (number[31:28] < 4'b1010)
disp_data <= number[31:28] + 8'h30;
else
disp_data <= number[31:28] + 8'h37;
end
number <= number << 4;
shift_cntr <= shift_cntr + 5'b1;
end
end
end
endcase // case (char)
end // always@ (negedge CLK_50MHZ)
endmodule
实验现象:
当SW1为低电平时,LCD无显示。

SW1向上拨后,如下图,LCD显示小时、分钟和秒,中间分别空一格,且该输出显示会按照时钟的样式计时、刷新,每过一秒钟秒位进一,秒的个位满10进位,秒数满60则分数增一……当SW1再次向下拨,LCD显示关闭,但始终仍然在计时。

程序刚烧进板子时,时钟的初始时间是人为设定的19时44分12秒。

3)按键拨动开始显示,10秒钟显示结束,结束时LCD上显示ABCDEF,同时八只LED灯亮。

UCF文件如下:
NET "CLK_50MHZ" LOC="C9";
NET "LCD_D<0>" LOC=R15;
NET "LCD_D<1>" LOC=R16;
NET "LCD_D<2>" LOC=P17;
NET "LCD_D<3>" LOC=M15;
NET "LCD_E" LOC=M18;
NET "LCD_RS" LOC=L18;
NET "LCD_RW" LOC=L17;
NET "SW1" LOC=L14;
NET "LED0" LOC=F12;
NET "LED1" LOC=E12;
NET "LED2" LOC=E11;
NET "LED3" LOC=F11;
NET "LED4" LOC=C11;
NET "LED5" LOC=D11;
NET "LED6" LOC=E9;
NET "LED7" LOC=F9;
源代码如下:
module lcd_write_number_test
(
input CLK_50MHZ,
input SW1,
output LCD_E,
output LCD_RS,
output LCD_RW,
output [3:0] LCD_D,
output LED0,
output LED1,
output LED2,
output LED3,
output LED4,
output LED5,
output LED6,
output LED7
);
wire if_ready;
reg if_write;
reg [31:0] if_data;
reg [1:0] state;
reg [31:0] cntr;
parameter IDLE = 2'b00,
IF_WRITE_1 = 2'b01,
SET_IF_WRITE_0 = 2'b10,
WAIT = 2'b11;
// Instantiate the Unit Under Test (UUT)
lcd_write_number uut
(
.SW1(SW1),
.CLK_50MHZ(CLK_50MHZ),
.LCD_E(LCD_E),
.LCD_RS(LCD_RS),
.LCD_RW(LCD_RW),
.LCD_D(LCD_D),
.if_data(if_data),
.if_write(if_write),
.if_ready(if_ready),
.LED0(LED0),
.LED1(LED1),
.LED2(LED2),
.LED3(LED3),
.LED4(LED4),
.LED5(LED5),
.LED6(LED6),
.LED7(LED7)
);
initial
begin
if_data <= 32'h19044012;
state <= IDLE;
if_write <= 1'b0;
cntr <= 32'b0;
end
always@ (posedge CLK_50MHZ)
begin
case (state)
IDLE:
if (if_ready)
begin
if(if_data[31:0]==32'h23059059)if_data <= 32'h0;
else if(if_data[27:0]==28'h9059059)if_data <= if_data + 32'h6fa6fa7; else if(if_data[19:0]==20'h59059)if_data <= if_data + 32'hfa6fa7; else if(if_data[15:0]==16'h9059)if_data <= if_data + 32'h6fa7;
else if(if_data[7:0]==8'h59)if_data <= if_data + 32'hfa7;
else if(if_data[3:0]==4'h9)if_data <= if_data + 32'h7; else if_data <= if_data + 1'b1;
if_write <= 1'b1;
state <= IF_WRITE_1;
cntr <= 32'b0;
end
IF_WRITE_1: // this state to keep if_write up for 2 cycles state <= SET_IF_WRITE_0;
SET_IF_WRITE_0: // set if_write 0 and start the counter begin
if_write <= 1'b0;
state <= WAIT;
cntr <= 32'b0;
end
WAIT:
if (cntr < 50000000) // wait for 1 seconds
cntr <= cntr + 32'b1;
else
state <= IDLE;
endcase
end
endmodule
`timescale 1ns / 1ps
module lcd_write_number
(
input CLK_50MHZ,
input SW1,
output LCD_E,
output LCD_RS,
output LCD_RW,
output [3:0] LCD_D,
output LED0,
output LED1,
output LED2,
output LED3,
output LED4,
output LED5,
output LED6,
output LED7,
input [31:0] if_data,
input if_write,
output if_ready
);
reg [7:0] disp_data;
reg disp_rs;
reg [31:0] disp_delay;
reg disp_write;
wire disp_ready;
reg disp_b8;
reg [7:0] char;
reg [1:0] state;
reg [31:0] number;
reg init_done;
reg running;
reg [4:0] shift_cntr;
reg if_ready_r;
reg [28:0] cnt;
reg cnt_state;
reg light;
assign if_ready = if_ready_r;
lcd_display display
(.clk(CLK_50MHZ),
.rst(1'b0),
.lcd_e(LCD_E),
.lcd_rw(LCD_RW),
.lcd_rs(LCD_RS),
.lcd_d(LCD_D),
.if_data(disp_data),
.if_rs(disp_rs),
.if_delay(disp_delay),
.if_write(disp_write),
.if_ready(disp_ready),
.if_8bit(disp_b8)
);
parameter NB_CHARS = 8'd12; parameter START = 2'b00,
WAIT_WRITE_0 = 2'b01,
WRITE_1 = 2'b10,
WAIT_WRITE_1 = 2'b11; initial
begin
state <= 2'b00;
char <= 8'b0;
init_done <= 1'b0;
if_ready_r <= 1'b0;
shift_cntr <= 5'b0;
cnt_state <= 1'b0;
cnt <= 29'b0;
light <= 1'b0;
end
always@ (posedge CLK_50MHZ) begin
if (init_done && char > 8'd16)
begin
if (disp_ready)
if_ready_r <= 1'b1;
if (if_write)
begin
char <= 4'd8; // reset the display
end
end
else if (char <= 8'd16) begin
if_ready_r <= 1'b0;
case (state)
START:
if (disp_ready) begin
disp_write <= 1'b1;
state <= WAIT_WRITE_0;
end
WAIT_WRITE_0:
state <= WRITE_1;
WRITE_1:
begin
disp_write <= 1'b0;
state <= 2'b11;
end
WAIT_WRITE_1:
begin
state <= START;
char <= char + 8'b1;
end
endcase // case (state)
end // else: !if(!running)
end // always@ (posedge CLK_50MHZ)
always@ (posedge CLK_50MHZ)
if (!SW1)
begin
cnt <= 29'b0;
cnt_state<=1'b0;
end
else if (cnt==29'h1dcd6500) cnt_state<=1'b1; else cnt <= cnt+1'b1;
always@ (negedge CLK_50MHZ) begin
// these next steps initialize the LCD display: case (char)
0:
begin
disp_b8 <= 1'b0;
disp_data <= 8'h30;
disp_delay <= 32'd1*******;
disp_rs <= 1'b0;
end
1: disp_data <= 8'h30;
2:
begin
disp_data <= 8'h30;
disp_delay <= 32'd1000000;
end
3:
begin
disp_data <= 8'h20;
disp_delay <= 32'd20000;
end
4:
begin
disp_b8 <= 1'b1;
disp_data <= 8'h28;
end
5: disp_data <= 8'h06;
6: disp_data <= 8'h0C;
7:
begin
disp_data <= 8'h01;
disp_delay <= 32'd1000000;
init_done <= 1'b1;
shift_cntr <= 5'd9;
end
8: // this state provides an entry point to reset the display and then // go on to the default state that writes the number
begin
disp_rs <= 1'b0;
disp_data <= 8'h01;
disp_delay <= 32'd1000000;
shift_cntr <= 5'b0;
number <= if_data;
end
default:
// state machine to print a 32-bit number out
if (SW1 && (!cnt_state))
begin
if (disp_ready && state == START)
begin
if (shift_cntr < 5'd8)
begin
disp_rs <= 1'b1;
disp_delay <= 32'd20000;
if((shift_cntr == 5'd2) || (shift_cntr == 5'd5))
disp_data <= 8'h20;
else
begin
if (number[31:28] < 4'b1010)
disp_data <= number[31:28] + 8'h30;
else
disp_data <= number[31:28] + 8'h37;
end
number <= number << 4;
shift_cntr <= shift_cntr + 5'b1;
end
end
light <= 1'b0;
end
else if (SW1 && cnt_state)
begin
if (disp_ready && state == START)
begin
if (shift_cntr < 5'd8)
begin
disp_rs <= 1'b1;
disp_delay <= 32'd20000;
if((shift_cntr == 5'd2) || (shift_cntr == 5'd5)) disp_data <= 8'h20;
else if(shift_cntr == 5'd0)
disp_data <= 8'h41;
else if(shift_cntr == 5'd1)
disp_data <= 8'h42;
else if(shift_cntr == 5'd3)
disp_data <= 8'h43;
else if(shift_cntr == 5'd4)
disp_data <= 8'h44;
else if(shift_cntr == 5'd6)
disp_data <= 8'h45;
else if(shift_cntr == 5'd7)
disp_data <= 8'h46;
end
shift_cntr <= shift_cntr + 5'b1;
end
light <= 1'b1;
end
else
light <= 1'b0;
endcase // case (char)
end // always@ (negedge CLK_50MHZ) assign LED0 = light;
assign LED1 = light;
assign LED2 = light;
assign LED3 = light;
assign LED4 = light;
assign LED5 = light;
assign LED6 = light;
assign LED7 = light;
endmodule
`timescale 1ns / 1ps
module lcd_display
(input clk,
input rst,
output lcd_e,
output lcd_rw,
output lcd_rs,
output [3:0] lcd_d,
input [7:0] if_data,
input if_rs,
input [31:0] if_delay,
input if_write,
output if_ready,
input if_8bit);
reg [2:0] state;
reg lcdr_e;
reg [3:0] lcdr_d;
reg [31:0] wait_cntr;
reg ready;
reg init_done;
parameter IDLE = 3'b000,
WAIT_PULSE_E_0 = 3'b001,
LOAD_LOWER_NIBBLE = 3'b010, WAIT_PULSE_E_1 = 3'b011,
WAIT_COMMAND = 3'b100;
parameter PULSE_E_DLY = 32'd12; parameter INIT_TIME = 32'd2*******; assign lcd_d = lcdr_d;
assign lcd_rs = if_rs;
assign lcd_rw = 1'b0;
assign lcd_e = lcdr_e;
assign if_ready = ready;
initial begin
state <= IDLE;
ready <= 1'b0;
lcdr_e <= 1'b0;
init_done <= 1'b0;
end
always@ (posedge clk) begin
if (rst) begin
state <= IDLE;
end else if (!init_done) begin
if (wait_cntr < INIT_TIME)
wait_cntr <= wait_cntr + 1;
else begin
init_done <= 1'b1;
ready <= 1'b1;
end
end else begin
case (state)
IDLE:
begin
if (if_write) begin
lcdr_e <= 1'b1;
lcdr_d <= if_data[7:4]; // upper nibble first ready <= 1'b0;
wait_cntr <= 32'b0;
state <= WAIT_PULSE_E_0;
end
end
WAIT_PULSE_E_0:
if (wait_cntr < PULSE_E_DLY) begin wait_cntr <= wait_cntr + 1;
end else begin
lcdr_e <= 1'b0;
wait_cntr <= 0;
if (if_8bit)
state <= LOAD_LOWER_NIBBLE;
else
state <= WAIT_COMMAND;
end
LOAD_LOWER_NIBBLE:
if (wait_cntr < PULSE_E_DLY) begin wait_cntr <= wait_cntr + 1;
end else begin
wait_cntr <= 0;
lcdr_e <= 1'b1;
lcdr_d <= if_data[3:0]; // lower nibble
state <= WAIT_PULSE_E_1;
end
WAIT_PULSE_E_1:
if (wait_cntr < PULSE_E_DLY) begin
wait_cntr <= wait_cntr + 1;
end else begin
lcdr_e <= 1'b0;
wait_cntr <= 0;
state <= WAIT_COMMAND;
end
WAIT_COMMAND:
if (wait_cntr < if_delay) begin
wait_cntr <= wait_cntr + 32'b1;
end else begin
wait_cntr <= 0;
if (!if_write) begin
state <= IDLE;
ready <= 1'b1;
end
end
endcase // case (state)
end
end
endmodule
实验现象:
当SW1为低电平时,LCD无显示,LED都不亮。

将SW1向上拨,LCD立即显示小时(空格)分钟(空格)秒数,且该时钟会走动;LCD显示10秒钟后,LCD上变成显示AB(空格)CD(空格)EF,同时八只LED灯亮;此时再将SW1向下拨,则LCD变为无显示,LED全灭。

再将SW1向上拨,又将重复上述过程。

将SW1向上拨,LCD显示持续10秒钟的时钟,如图:
10秒钟后,LCD改为显示AB CD EF,且8个LED全亮,如图:。

相关文档
最新文档