【国产FPGA高云GW1N-4系列开发板测评】——11、点个LCD1602屏
[复制链接]
本帖最后由 gs001588 于 2022-1-20 20:55 编辑
【国产FPGA高云GW1N-4系列开发板测评】——11、点个LCD1602屏
之前用在FPGA上写过12864带字库屏的显示应用,间隔时间比较长了,之前备份的资料暂时没有找到。手头正好有LCD1602的LCD屏,不妨先拿LCD1602来做个显示实验。LCD1602作为一款经典的LCD屏,在各种学习平台上的应用自然是少不了的,在FPGA上也不例外。
本着拿来主义的想法,参考网友资料,做了适当修改。原本打算做成显存方式模块,对外接口为异步RAM方式,模块内部完成LCD初始化,有新显存数据后自动显示刷新操作。这样就需要写顶层文件,需要提供变化的数据源,把问题复杂化,因此可作为之后的改进实验。本贴先显示一下LCD1602。
参考网址(基于FPGA的LCD1602显示屏驱动 https://blog.csdn.net/qq_33231534/article/details/108484995)
本实验使用到的FPGA管脚资源配置如下:
GWIN-4B与LCD1602屏之间对应关系接线表:
LCD1602 |
功能说明 |
GWIN-4B |
1、VCC |
电源地 |
JP7.2-5V |
2、GND |
电源正极 |
J19.1-GND |
3、V0(接5.1K到GND)
|
液晶显示偏压 |
|
4、RS |
命令/数据选择 |
J4.1-32 |
5、RW |
读/写选择 |
J4.2-34 |
6、EN |
使能信号 |
J4.3-38 |
7、DATA0 |
数据0 |
J4.4-39 |
8、DATA1
|
数据1 |
J4.5-40 |
9、DATA2 |
数据2 |
J4.6-41 |
10、DATA3 |
数据3 |
J4.7-42 |
11、DATA4 |
数据4 |
J4.8-43 |
12、DATA5 |
数据5 |
J4.9-44 |
13、DATA6
|
数据6 |
J4.10-45 |
14、DATA7 |
数据7 |
J4.11-46 |
15、A(5V) |
背光正极 |
JP7.1-5V |
16、K(GND) |
背光负极 |
J19.16-GND |
LCD1602的1、3脚之间并个5.1K直插电阻,为3脚的液晶显示偏置电压V0提供参考。一般开发板上使用的话会在1、3脚之间接个10K的电位器来调节电压,为啥是5.1K?之前修过一块开发板,在板上3脚接到GND了,导致普通LCD1602不能显示。查询LCD1602数据手册,此管脚V0为液晶显示偏压,接地时对比度最高,对比度过高时会产生“鬼影”,显示发黑不易区分正常显示与底色;接正电源电压时对比度最弱,显示发白几乎看不见。接个5K左右的电阻即可正常显示,电阻不需要精确4到6K都可以。
正好JP7有两针5V引出,其中一个给LCD逻辑供电,另一个给背光正极供电;GND比较多,随意选了两个,一个作为电源地,另一个作为背光负极。
剩余11条数据线分别一一对应接到JP14的1到11脚。
逻辑代码见下。具体功能及LCD1602相关寄存器功能等可以参考上面的“参考网址”中相关内容。
module lcd(
input clk ,
input rst_n ,
output reg lcd_rs ,
output wire lcd_rw ,
output reg lcd_en ,
output reg [7:0] lcd_data
);
reg [17:0] cnt ;
reg [3:0] state_c ;
reg [3:0] state_n ;
reg [4:0] char_cnt ;
reg [7:0] data_display ;
localparam
IDLE = 4'd0 ,
INIT = 4'd1 ,
S0 = 4'd2 ,
S1 = 4'd3 ,
S2 = 4'd4 ,
S3 = 4'd5 ,
ROW1_ADDR = 4'd6 ,
WRITE = 4'd7 ,
ROW2_ADDR = 4'd8 ,
stop = 4'd9 ;
reg [7:0] disp_memory [0:31];
reg [4:0] disp_cnt;
assign lcd_rw = 1'b0;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 17'd0;
end
else begin
if (cnt==17'd100_000 - 1) begin
cnt <= 17'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
lcd_en <= 0;
end
else if (cnt==17'd50_000 - 1) begin
lcd_en <= 1;
end
else if (cnt==17'd100_000 - 1) begin
lcd_en <= 0;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
char_cnt <= 0;
end
else if (state_c==WRITE && cnt==17'd50_000 - 1) begin
if (char_cnt==5'd31) begin
char_cnt <= 5'd0;
end
else begin
char_cnt <= char_cnt + 1'b1;
end
end
end
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for(i=0;i<32;i=i+1)
begin
case(i)
5'd0: data_display = "W";
5'd1: data_display = "e";
5'd2: data_display = "l";
5'd3: data_display = "c";
5'd4: data_display = "o";
5'd5: data_display = "m";
5'd6: data_display = "e";
5'd7: data_display = " ";
5'd8: data_display = "t";
5'd9: data_display = "o";
5'd10: data_display = " ";
5'd11: data_display = "G";
5'd12: data_display = "O";
5'd13: data_display = "W";
5'd14: data_display = "I";
5'd15: data_display = "N";
5'd16: data_display = "M";
5'd17: data_display = "i";
5'd18: data_display = "n";
5'd19: data_display = "i";
5'd20: data_display = " ";
5'd21: data_display = "K";
5'd22: data_display = "i";
5'd23: data_display = "T";
5'd24: data_display = " ";
5'd25: data_display = "G";
5'd26: data_display = "W";
5'd27: data_display = "I";
5'd28: data_display = "N";
5'd29: data_display = "-";
5'd30: data_display = "4";
5'd31: data_display = "B";
default:data_display = "P";
endcase
disp_memory = data_display;
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_c <= IDLE;
end
else if(cnt==17'd50_000 - 1) begin
state_c <= state_n;
end
end
reg [19:0] cnt_15ms;
reg flag ;
always@(posedge clk or negedge rst_n)begin
if (!rst_n) begin
cnt_15ms <= 0;
end
else if (state_c == IDLE) begin
cnt_15ms <= cnt_15ms + 1'b1;
end
end
always@(posedge clk or negedge rst_n)begin
if (!rst_n) begin
flag <= 0;
end
else if (state_c==IDLE && cnt_15ms==20'd750000) begin
flag <= 1;
end
end
always @(*) begin
case(state_c)
IDLE :
begin
if (flag) begin
state_n = INIT;
end
else begin
state_n = state_c;
end
end
INIT :
begin
state_n = S0;
end
S0 :
begin
state_n = S1;
end
S1 :
begin
state_n = S2;
end
S2 :
begin
state_n = S3;
end
S3 :
begin
state_n = ROW1_ADDR;
end
ROW1_ADDR:
begin
state_n = WRITE;
end
WRITE :
begin
if (char_cnt==5'd15) begin
state_n = ROW2_ADDR;
end
else if (char_cnt==5'd31) begin
state_n = stop;
end
else begin
state_n = state_c;
end
end
ROW2_ADDR:
begin
state_n = WRITE;
end
stop :
begin
state_n = stop;
end
default:state_n = IDLE;
endcase
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
lcd_data <= 8'd0;
end
else begin
case(state_c)
IDLE :begin lcd_data <= 8'h38; lcd_rs <= 0;end
INIT :begin lcd_data <= 8'h38; lcd_rs <= 0;end
S0 :begin lcd_data <= 8'h08; lcd_rs <= 0;end
S1 :begin lcd_data <= 8'h01; lcd_rs <= 0;end
S2 :begin lcd_data <= 8'h06; lcd_rs <= 0;end
S3 :begin lcd_data <= 8'h0c; lcd_rs <= 0;end
ROW1_ADDR :begin lcd_data <= 8'h80; lcd_rs <= 0;end
//WRITE :begin lcd_data <= data_display; lcd_rs <= 1;end
WRITE :begin lcd_data <= disp_memory[char_cnt]; lcd_rs <= 1;end
ROW2_ADDR :begin lcd_data <= 8'hc0; lcd_rs <= 0;end
stop :begin lcd_data <= 8'h38; lcd_rs <= 0;end
default:;
endcase
end
end
endmodule
本实验用到了复位功能,将双功能管脚选项中的RECONFIG_N作为普通IO选项打勾。
逻辑代码编译通过,下载到开发板,LCD1602两行分别显示“Welcome to GOWIN”、“Mini KiT GWIN-4B”,效果见下图。
本实验完成将LCD1602屏点亮显示字符。
疫情原因无法正常上般,家里条件有限,手头缺少扩展模块来实验,更多扩展功能之后有时间补上。
|