此实验基于FPGA征途pro开发板实现,
数码管的基本知识
数码管简介
数码管是一种半导体发光器件,其基本单元是发光二极管。数码管按段数一般分为七 段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管(多一个小数点显 示)。当然也还有一些其他类型的数码管如“N”形管、“米”字管以及工业科研领域用 的 16 段管、24 段管等,本次实验我们采用8段数码管。
八段数码管知识
由上图可以看出,八段数码管是一个八字型数码管,分为八段:a、b、c、d、e、 f、g、dp,其中 dp 为小数点,每一段即为一个发光二极管,这样的八段我们称之为段选信 号。数码管常用的有 10 根管脚,每一段有一根管脚,另外两根管脚为一个数码管的公共 端,两根互相连接。
数码管分为共阳极数码管和共阴极数码管。共阳极数码管就是把发光二极管的正极连 接在一起作为一个引脚,负极分开。相反的,共阴极数码管就是把发光二极管的阴极连接 在一起作为一个引脚,正极分开。这两者的区别在于,公共端是连接到地还是高电平,对 于共阳极数码管需要给对应段低电平才会使其点亮,而对于共阴极数码管则需要给其高电 平才会点亮。本次实验使用的是共阳极数码管,也就是说给对应段低电平才会被点亮。给 不同的段点亮可显示 0~f 的值,
下图是提供的数码管编码译码表:
二进制段码右边为高位左边为低位。我们只要点亮相应的段码,就 能显示我们需要显示的内容。
段式数码管工作方式有两种:静态显示和动态显示。静态显示的特点是每个数码管的 段选必须接一个 8 位数据线来显示字形,显示字形可一直保持,直到送入新字形码为止。 那么如果点亮 6 个码管是不是需要 48 位数据线去分别控制每一个码管的段选?当然这种方 法也可以,但是其占用的 I/O 口较多,因此硬件电路比较复杂,成本较高,很少使用。
为节省资源我们采用如图所示的数码管的连接方式:
由上图可以看到,我们将六个数码管的段选信号连接在一起,而位选(sel)独立控 制,这样六个数码管接在一起就少了 8×5 个 I/O 口。这里对位选信号特别说明一下:由上 图可以看到每一个数码管都有一个位选信号,而这个位选信号就控制着数码管的亮灭。这 样我们就可以通过位选信号去控制数码管亮,而在同一时刻,位选选通的数码管上显示的 字形是一样的,因为我们将 6 个数码管相对应的段选连在了一起,数码管的显示自然就相 同了,数码管的这种显示方式即为静态显示。
为了进一步减少板载I/O口资源我们采用74HC595芯片,
74HC595芯片介绍
74HC595 是一个 8 位串行输入、并行输出的位移缓存器。其内部具有 8 位移位寄存器 和一个存储器,具有三态输出功能。
通过查找数据手册我们得到74HC595芯片的功能表:
总结一下74HC595芯片的用法
1、 首先把要传输的数据通过引脚 DS 输入到 74HC595 中。
2、 产生 SHCP 时钟,将 DS 上的数据串行移入移位寄存器。
3、 产生 STCP 时钟,将移位寄存器里的数据送入存储寄存器
4、 将OE 引脚置为低电平,存储寄存器的数据会在 Q0—Q7 并行输出,同时并行输出 的数据会被锁存起来。
接下来正式开始实验的设计验证和实现:
我们可以设计一个这样的 6 位数码管静态显示:控制六位 数码管让其以 000000、111111、222222 一直到 FFFFFF 循环显示。每个字符显示 0.5s 后变 化。
程序设计
根据实验要求绘制系统框架:
根据绘制的系统框架可以将这个程序初步设计为三部分:
第一部分:实现seg_static功能,
第二部分:实现芯片hc595_ctrl控制功能;
第三部分:实现顶层设计模块的综合。
第一部分:seg_static数码管显示模块
首先介绍一下程序中的几个变量所代表的含义:
cnt:根据实验要求需要等待 0.5s 后显示的字符才发生变化。所以我们需要一个 0.5s 的循环计数器。我们输入的时钟频率是 50MHz,一个时钟周期的时间就是 (1/50MHz)s , 也 就 是 20ns 。 所 以 我 们 计 数 器 从 0 计 到 24_999_999 即 为 0.5s (25000000*20ns)的时间。计到 0.5s 后让其归 0 开始下一个 0.5s 的计数。
cnt_flag:当计数器计到 0.5s 时,我们拉高一个标志信号,让这个标志信号去控制数 码管字符的跳转。 num:每个数码管显示的字符,初始显示为 0,六个就是 000000。当检测到跳转的标 志信号为高时,让各个数码管显示的字符加 1。当加到 4’hF 时让其归 0 重新相加以此循 环。
sel:数码管的位选信号。我们是显示六个数码管,直接给其全点亮即可。根据原理图 可知我们需要给其位选信号高电平数码管才会被点亮,所以给对应的位数高电平对应的数 码管就会点亮,一位表示一个数码管。这里我们全部点亮即可。
seg:数码管的段选信号,给其相应段码点亮显示 num 里的值即可。
module seg_static
#(
parameter CNT_MAX = 25'd24_999_999
)
(
input wire sys_clk,
input wire sys_rst_n,
output reg [5:0] sel ,
output reg [7:0] seg
);
reg [24:0] cnt;
reg [3:0] data;
reg cnt_flag;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 25'd0;
else if(cnt == CNT_MAX)
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_flag <= 1'b0;
else if(cnt == CNT_MAX-1)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 4'd0;
else if(cnt_flag == 1'b1)
data <= data + 1'b1;
else
data <= data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel <= 6'b000_000;
else
sel <= 6'b111_111;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg <= 8'hff;
else case(data)
4'd0 : seg <= 8'hc0;
4'd1 : seg <= 8'hf9;
4'd2 : seg <= 8'ha4;
4'd3 : seg <= 8'hb0;
4'd4 : seg <= 8'h99;
4'd5 : seg <= 8'h92;
4'd6 : seg <= 8'h82;
4'd7 : seg <= 8'hf8;
4'd8 : seg <= 8'h80;
4'd9 : seg <= 8'h90;
4'd10 : seg <= 8'h88;
4'd11 : seg <= 8'h83;
4'd12 : seg <= 8'hc6;
4'd13 : seg <= 8'ha1;
4'd14 : seg <= 8'h86;
4'd15 : seg <= 8'h8e;
default seg <= 8'hff;
endcase
endmodule
第二部分74HC595 控制模块
程序中的一些变量所表示的含义:
cnt:分频计数器。这里我们让计数器在 0 和 3 之间循环计数,这样一个循环生成一个 时钟即为四分频时钟。
cnt_bit:传输位数计数器。我们知道我们需要传输 14bit 的数据,故我们需要一个数据 器对传输的位数进行计数,这样我们对传输完成 14 位数据就可以用这个计数器进行判别了。当 cnt 等于 3 时让 cnt_bit 计数器加 1,让其从 0 到 13 循环计数,每个数值 代表传输一位数据。
data:我们将需要传输的数码管信号寄存在 data 中,方便赋值。存储顺序是根据我们 传输的位数顺序由低到高位进行存储的,至于数码管各信号的传输顺序我们在硬件部分已 有所讲解。
ds:串行数据输出(对我们 FPGA 芯片来说其是输出,对 74HC595 来说其是输入, stcp 和 shcp 信号也是如此)。第二片的 Q5 引脚连到 了数码管的 DIG6,也就是最右侧的数码管,而我们最右侧数码管对应的是我们位选信号的 最低位,即 sel[0]。所以我们第一位应传输的数据为 sel[0],当一次数据传完之后再次回到状态 0 开始新一轮 的数码管信号传输。
shcp:移位寄存器时钟,上升沿时将数据写入移位寄存器中。我们在 ds 数据的中间状 态拉高产生上升沿,这样可以使 shcp 采得的 ds 数据更加稳定。
stcp:存储寄存器时钟。当我们 14 位数码管控制信号传输完之后我们需要拉高一个 stcp 时钟来将信号存入存储寄存器之中。最后一个数据是在 cnt_bit=13 且 cnt=2 时传输的, 所以我们就在下一个时钟(cnt_bit=13 且 cnt=3 时)将 stcp 拉高一个时钟产生上升沿即可。
oe:存储寄存器数据输出使能信号,低电平有效,这里我们将复位信号取反的值赋给 该信号即可。
module hc595_crtl
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [5:0] sel ,
input wire [7:0] seg ,
output reg stcp ,
output reg shcp ,
output reg ds ,
output wire oe
);
reg [1:0] cnt_4;
reg [3:0] cnt_bit;
wire [13:0] data;
assign data = {seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel};
assign oe = 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_4 <= 2'd0;
else if(cnt_4 == 2'd3)
cnt_4 <= 2'd0;
else
cnt_4 <= cnt_4 + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 4'd0;
else if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
cnt_bit <= 4'd0;
else if(cnt_4 == 2'd3)
cnt_bit <= cnt_bit + 1'b1;
else
cnt_bit <= cnt_bit;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
stcp <= 1'b0;
else if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
stcp <= 1'b1;
else
stcp <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shcp <= 1'b0;
else if (cnt_4 >= 4'd2)
shcp <= 1'b1;
else
shcp <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
ds <= 1'b0;
else if (cnt_4 == 2'd0)
ds <= data[cnt_bit];
else
ds <= ds;
endmodule
第三部分顶层模块综合:
module seg_595_static
(
input wire sys_clk,
input wire sys_rst_n,
output wire ds,
output wire shcp,
output wire stcp,
output wire oe
);
wire [5:0] sel;
wire [7:0] seg;
seg_static seg_static_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.sel (sel ),
.seg (seg )
);
hc595_crtl hc595_crtl_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.sel (sel),
.seg (seg),
.stcp (stcp),
.shcp (shcp),
.ds (ds),
.oe (oe )
);
endmodule
编写仿真代码进行仿真验证
`timescale 1ns/1ns
module tb_seg_595_static();
reg sys_clk;
reg sys_rst_n;
wire stcp;
wire shcp;
wire ds;
wire oe;
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
always #10 sys_clk <= ~sys_clk;
defparam seg_595_static_inst.seg_static_inst.CNT_MAX =100;
seg_595_static seg_595_static_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.stcp (stcp),
.shcp (shcp),
.ds (ds),
.oe (oe )
);
endmodule
综合方正结果:
与我们所想的基本一致
上板验证:
给开发板上电,绑定FPGA管脚,下载成功后,开发板数码管六位会依次从111111到FFFFFF循环。
总结:
经过对这个实验的流程,系统层次化设计有一个深刻的感悟 !文章来源:https://www.toymoban.com/news/detail-769152.html
文章来源地址https://www.toymoban.com/news/detail-769152.html
到了这里,关于FPGA基本实验之数码管的静态显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!