1、数码管组成
数码管通常由七个发光二极管(LED)和一个或多个额外的 LED(用于显示小数点)组成。这些 LED 排列成数字“8”的形状,通过不同的点亮组合显示 0 到 9 的数字。
2、数码管内部电路图
数码管一般分为 共阳 和 共阴 两种。共阳 数码管是将内部所有 LED 的正极连接在一起就组成的 共阳 数码管。反正将所有的负极都连接就成了 共阴 数码管。我们 逻辑派 使用的数码管为共阳,其内部电路图如下所示:
3、数码管原理图
逻辑派 上搭载了一个一位数码管,每个端口都有一个 510Ω 的限流电阻,数码管的所有引脚如下图所示:
4、实战任务
设计一个 FPGA 控制系统,用于驱动一个共阳数码管,实现数字从 0 到 9 的循环显示。系统需要确保每个数字在数码管上显示 1 秒,之后自动切换到下一个数字。整个显示过程应重复进行,以形成一个从 0 到 9 的循环展示。
5、系统框图
根据实验任务分析我们需要实现的功能是使用输入时钟,一个复位按键,一个八位数码管输出显示。
因此,本实验需要两个输入端口:系统时钟和系统复位,输出端口为一个八位共阳数码管,模块框图如下图所示:
6、时序图
因为我们是共阳数码管,低电平有效。根据 0 到 9 段选信号显示,我们绘制出如下波形图:
上图可知,count 循环从 0 计数到 49_999_999,表示计时 1s 到了,数码管的显示内容将从当前数字切换到下一个数字。数字的切换是循环进行的,即在显示到数字 9 后,下一个数字将重新显示为 0,形成一个从 0 到 9 的循环展示。这样,数码管将每秒钟依次显示从 0 到 9 的数字,实现连续的数字循环显示效果。
7、程序编写
数码管显示 (seg.v) 代码编写如下:
module seg(
input sys_clk, //全局时钟
input sys_rst_n, //全局复位,低电平有效
output reg [7:0] seg //数码管输出定义
);
reg [25:0] count; //计数器
reg [3:0] number; // 数码管位数定义
parameter Scends = 50_000_000; // 1S 所需的脉冲
//parameter Scends = 50; // 用于仿真
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
count <= 26'd0;
else if(count < Scends - 26'd1)
count <= count + 26'd1;
else
count <= 26'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
number <= 4'd0;
else if(count == Scends - 25'd2) begin
number <= number + 4'd1; //每到 1S 将显示位数加一
if(number == 4'd9) //计数到 九 然后清零
number <= 4'd0;
end
else
number <= number;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
seg <= 8'hC0; //清理 零
else begin
case(number) // 根据number的值选择对应的7段显示编码
4'd0: seg <= 8'hC0; // 显示数字0
4'd1: seg <= 8'hF9; // 显示数字1
4'd2: seg <= 8'hA4; // 显示数字2
4'd3: seg <= 8'hB0; // 显示数字3
4'd4: seg <= 8'h99; // 显示数字4
4'd5: seg <= 8'h92; // 显示数字5
4'd6: seg <= 8'h82; // 显示数字6
4'd7: seg <= 8'hF8; // 显示数字7
4'd8: seg <= 8'h80; // 显示数字8
4'd9: seg <= 8'h90; // 显示数字9
default: ; // 默认情况下不进行任何操作
endcase
end
end
endmodule
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
代码解析:
第 26 - 36 行:是一个简单的定时功能,每当定时时间达到 1S ,计数器 number(数码管显示值) 会增加,并在达到上限时重置为零,从而达到循环。
第 38 - 58 行:我们选择一个状态机来执行,数码管 0 - 9 的数字显示界面,在系统复位时,数码管显示 0,在正常工作时,根据 number 的值选择显示相应的数字。
8、仿真编写
数码管显示仿真 (seg_mod.v) 代码编写如下:
`timescale 10ns/10ns // 设置仿真时间单位和时间精度为 1 纳秒
module seg_mod(); // 定义测试模块
//reg define
reg sys_clk; // 全局系统时钟信号
reg sys_rst_n; // 全局复位信号(低电平有效)
//wire define
wire [7:0]seg; // 位宽 8 位 数码管输出信号
always #10 sys_clk = ~sys_clk; // 每 10ns 生成一个时钟周期
initial begin
sys_clk = 1'd0;
sys_rst_n = 1'd0; //将时钟和服务置零
#200;
sys_rst_n = 1'd1; //将复位拉高,准备进入正常工作模式
end
seg u_seg(
.sys_clk(sys_clk), // 将测试模块的 sys_clk 连接到被测模块的时钟输入
.sys_rst_n(sys_rst_n), // 将测试模块的复位信号连接到被测模块的复位输入
.seg(seg) // 将被测模块的 seg 输出连接到测试模块的 seg 端口
);
endmodule
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
代码解析:
- 第 27 - 34 行:将仿真文件的端口与数码管程序的端口进行绑定。
接下来打开 Modelsim 软件对代码进行仿真,需要添加文件如下图所示:
运行仿真一段时间后,仿真的波形如下图所示:
从波形图中我们可以看出,seg 的波形从 0XC0 变化到 0X90 ,这对应我们共阳数码管的段码,正好是从 0 到 9 ,实现了循环显示。说明仿真和我们想的一致,说明程序没有问题。
9、I/O 引脚绑定
进行 I/O 约束,这里只需要对 clk 、 reset_n 和 数码管 8 个引脚进行约束,管脚分配如下表所示:
信号 | 方向 | 引脚 | 端口作用 | 电平标准 |
---|---|---|---|---|
sys_clk | input | T7 | 时钟 | LVCMOS33 |
sys_rst_n | input | F10 | 复位 | LVCMOS33 |
seg[0] | output | G13 | A | LVCMOS33 |
seg[1] | output | H16 | B | LVCMOS33 |
seg[2] | output | H12 | C | LVCMOS33 |
seg[3] | output | H13 | D | LVCMOS33 |
seg[4] | output | H14 | E | LVCMOS33 |
seg[5] | output | G12 | F | LVCMOS33 |
seg[6] | output | G11 | G | LVCMOS33 |
seg[7] | output | L14 | DP | LVCMOS33 |
Gowin 软件中 I/O Constraints 界面如下图所示:
10、程序下载
连接开发板的下载器,将码流文件下载到开发板后,数码管会从 0 开始依次显示到 9,然后重新从 0 开始,实现了从 0 到 9 的循环显示,达成了我们的任务目标。