课程名称:_____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'd10000000; 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'd20000000; 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
共有三个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'd20000000; 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'd10000000; 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'd10000000; 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)
if (shift_cntr < 5'd8)
begin 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;
light <= 1'b1;
end 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'd20000000; 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全亮,如图:
.
因篇幅问题不能全部显示,请点此查看更多更全内容