赞
踩
此实验基于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 是一个 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控制功能;
第三部分:实现顶层设计模块的综合。
首先介绍一下程序中的几个变量所代表的含义:
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

程序中的一些变量所表示的含义:
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循环。
经过对这个实验的流程,系统层次化设计有一个深刻的感悟 !
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。