串口通信例程讲解
1. 需求解读
1.1 需求
在液晶屏第一行显示“HELLO FPGA 1234!”
1.2 知识背景
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。
LCD1602是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。一般来说,LCD1602有16条引脚,据说还有14条引脚的,与16脚的相比缺少了背光电源A(15脚)和地线K(16脚)。实物如下图所示:
引脚定义如下:
说明:
- VSS接电源地。
- VDD接+5V。
- VO是液晶显示的偏压信号,可接10K的电位器用于调节显示效果。
- RS是命令/数据选择引脚,当RS为低电平时,选择命令;当RS为高电平时,选择数据。
- RW是读/写选择引脚,当RW为低电平时,向LCD1602写入命令或数据;当RW为高电 平时,从LCD1602读取状态或数据。如果不需要进行读取操作,可以直接将其接VSS。
- E,执行命令的使能引脚。
- D0—D7,并行数据输入/输出引脚 。
- A背光正极,与VDD相连接。
- K背光负极,接VSS。
1.3 硬件设计
1.4 接口说明
信号名 | 方向 | FPGA管脚号 | 说明 |
---|---|---|---|
CLK50M | 输入 | E1 | 时钟信号,50MHZ |
LCD_RS | 输出 | J6 | 命令/数据选择引脚,当RS为低电平时,选择命令;当RS为高电平时,选择数据 |
LCD_RW | 输出 | F5 | 是读/写选择引脚,当RW为低电平时,向LCD1602写入命令或数据;当RW为高电平时,从LCD1602读取状态或数据 |
LCD_CLK | 输出 | E5 | 执行命令的使能引脚 |
LCD_DB0 | 输出 | D4 | 并行数据输入/输出引脚 |
LCD_DB1 | 输出 | G5 | 并行数据输入/输出引脚 |
LCD_DB2 | 输出 | D1 | 并行数据输入/输出引脚 |
LCD_DB3 | 输出 | C2 | 并行数据输入/输出引脚 |
LCD_DB4 | 输出 | B1 | 并行数据输入/输出引脚 |
LCD_DB5 | 输出 | B7 | 并行数据输入/输出引脚 |
LCD_DB6 | 输出 | B4 | 并行数据输入/输出引脚 |
LCD_DB7 | 输出 | B3 | 并行数据输入/输出引脚 |
2. 绘制理论波形图
3.新建QuartusII 工程
为了让工程看起来整洁,同时方便工程移植。我们新建4个文件夹,分别是Project,Source,Sim,Doc。
Project — 工程文件夹,里面放的QuartusII工程
Source — 源代码文件夹,里面放的工程源码(.v文件或.vhd文件)
Sim — 仿真文件夹,里面放的仿真相关的文件
Doc — 存放相关资料,比如数据手册,需求文档等
4.编写代码
///
//QQ:3181961725
//TEL/WX:13540738439
//作者:Mr Wang
//模块介绍:LCD1602显示驱动
///
module lcd (
input clk ,//系统时钟输入50M
input rst_n ,//复位,低电平有效
output reg [7:0] dat ,//LCD的8位数据口
output reg rs ,//数据命令选择信号,高电平表示数据,低电平表示命令
output rw ,//读写标志,高电平表示读,低电平表示写,该程序我们只对液晶屏进行写操作
output en //LCD的控制脚
);
reg [15:0] counter ;
reg [ 5:0] current ;
reg clkr ;
reg e ;
//定义了LCD状态机需要的状态。
parameter set0 =6'd0;
parameter set1 =6'd1;
parameter set2 =6'd2;
parameter set3 =6'd3;
parameter set4 =6'd4;
parameter dat0 =6'd5;
parameter dat1 =6'd6;
parameter dat2 =6'd7;
parameter dat3 =6'd8;
parameter dat4 =6'd9;
parameter dat5 =6'd10;
parameter dat6 =6'd11;
parameter dat7 =6'd12;
parameter dat8 =6'd13;
parameter dat9 =6'd14;
parameter dat10=6'd15;
parameter dat11=6'd16;
parameter dat12=6'd17;
parameter dat13=6'd18;
parameter dat14=6'd19;
parameter dat15=6'd20;
parameter fini=6'hF1;
always @(posedge clk or negedge rst_n) //da de data_w1 zhong pinlv
begin
if(!rst_n)
begin
counter<=0;
clkr<=0;
end
else
begin
counter<=counter+1;
if(counter==16'h000f)
clkr<=~clkr;
else
;
end
end
always @(posedge clkr or negedge rst_n)
begin
if(!rst_n)
begin
current<=set0;
dat<=0;
rs<=0;
e<=1;
end
else
begin
case(current)
set0: begin e<=0;rs<=0; dat<=8'h38; current<=set1; end //*设置8位格式,2行,5*7*
set1: begin e<=0;rs<=0; dat<=8'h0C; current<=set2; end //*整体显示,关光标,不闪烁*/
set2: begin e<=0;rs<=0; dat<=8'h06; current<=set3; end //*设定输入方式,增量不移位*/
set3: begin e<=0;rs<=0; dat<=8'h01; current<=set4; end //*清除显示*/
set4: begin e<=0;rs<=0; dat<=8'h80; current<=dat0; end //设置显示第一行
dat0: begin e<=0;rs<=1; dat<="H"; current<=dat1; end
dat1: begin e<=0;rs<=1; dat<="E"; current<=dat2; end
dat2: begin e<=0;rs<=1; dat<="L"; current<=dat3; end
dat3: begin e<=0;rs<=1; dat<="L"; current<=dat4; end
dat4: begin e<=0;rs<=1; dat<="O"; current<=dat5; end
dat5: begin e<=0;rs<=1; dat<=" "; current<=dat6; end
dat6: begin e<=0;rs<=1; dat<="F"; current<=dat7; end
dat7: begin e<=0;rs<=1; dat<="P"; current<=dat8; end
dat8: begin e<=0;rs<=1; dat<="G"; current<=dat9; end
dat9: begin e<=0;rs<=1; dat<="A"; current<=dat10 ; end
dat10: begin e<=0;rs<=1; dat<="!"; current<=dat11; end
dat11: begin e<=0;rs<=1; dat<="1"; current<=dat12; end
dat12: begin e<=0;rs<=1; dat<="2"; current<=dat13; end
dat13: begin e<=0;rs<=1; dat<="3"; current<=dat14; end
dat14: begin e<=0;rs<=1; dat<="4"; current<=dat15; end
dat15: begin e<=0;rs<=1; dat<="6"; current<=fini; end
fini: begin e<=1;rs<=0; dat<=8'h00; end
default: current<=set0;
endcase
end
end
assign en=clkr|e;
assign rw=0;
endmodule
5.编写仿真测试激励文件
`timescale 1ns/1ns
module lcd1602_tb;
reg clk ;
reg rst_n ;
initial
begin
clk = 0;
rst_n=0;
#1000
rst_n=1;
end
always #10 clk=~clk;
lcd Ulcd(
.clk (clk),//系统时钟输入50M
.rst_n (rst_n),//复位,低电平有效
.dat (),//LCD的8位数据口
.rs (),//数据命令选择信号,高电平表示数据,低电平表示命令
.rw (),//读写标志,高电平表示读,低电平表示写,该程序我们只对液晶屏进行写操作
.en ()//LCD的控制脚
);
endmodule
6.Modelsim仿真
Modelsim仿真一般有两种方法
-
图形化界面仿真,即所有的操作都是在Modelsim软件界面上来完成,该方式的优点是,简单易学,适用于简单的项目,缺点是操作步骤繁琐。
-
批处理仿真,这种方式在仿真前需要编写相应的脚本文件,该方式的优点是,一键即可完成仿真,省时省力,缺点是前期需要编写脚本文件。前两讲采用的是图形化界面仿真的方式;为了更贴近工程实际,从第三讲开始,我们就采用批处理方式仿真。具体操作步骤可参考我们的视频教程
仿真出的波形如下图所示:
7.对比波形图
将第二步绘制的理论波形图与第六步Modelsim仿真出来的波形图进行对比,结果一致,说明我们的逻辑设计是正确的。如果发现比对结果不一致,就需要找到不一致的原因,最终要保证对比结果一致。通过对比,理论波形与仿真波形一致,说明功能符合设计要求。
8.编译综合
9.绑定管脚
当工程编译成功后,即可进行管脚分配(需要参考开发板的原理图)。我们店铺的开发板和模块在PCB板上均标注了信号名,在绑定管脚时也可以直接参照实物的连接关系。
管脚映射关系如下所示:
10.再次编译综合
11 下载SOF文件
再次编译综合成功后便可以将生成的SOF文件下载到开发板
下载成功后,便可以观察到开发板上的实验现象,如果实验现象与设计需求相符,那说明我们的设计是没有问题的,即可进行下一步固化JIC文件操作
12 生成并固化JIC文件
FPGA有一个特性,就是掉电后配置信息会丢失,所以我们需要将配置信息存储在配置芯片(FLASH)中,待开发板上电后,FPGA便会读取配置芯片中的配置信息,这样开发板掉电再上电后同样可正常工作。要将程序固化到配置芯片,需要先生成JIC文件。SOF文件转换成JIC文件步骤如下:
12.1 file–>Convert Programming File…
12.2 选择JIC文件以及配置芯片的型号,FPGA的型号
标号1:选择生成文件的格式,我们选择JIC文件
标号2:选择配置芯片的型号,我们选择EPCS16
标号3:修改生成JIC文件的名字以及存放路径
标号4:鼠标左键点击Flash Loader
标号5:选择FPGA的型号,我们开发板用的是EP4CE6F17C8这款FPGA,所以我们也应该选这个型号,如下图所示:
12.3 选择SOF文件
标号1:鼠标左键点击SOF Data
标号2:添加SOF文件,选中我们工程生成的SOF文件,如下图:
12.3 生成JIC文件
到此,JIC文件生成好,可以进行固化操作了。
12.4 固化JIC文件
固化好以后,掉电程序也不会丢失了!
实验现象
与设计需求吻合,设计完成!