实验描述:
一、实验目的
1. 学习动态扫描显示数码管的使用。
2. 学习数据选择器及其信号分配方法。
3. 巩固 Verilog HDL 层次化设计电路的方法。
二、基本实验内容
多位数码管的显示电 路如果每一位都单独连接 到驱动(控制)器上,需要 非常多的引脚和布线通道, 实际使用中,为了降低成本、 方便 PCB 布局布线,常使用 动态显示数码管。 右图是 1 种 4 位共阴型 数码管的引脚图。
A,B,C,D,E,F,G,DP 是段选 (行)引脚,
SEG1,SEG2,SEG3,SEG4 是 位选(列)引脚。 对于共阴型数码管,段 信号是高电平有效,位选信 号是低电平有效。整个数码管共用同一组段信号(引脚)。实验室所用的数字电路实验箱上, 数码管的位选信号经过一个 NPN 型三极管放大驱动能力之后连接到数码管的位选引脚,信 号被三极管反相,因此,进行 FPGA 程序设计时位选信号应设计成高电平有效。数码管的 驱动信号时序图可参考下图。 段信号 Data1 Data2 Data3 Data4 Data1 … SEG1 SEG2 SEG3 SEG4 4 位动态扫描显示数码管驱动信号时序图
4 位动态扫描显示数码管的位选信号可看作是 4 相时钟,占空比 25%,位选信号为高电 平时将需要显示的数据送到数码管译码器上译码,再将译码输出送到数码管的段信号。 从上述时序图可以看出,在 SEG1 为高电平时,SEG1 位数码管被选中驱动,Data1 被 送到 7 段译码器中译码,此时数码管的 SEG1 位显示 Data1 的数值,其它几位数码管不亮; 在下一个时钟相位,SEG2 为高电平,SEG2 显示 Data2 的数据…在第四个时钟相位 SEG4
显示 Data4 之后,一个显示周期结束,电路将开始下一个显示周期。由于人眼的视觉暂留,
西南交通大学 电子技术实验室
当 SEG 位选信号切换得足够快(100Hz 以上),在人眼看来,数码管的所有位都同时点亮。 使用可编程芯片(FPGA/CPLD)控制多位动态扫描数码管显示时,一般需要使用计数 器、译码器等模块电路,电路原理可参考下图“4 位动态扫描数码管显示驱动电路框图”。
Data1,Data2,Data3,Data4 为 BCD 码数据,对应数码管上显示的千、百、十、个位显示的数 值。“位信号驱动电路”和“7 段数码管”是可编程芯片之外的单独电路元件,其余部分都 需要编程实现,为了获得频率 1000Hz 左右的扫描时钟,还需要设计一个前置分频器,将
50MHz 的系统时钟分频。
注意,因为位信号驱动电路和数码管的切换速度都不高,一般最高只能几 kHz,所以 扫描时钟频率并非越高越好,否则数码管的亮度可能会降低,甚至显示错误。
扫描时钟 Data4 Data3 Data2 Data1 4选1数据选择器 7段译码器
7段数码管 2-4线译码器 位信号驱动电路 模4计数器 约1000Hz
实验要求: 用 Verilog HDL 设计一个 3 位数码管动态扫描显示电路,在实验箱的数码管上固定显示 显示自己学号的后 3 位数(学号后 3 位全 0 则显示 321)。采用层次化设计方法,只能调用 1
个 7 段译码器。
三、提高性实验
1. 在基本实验内容的基础上,增加一个功能切换控制开关,切换功能后,数码管显示 的数字可以自动循环移位。
2. 其它显示功能。
四、预习要求
1. 简要写出电路设计思路。
2. 完成实验程序代码编写。
3. 用 ModelSim 对实验电路进行功能仿真,并将仿真结果截图。除了观察输出引脚上 的电平,还应该观察中间信号——数据选择器的输出 Y,确保所有信号都是正确的 再进行下一步实验。
4. 列出引脚锁定分配表(信号名->主板器件名->引脚号),实验箱上的数码管段信号 命名为小写字母,位信号命名是 SEG0~SEG7。
五、实验报告要求
1. 列出关键程序代码。
2. 附 Quartus 生成的 RTL 图(菜单 Tools -> Netlist Viewers –>RTL)。
3. 附仿真测试波形。
4. 列出实验过程出现的问题及解决措施。
5. 附源程序(截图)
思路:
1. 连接外部信号:连接包括时钟信号clk、复位信号rstn,以及从模块输出的七段数码管的段选信seg、选择信号sel、显示输出值tub和控制信号con。
2. 操作控制:根据需要,通过更改控制信号con的值来选择不同的数字进行显示。具体的操作如下:
(1)初始状态下,con为0。
(2)通过递增con的值,由高位到低位切换要显示的数字。每次递增con时,选择信号sel 和显示值tub会根据con的值更新。具体操作是:
①当con为0时,选择信号sel为3'b100(对应第一个数码管),显示值tub为4'd9。
②当con为1时,选择信号sel为3'b010(对应第二个数码管),显示值tub为4'd0。
③当con为2时,选择信号sel为3'b001(对应第三个数码管),显示值tub为4'd2。
④当con` 超过2时,控制信号con会被重置为0,并标志位flag会设置为1(flag的作用是复位的时候con从0开始而不是1开始),以开始下一个循环。
3. 七段数码管显示:模块会根据sel和tub的值选择要在数码管上显示的数字。具体的显示值已经在代码中定义,通过case语句进行匹配,将seg设置为相应的七段数码管段选信号,以显示正确的数字。
4. 复位功能:在系统初始化或复位时,确保复位信号rstn为低电平。这会将所有输出信号复位为零,以确保初始化状态。
5. 时钟信号生成:模块内部的计数器cnt会生成1kHz的时钟信号clk1k用于控制数码管的刷新。
代码:
上板子的代码:
module qwq(
input clk,
input rstn,
output reg [6:0] seg, // 数码管
output reg [7:0] sel, // 选择位数
output reg [3:0] tub, // 输出的数
output reg [1:0] con // 控制赋值哪位
);
reg [31:0] cnt; // 16位寄存器,用于计数
reg clk1k; // 时钟信号,1kHz的时钟
reg flag;
reg [3:0] k1 = 4'd9;
reg [3:0] k2 = 4'd0;
reg [3:0] k3 = 4'd2;
always @ (posedge clk or negedge rstn) // 时钟上沿或下沿
begin
if (!rstn) // 如果复位信号为低电平
begin
cnt <= 0; // 计数器复位为0
clk1k <= 0; // 1kHz时钟信号复位为低电平
end
else if (cnt >= 24999999) // 如果计数达到24999(1kHz频率下1秒的计数值)
begin
clk1k <= !clk1k; // 切换1kHz时钟信号的状态
cnt <= 0; // 计数器复位为0
end
else
cnt <= cnt + 1; // 计数器递增
end
always @ (posedge clk1k or negedge rstn)
begin
if (!rstn) // 如果复位信号为低电平
begin
tub <= 0; // 七段数码管显示值复位为0
con <= 0; // 控制信号复位为0
sel <= 0; // 选择信号复位为0
seg <= 0; // 段选信号复位为0
flag <= 0;
end
else
begin
if (con < 2 && flag == 1)
con = con + 1'd1; // 控制信号递增
else
begin
con = 0; // 控制信号复位为0
flag = 1'd1;
end
case(con) // 根据控制信号值进行不同的操作
2'b00:begin sel = 8'b0000_0100;tub = k1;end
2'b01:begin sel = 8'b0000_0010;tub = k2;end
2'b10:begin sel = 8'b0000_0001;tub = k3;end
endcase
//调用数码管
case(tub) // 根据七段数码管显示值进行不同的操作
4'd0: seg = 7'b1111110;
4'd1: seg = 7'b0110000;
4'd2: seg = 7'b1101101;
4'd3: seg = 7'b1111001;
4'd4: seg = 7'b0110011;
4'd5: seg = 7'b1011011;
4'd6: seg = 7'b1011111;
4'd7: seg = 7'b1110000;
4'd8: seg = 7'b1111111;
4'd9: seg = 7'b1111011;
default: seg = 7'b0000001; // 将大于9的数显示为-负号
endcase
end
end
endmodule
modelsim代码:
`timescale 1ns/1ns // 定义时间单位,1ns为仿真时间单位,10ns为仿真时间精度
module emm();
reg clk; // 时钟信号
reg rstn; // 同步复位信号
wire [6:0] seg; // 7位数码管的段选信号
wire [7:0] sel; // 3位数码管的选择信号
wire [3:0] tub; // 4位七段数码管显示的值
wire [1:0] con; // 控制信号
wire [11:0] number;
initial
begin
clk = 1'b0; // 初始化时钟为低电平
rstn = 1'b0; // 初始化同步复位信号为低电平
#100 // 延时100个时间单位(1ns),持续100ns
rstn = 1'b1; // 同步复位信号变为高电平
// #10000 // 延时100000个时间单位(1ns),持续100ns
// rstn = 1'b0; // 同步复位信号重新变为低电平
// #10000 // 延时100000个时间单位(1ns),持续100ns
// rstn = 1'b1; // 同步复位信号重新变为低电平
end
always #(1) clk = ~clk; // 时钟信号每1ns翻转一次,周期为2ns,频率为50MHz
qwq dfun(
.clk(clk),
.rstn(rstn),
.seg(seg),
.sel(sel),
.tub(tub),
.con(con),
.number(number)
);
endmodule