数码管动态显示例程讲解
1.需求解读
1.1 需求
在六位数码管上稳定的显示123456
1.2 知识背景
数码管是由多个 LED 发光二极管组成的一个“8”字型的器件,根据极性不同,分为共阳极和共阴极,我们开发板上采用的是共阳数码管。数码管内部结构如下图:
通过图上可以看出,共阳极和共阴极的区别。共阳极公共端接电源正极,共阴极公共端接地。选用共阳极数码管时,我们只需将对应的 abcdefgdq 给低电平便可点亮对应的数码管。共阴极与之相反,需要将 abcdefgdq 接入电源正极便可点亮对应的数码管。数码管示意图如下:
我们选用的开发板使用的是共阳极数码管,如果要显示 2,那么我们应该点亮A,B,G,E,D 段发光二极管。如果要显示 5,大家可以自行分析,应该点亮哪些段,这样我们便可以得出共阳数码管 0 到 9 的编码。为了节约大家的时间,我将共阳数码管对应的编码整理出来,如下图,可以直接调用。共阴数码管的编码只用按位取反即可。
我们开发板共阳数码管段选编码表如下:
1.3 硬件设计
我们开发板上选用的是PNP三极管,当给三极管基极输入低电平,三极管的集电极与发射极便导通,3.3V 的电压便加在了数码管的位选管脚上,那么我们要点亮第一位数码管则需要给SMG_W0 输入低电平,并按数码管编码表给数码管的段选赋值。原理掌握了,我们可以开始编写代码
1.4 数码管动态扫描原理
我们上一讲讲了数码管的静态显示,如果只有一位,用静态扫描的方式那么我们需要控 制 8个段选,1个位选,总共 9 个引脚。如果我们要控制 6 位数码管,而同样采用静态显示的方式,那总共要用 9*6=54 个管脚,事必会造成管脚的严重浪费。为了节约管脚,同时又能显示多位信息,我们可以采用动态扫描的方式来驱动多位数码管,同样的驱动6位数码管,用动态扫描的方式只需要控制8个段选,6个位选信号,总共14个管脚,比静态扫描节约了40个,所以,利用动态扫描方式驱动数码管,是我们学习以及工作中必需要学会的。 多位数码管用于显示更多的数值信息,其由多个数码管组成,这些数码管的段(a~h) 一一对应连接在一起,公共极独立。动态扫描即按照一定的方向逐一选中数码管(通过位选接口来选中要点亮的数码管),然后给段选管脚输入事先准备好的编码数据,并保持一定的时间,如此循环。由于人眼的视觉暂留效应,我们看到的现象便是多位同时显示,这就像我们小时候翻看动画书,当翻得很快时,我们就发现书里面的小动物跑起来了,当时还乐此不疲的找过各种动画书。根据经验,当帧率为 15fps 以上时,动画是连贯的,帧率越高动画也越流畅。但是帧率过高,会造成看不清数码管上显示的信息。所以适当的帧率才是最好的。对于我们的6位数码管,扫描 1 次(显示 6 个数字) 为一帧。我们可以观察不同的扫描频率对应的数码管显示效果,找到显示效果较好的扫描方式。经实验发现,当每一个数字显示 10ms,数码管有明显的闪烁现象,当改为5ms时则显示稳定。原理掌握了,我们可以开始编写代码
1.5 接口说明
信号名 | 方向 | FPGA管脚号 | 说明 |
---|---|---|---|
CLK_50M | 输入 | E1 | 系统时钟,50Mhz |
KEY1 | 输入 | M1 | 独立按键,按下低电平,当作复位使用 |
SMG_W0 | 输出 | A2 | 位选控制信号,低电平可导通三极管,使其给数码管位选供电 |
SMG_W1 | 输出 | A3 | 位选控制信号,低电平可导通三极管,使其给数码管位选供电 |
SMG_W2 | 输出 | A4 | 位选控制信号,低电平可导通三极管,使其给数码管位选供电 |
SMG_W3 | 输出 | B5 | 位选控制信号,低电平可导通三极管,使其给数码管位选供电 |
SMG_W4 | 输出 | A5 | 位选控制信号,低电平可导通三极管,使其给数码管位选供电 |
SMG_W5 | 输出 | 位选控制信号,低电平可导通三极管,使其给数码管位选供电 | |
SMG_A | 输出 | A9 | 数码管段选控制信号,低电平点亮该段 |
SMG_B | 输出 | K8 | 数码管段选控制信号,低电平点亮该段 |
SMG_C | 输出 | D8 | 数码管段选控制信号,低电平点亮该段 |
SMG_D | 输出 | A7 | 数码管段选控制信号,低电平点亮该段 |
SMG_E | 输出 | E7 | 数码管段选控制信号,低电平点亮该段 |
SMG_F | 输出 | B9 | 数码管段选控制信号,低电平点亮该段 |
SMG_G | 输出 | A10 | 数码管段选控制信号,低电平点亮该段 |
SMG_DP | 输出 | C8 | 数码管段选控制信号,低电平点亮该段 |
总结:通过上述说明,可以将需求解读成:当点亮第一位数码管时,位选为6’h3e,此时数码管段选的编码为8’hf9;当点亮第二位数码管时,位选为6’h3d,数码管段选的编码为8’h25;当点亮第三位数码管时,位选为6’h3b,数码管段选的编码为8’h0d;当点亮第四位数码管时,位选为6’h37,数码管段选的编码为8’h99;当点亮第五位数码管时,位选为6’h2f,数码管段选的编码为8’h49;当点亮第六位数码管时,位选为6’h1f,数码管段选的编码为8’h41;
2. 绘制理论波形图
3.新建QuartusII 工程
为了让工程看起来整洁,同时方便工程移植。我们新建4个文件夹,分别是Project,Source,Sim,Doc。
Project — 工程文件夹,里面放的QuartusII工程
Source — 源代码文件夹,里面放的工程源码(.v文件或.vhd文件)
Sim — 仿真文件夹,里面放的仿真相关的文件
Doc — 存放相关资料,比如数据手册,需求文档等
4.编写代码
///
//QQ:3181961725
//TEL/WX:13540738439
//工程师:Mr Wang
//模块介绍:数据管动态扫描,显示123456
module smg_drv(
input clk,
input rst_n,
output reg [5:0] smg_bit,
output reg [7:0] smg_seg
);
parameter refresh_time=50000;//一个时钟周期20ns,50000*20=1000000ns=1ms
reg [3:0] cnt;
reg [24:0] refresh_cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
refresh_cnt<=0;
else if(refresh_cnt==refresh_time-1)
refresh_cnt<=0;
else
refresh_cnt<=refresh_cnt+1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt<=4'hf;
else if(refresh_cnt==0&&cnt==5)
cnt<=0;
else if(refresh_cnt==0)
cnt<=cnt+1;
else;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
smg_bit<=6'h3f;
smg_seg<=8'h0;
end else case(cnt)
0:begin smg_bit<=6'h1f;smg_seg<=8'h9f; end
1:begin smg_bit<=6'h2f;smg_seg<=8'h25; end
2:begin smg_bit<=6'h37;smg_seg<=8'h0d; end
3:begin smg_bit<=6'h3b;smg_seg<=8'h99; end
4:begin smg_bit<=6'h3d;smg_seg<=8'h49; end
5:begin smg_bit<=6'h3e;smg_seg<=8'h41; end
default:;
endcase
end
endmodule
5.编写仿真测试激励文件
仿真时,我们主要关心的是输入端口,在该实验的输入信号有clk,rst_n两个,所以我们只用对这两个信号赋值,让其产生激励,仿真代码如下:
`timescale 1ns/1ns
module smg_drv_tb;
reg clk ;
reg rst_n ;
initial
begin
clk = 0;
rst_n=0;
#1000
rst_n=1;
end
always #10 clk=~clk;
smg_drv Usmg_drv(
.clk (clk),
.rst_n (rst_n),
.smg_bit (),
.smg_seg ()
);
endmodule
6.Modelsim仿真
这个例程非常简单,只用了一条语句,所以不需要仿真验证。但是为了给大家演示一个完整的开发流程,这个实验我们也新建一个仿真工程,从最简单的一个代码开始教大家如何编写仿真激励文件以及如何使用Modelsim软件进行仿真。将第三步编写的源码和第四步编写的仿真测试激励文件一起加入到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文件
固化好以后,掉电程序也不会丢失了!
实验现象
与设计需求吻合,设计完成!