实验二:数码管动态显示实验_数码管显示实验
实验二 数码管动态显示实验报告
目录
- 实验目的
- 实验内容
- 原理描述
- Verilog HDL设计源代码
- Testbench仿真代码及仿真结果
- XDC文件配置
- 下板测试
- 实验体会
- 实验视频与图片
实验目的
- 设计具有异步复位、同步置数(可选)的十进制计数器(模值为学号后3位),并利用数码管动态显示计数值,实现一个秒计数器功能,数字每加一即为一秒。
实验内容
原理描述
本实验采用层次化设计思想,分为三个主要模块:
- 十进制计数器:具有异步复位和可选同步置数功能,模值为学号后三位(如145)。
- 二进制转BCD(bintobcd8):将二进制计数值转换为BCD码,为数码管显示做准备。采用“左移加三法”实现。
- 数码管显示模块(scan_seg_disp):实现多位数码管的动态扫描显示。通过快速轮流点亮各位,实现人眼滞留下的多位数同显。
由于FPGA系统时钟较高(100MHz),需要设计分频电路,使计数器每1秒自增一次,并用动态扫描方式刷新显示。
Verilog HDL设计源代码
`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Module Name: counter_// Description: 秒计数器,模值为145,数码管动态显示//////////////////////////////////////////////////////////////////////////////////module counter_( input rst, clk, en, // 异步复位、时钟、计数使能 output [6:0] sseg, // 数码管段选 output [7:0] an // 数码管位选); wire [3:0] one, ten, hun; reg [7:0] bin; reg [26:0] count; // 分频计数器 reg s_pulse; // 秒脉冲 always @(posedge clk or negedge rst) if (!rst) begin bin <= 0; count <= 0; end else if (en) begin count <= count + 1; if (count == 100_000_000 - 1) // 1秒 count <= 0; if (count == 0) s_pulse <= 1; else s_pulse <= 0; if (s_pulse) begin if (bin == 145) bin <= 0; else bin <= bin + 1; end end // 实例化二进制转BCD bintobcd8 bintobcd_1( .clk(clk), .rst(rst), .bin(bin), .one(one), .ten(two), .hun(three) ); // 实例化数码管显示 scan_seg_disp scan_seg_disp_1( .clk(clk), .rst(rst), .one(one), .ten(two), .hun(three), .an(an), .sseg(sseg) );endmodule// 二进制转BCD模块module bintobcd8( input clk, rst, input [7:0] bin, output reg [3:0] one, ten, hun); reg [17:0] shift_reg; reg [3:0] count; always @(posedge clk or negedge rst) if (!rst) begin one = 0; ten = 0; hun = 0; shift_reg = 0; count = 0; end else begin if (count == 0) shift_reg = {10\'d0, bin}; if (count 4) shift_reg[11:8] = shift_reg[11:8] + 2\'b11; if (shift_reg[15:12] > 4) shift_reg[15:12] = shift_reg[15:12] + 2\'b11; shift_reg[17:1] = shift_reg[16:0]; end else if (count == 4\'d8) begin one = shift_reg[11:8]; ten = shift_reg[15:12]; hun = {2\'b00, shift_reg[17:16]}; count = count + 1; end else count = count - 9; endendmodule// 数码管动态扫描模块module scan_seg_disp ( input clk, rst, input [3:0] one, ten, hun, output reg [7:0] an, output reg [6:0] sseg); localparam N=20; reg [N-1:0] cnt; reg [3:0] hex; always @(posedge clk or negedge rst) begin if (!rst) begin cnt = 0; hex = 4\'d10; end else begin cnt = cnt + 1; case (cnt[N-1:N-2]) 2\'b00: begin hex = one; an = 8\'b11111110; end 2\'b01: begin hex = ten; an = 8\'b11111101; end 2\'b11: begin hex = hun; an = 8\'b11111011; end endcase end end always @(*) begin case(hex) 4\'h0: sseg[6:0] = 7\'b0000001; 4\'h1: sseg[6:0] = 7\'b1001111; 4\'h2: sseg[6:0] = 7\'b0010010; 4\'h3: sseg[6:0] = 7\'b0000110; 4\'h4: sseg[6:0] = 7\'b1001100; 4\'h5: sseg[6:0] = 7\'b0100100; 4\'h6: sseg[6:0] = 7\'b0100000; 4\'h7: sseg[6:0] = 7\'b0001111; 4\'h8: sseg[6:0] = 7\'b0000000; 4\'h9: sseg[6:0] = 7\'b0000100; default: sseg[6:0] = 7\'b1111111; endcase endendmodule
Testbench仿真代码及仿真结果
`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Module Name: test// Description: counter_模块仿真//////////////////////////////////////////////////////////////////////////////////module counter__tb(); reg clk, rst, en; wire [6:0] sseg; wire [7:0] an; counter_ dut( .clk(clk), .rst(rst), .en(en), .sseg(sseg), .an(an) ); initial begin clk = 0; forever #10 clk = ~clk; end initial begin rst = 0; en = 0; #10 en = 1; #100 rst = 1; #200000000 en = 0; #1000 en = 1; #1000 $finish; endendmodule
- 第一秒、第二秒仿真波形:见仿真结果截图
XDC文件配置
set_property IOSTANDARD LVCMOS33 [get_ports {an[7]}]set_property IOSTANDARD LVCMOS33 [get_ports {an[6]}]set_property IOSTANDARD LVCMOS33 [get_ports {an[5]}]set_property IOSTANDARD LVCMOS33 [get_ports {an[4]}]set_property IOSTANDARD LVCMOS33 [get_ports {an[3]}]set_property IOSTANDARD LVCMOS33 [get_ports {an[2]}]set_property IOSTANDARD LVCMOS33 [get_ports {an[1]}]set_property IOSTANDARD LVCMOS33 [get_ports {an[0]}]set_property IOSTANDARD LVCMOS33 [get_ports {sseg[6]}]set_property IOSTANDARD LVCMOS33 [get_ports {sseg[5]}]set_property IOSTANDARD LVCMOS33 [get_ports {sseg[4]}]set_property IOSTANDARD LVCMOS33 [get_ports {sseg[3]}]set_property IOSTANDARD LVCMOS33 [get_ports {sseg[2]}]set_property IOSTANDARD LVCMOS33 [get_ports {sseg[1]}]set_property IOSTANDARD LVCMOS33 [get_ports {sseg[0]}]set_property PACKAGE_PIN J17 [get_ports {an[0]}]set_property PACKAGE_PIN J18 [get_ports {an[1]}]set_property PACKAGE_PIN T9 [get_ports {an[2]}]set_property PACKAGE_PIN J14 [get_ports {an[3]}]set_property PACKAGE_PIN P14 [get_ports {an[4]}]set_property PACKAGE_PIN T14 [get_ports {an[5]}]set_property PACKAGE_PIN K2 [get_ports {an[6]}]set_property PACKAGE_PIN U13 [get_ports {an[7]}]set_property PACKAGE_PIN E3 [get_ports clk]set_property PACKAGE_PIN T8 [get_ports rst]set_property PACKAGE_PIN L18 [get_ports {sseg[0]}]set_property PACKAGE_PIN K13 [get_ports {sseg[3]}]set_property PACKAGE_PIN K16 [get_ports {sseg[4]}]set_property PACKAGE_PIN R10 [get_ports {sseg[5]}]set_property IOSTANDARD LVCMOS33 [get_ports clk]set_property IOSTANDARD LVCMOS33 [get_ports rst]set_property PACKAGE_PIN T10 [get_ports {sseg[6]}]set_property PACKAGE_PIN T11 [get_ports {sseg[1]}]set_property PACKAGE_PIN P15 [get_ports {sseg[2]}]set_property IOSTANDARD LVCMOS33 [get_ports en]set_property PACKAGE_PIN R13 [get_ports en]
下板测试
- 复位(T8):低电平为异步复位
- 开关控制(R13):随时控制计数器起止
- 计数显示:数码管动态显示,从0计数到145,循环
- 演示视频:见附件“数码管演示视频.mp4”
- 暂停后再开始:计数可暂停和继续
- 达到145后变为0,继续循环
实验体会
在实验前需要把理论知识弄清楚,心中有知识体系,要不然听课也会一头雾水,在写代码前要把思路捋清楚,想要实现一个什么功能,需要有什么,怎么可以得到。学会层次化设计,这样会使思路更清晰。
刚开始写代码时不知道计数器的工作原理,把老师的计数器原理代码复制运行研究。下班测试发现一直都是00,就感觉是因为时钟信号太快了,无法看到,所以又加了
if(count % 10000000 == 0) q <=q+1;发现还是不可以,就给代码加了一个分频,就可以正常运行了。加分频前:module counter_( input [3:0] data, input reset_n, clk,en,load, output reg [3:0] q);reg count; always@(posedge clk, negedge reset_n) if (!reset_n) // 异步复位 q<=0; else if (load) // 同步加载数据data q<=data; else if (en) // 若load=0在en控制下计数 begin count <= count + 1; if(count % 10000000 == 0) q <=q+1; endEndmodule加分频后:module counter_( input [3:0] data, input reset_n, clk,en,load, output reg [3:0] q);reg [26:0]count;reg s_pulse; always@(posedge clk, negedge reset_n) if (!reset_n) begin // 异步复位 q<=0; count <= 0; end else if (load) // 同步加载数据data q<=data; else if (en) // 若load=0在en控制下计数 begin count <= count + 1; if(count == 100000000 -1) begin count <= 0; end if(count == 0)begin s_pulse <= 1; end else begin s_pulse <= 0; end if(s_pulse) begin if(q == 15) begin q <= 0; end else begin q <= q + 1; end endendEndmodule
管脚:
利用led灯来查看数是否正常每秒加一。这里实现的有置数功能。
上板:
有演示视频,名字是“测试视频”
将U18和R13拉高置数:
将R13拉低,T8拉高,开始计数:
综上,我们需要多思考,多测试,学会把一个大任务拆分,一个一个解决。