FPGA 26,数码管动态显示,解析与实现( 使用 Xilinx Vivado 实现数码管动态显示 )
目录
前言
一. 基本原理
1.1 数码管的结构
1.2 动态显示原理
二. 设计流程
三. 代码实现
1.show.v 模块
2. seg.v 模块
四. 段选位选
4.1 段选信号
4.2 位选信号
五. 注意事项
六. 文本总结
七. 更多操作
前言
数码管是电子设备中常见的显示组件,广泛应用于时钟、计数器、温度计等设备中。数码管显示分为静态显示和动态显示两种方式。静态显示简单直接,但占用资源较多;动态显示通过分时复用技术,能够以较少的硬件资源,实现多位数字的显示。上期分享了数码管的静态显示,这里来详细介绍如何使用Verilog HDL实现数码管的动态显示,并结合代码进行详细讲解。
看下实现的数码管动态显示效果:
一. 基本原理
数码管动态显示,通常涉及将多个数码管逐个点亮,而不是同时点亮所有数码管。这意味着在任何给定时间,实际上只有一个数码管是亮着的。它是通过高速切换各个数码管的显示内容,使人眼感觉所有的数码管都在同时显示不同的数字。
1.1 数码管的结构
数码管通常由多个发光二极管(LED)组成,分为共阴极和共阳极两种类型:
-
共阴极:所有LED的阴极连接在一起,阳极分别控制。
-
共阳极:所有LED的阳极连接在一起,阴极分别控制。
1.2 动态显示原理
数码管的动态显示,通过快速切换数码管的位选信号,依次点亮每个数码管,并显示对应的数字。由于切换速度非常快(通常几十毫秒),人眼无法察觉到闪烁,从而看到稳定的显示效果。这里实际上利用的就是人的视觉暂留效应。
视觉暂留科学实验证明,人眼在某个视像消失后,仍可使该物像在视网膜上滞留0.1 - 0.4秒左右。因此当切换各个数码管显示内容足够快的时候,你可以同时看到它们的显示内容,达到一个所有数码管常亮的效果。
二. 设计流程
1. 设计思路
数码管动态显示,设计思路如下
-
数据拆分:将需要显示的数字拆分为个位、十位、百位和千位。
-
状态机设计:使用状态机控制数码管的显示顺序,每个状态对应一个数码管。
-
延时控制:每个数码管显示一段时间(如1ms),然后切换到下一个数码管。
-
段选信号生成:根据当前显示的数字生成对应的段选信号。
-
位选信号控制:通过位选信号选择当前显示的数码管。
整体流程就是首先将4位数据进行拆分,分别拆分为个,十,百,千,四个数据。然后,通过状态机设计1ms显示切换,第一毫秒时,将个位数据进行显示,第二毫秒时,将十位数据进行显示,第三毫秒时,将百位数据进行显示,第四毫秒时,将千位数据进行显示,依次进行切换。
2. 模块划分
数码管动态显示设计,主要分为 show.v
和 seg.v
两个模块,每个模块负责不同的功能,协同工作以实现稳定的多位数字显示。
show.v
模块
- 功能:根据输入的数字生成对应的段选信号。
- 输入:4位宽的数字。
- 输出:8位宽的段选信号。
seg.v
模块
- 功能:控制数码管的动态显示,调用 show.v 模块生成段选信号。
- 输入:时钟信号和复位信号。
- 输出:位选信号和段选信号。
三. 代码实现
以下是完整的Verilog代码实现,包含详细的注释:
1.show.v
模块
show.v
模块负责根据输入的数字生成对应的段选信号,用于控制数码管的显示。
`timescale 1ns / 1ps
// 静态数码管显示模块
module show(
input clk, // 时钟信号
input rst_n, // 复位信号,低电平有效
input [3:0] number, // 输入的数字,4位宽,范围0-9
output reg [7:0] seg // 数码管段选信号,8位宽,控制数码管的各段
);
assign dig = 4'b0000; // 数码管位选信号,共阴极数码管,此处设置为全低电平(选中所有数码管)
always @(*) begin
case (number) // 根据输入的数字选择对应的段选信号
0: seg = 8'hfc; // 数字0对应的段选信号
1: seg = 8'h60; // 数字1对应的段选信号
2: seg = 8'hda; // 数字2对应的段选信号
3: seg = 8'hf2; // 数字3对应的段选信号
4: seg = 8'h66; // 数字4对应的段选信号
5: seg = 8'hb6; // 数字5对应的段选信号
6: seg = 8'hbe; // 数字6对应的段选信号
7: seg = 8'he0; // 数字7对应的段选信号
8: seg = 8'hfe; // 数字8对应的段选信号
9: seg = 8'hf6; // 数字9对应的段选信号
default: seg = 8'hfc; // 默认显示数字0
endcase
end
endmodule
代码说明:
-
输入信号:
-
clk
:时钟信号。 -
rst_n
:复位信号,低电平有效。 -
number
:4位宽的数字输入,范围是0-9。
-
-
输出信号:
-
seg
:8位宽的段选信号,用于控制数码管的各段显示。
-
-
段选信号:
-
根据输入的数字
number
,生成对应的段选信号seg
。 -
例如,
8'hfc
表示数码管的 a、b、c、d、e、f 段亮,g 和 dp 段灭,显示数字0。
-
-
默认值:
-
如果
number
的值不在0-9范围内,默认显示数字0。
-
2. seg.v
模块
seg.v
模块负责控制数码管的动态显示,通过状态机依次显示个位、十位、百位和千位数字。
`timescale 1ns / 1ps
module seg(
input clk, // 时钟信号
input rst_n, // 复位信号,低电平有效
output reg [3:0] dig, // 位选信号,控制数码管的位选
output [7:0] seg // 段选信号,控制数码管的段选
);
// 定义常量
parameter show_number = 1234; // 要显示的数字
parameter delay_1ms = 50_000; // 1ms 延迟对应的时钟周期数
// 定义状态编码
parameter idle = 5'b0_0001, // 空闲状态
s0 = 5'b0_0010, // 显示个位
s1 = 5'b0_0100, // 显示十位
s2 = 5'b0_1000, // 显示百位
s3 = 5'b1_0000; // 显示千位
// 计算各位数字
wire [3:0] number0 = show_number % 10; // 个位
wire [3:0] number1 = (show_number / 10) % 10; // 十位
wire [3:0] number2 = (show_number / 100) % 10; // 百位
wire [3:0] number3 = show_number / 1000; // 千位
// 状态寄存器
reg [4:0] cur_state, next_state;
// 1ms 计数器
reg [15:0] cnt_1ms;
// 当前显示的数字
reg [3:0] number;
// 状态转移逻辑
always @(posedge clk) begin
if (!rst_n)
cur_state <= idle; // 复位时进入空闲状态
else
cur_state <= next_state; // 更新当前状态
end
// 状态机逻辑
always @(*) begin
case (cur_state)
idle: begin
next_state = s0; // 空闲状态后进入显示个位状态
end
s0: begin
if (cnt_1ms == delay_1ms - 1)
next_state = s1; // 1ms 后进入显示十位状态
else
next_state = s0;
end
s1: begin
if (cnt_1ms == delay_1ms - 1)
next_state = s2; // 1ms 后进入显示百位状态
else
next_state = s1;
end
s2: begin
if (cnt_1ms == delay_1ms - 1)
next_state = s3; // 1ms 后进入显示千位状态
else
next_state = s2;
end
s3: begin
if (cnt_1ms == delay_1ms - 1)
next_state = s0; // 1ms 后回到显示个位状态
else
next_state = s3;
end
default: next_state = s0; // 默认回到显示个位状态
endcase
end
// 位选和数字选择逻辑
always @(posedge clk) begin
if (!rst_n) begin
dig <= 4'b1111; // 复位时关闭所有数码管
number <= 0;
end else begin
case (cur_state)
idle: begin
dig <= 4'b1111; // 空闲状态关闭所有数码管
number <= 0;
end
s0: begin
dig <= 4'b1110; // 选择个位数码管
number <= number0; // 显示个位数字
end
s1: begin
dig <= 4'b1101; // 选择十位数码管
number <= number1; // 显示十位数字
end
s2: begin
dig <= 4'b1011; // 选择百位数码管
number <= number2; // 显示百位数字
end
s3: begin
dig <= 4'b0111; // 选择千位数码管
number <= number3; // 显示千位数字
end
default: begin
dig <= 4'b1111; // 默认关闭所有数码管
number <= 0;
end
endcase
end
end
// 1ms 计数器逻辑
always @(posedge clk) begin
if (!rst_n)
cnt_1ms <= 0; // 复位时计数器清零
else begin
case (cur_state)
s0, s1, s2, s3: begin
if (cnt_1ms == delay_1ms - 1)
cnt_1ms <= 0; // 达到 1ms 后计数器清零
else
cnt_1ms <= cnt_1ms + 1; // 计数器加 1
end
default: cnt_1ms <= 0; // 其他状态计数器清零
endcase
end
end
// 实例化数码管显示模块
show show_u(
.clk (clk),
.rst_n (rst_n),
.number (number),
.seg (seg)
);
endmodule
代码说明:
-
输入信号:
-
clk
:时钟信号。 -
rst_n
:复位信号,低电平有效。
-
-
输出信号:
-
dig
:4位宽的位选信号,控制数码管的位选。 -
seg
:8位宽的段选信号,控制数码管的段选。
-
-
状态机设计:
-
使用状态机控制数码管的显示顺序,依次显示个位、十位、百位和千位。
-
每个状态对应一个数码管,显示时间为1ms。
-
-
数字拆分:
-
将需要显示的数字拆分为个位、十位、百位和千位,分别存储在
number0
、number1
、number2
和number3
中。
-
-
延时控制:
-
使用计数器实现1ms的延时,确保每个数码管显示时间一致。
-
-
实例化
show
模块:-
调用
show
模块,根据当前数字生成段选信号。
-
show.v 和 seg.v 这两个模块共同实现了数码管的动态显示功能。show.v 模块将输入的数字转换为段选信号,控制数码管各段的亮灭。seg.v 模块通过状态机依次选择数码管,并调用 show.v 生成段选信号,实现动态显示。两个模块协作,高效完成多位数字的稳定显示。
四. 段选位选与引脚绑定
段选信号和位选信号,是数码管显示设计中的关键控制信号。段选信号,通过控制数码管的各段亮灭来决定显示的内容,而位选信号,则用于选择当前显示的数码管。
4.1 段选信号
段选信号控制数码管各段(a、b、c、d、e、f、g、dp)的亮灭,决定显示的数字或字符。它是一个8位二进制信号,每位对应一段,通过不同编码显示0-9等字符。
以下是段选信号的引脚定义:
-
U15-a:段a
-
W15-b:段b
-
U17-c:段c
-
V18-d:段d
-
W18-e:段e
-
U19-f:段f
-
U14-g:段g
-
Y14-dp:小数点
4.2 位选信号
位选信号用于选择当前显示的数码管。在动态显示中,多个数码管共享段选信号后,通过位选信号依次选择每个数码管。它是一个4位二进制信号,每位对应一个数码管,快速切换实现稳定显示。
以下是位选信号的引脚定义:
-
P15-W1:数码管1
-
V15-W2:数码管2
-
V17-W3:数码管3
-
V18-W4:数码管4
段选: U15-a W15-b U17-c V18-d W18-e U19-f U14-g Y14-dp
位选: P15-W1 V15-W2 V17-W3 V18-W4
五. 注意事项
时钟频率:代码中的
delay_1ms
需要根据实际时钟频率进行调整,以确保1ms的延时准确。复位信号:复位信号
rst_n
为低电平有效,复位时应将所有状态和计数器清零。数码管类型:代码中默认使用共阴极数码管,如果使用共阳极数码管,需要调整位选和段选信号的逻辑。
段选信号定义:段选信号
seg
的具体值需要根据数码管的段选编码表进行调整,确保显示正确。资源占用:动态显示虽然节省了硬件资源,但需要较高的切换频率,可能会增加功耗。
六. 文本总结
本文详细介绍了如何使用Verilog实现数码管的动态显示,通过状态机控制数码管的显示顺序,并结合延时计数器实现稳定的显示效果。动态显示技术不仅节省了硬件资源,还能够实现多位数字的显示,是数字电路设计中的常用技术。希望这里的内容,能够帮助你更好地理解和应用数码管动态显示技术。
七. 更多操作
完整FPGA系列,请看
FPGA系列,文章目录https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501