顶层代码:
module HXE_top(Clk,Rst_n,SH_CP,ST_CP,DS);
input Clk; //50M
input Rst_n;
output SH_CP;
output ST_CP;
output DS;
wire[31:0]disp_data;
wire [7:0] sel;//数码管位选(选择当前要显示的数码管)
wire [6:0] seg;//数码管段选(当前要显示的内容)
hex_data hex_data( //调用ISSP调试,列化文件
.probe(),
.source(disp_data)
);
HC595_Driver HC595_Driver(
.Clk(Clk),
.Rst_n(Rst_n),
.Data({1'd0,seg,sel}),
.S_EN(1'b1),
.SH_CP(SH_CP),
.ST_CP(ST_CP),
.DS(DS)
);
HXE8 HXE8(
.Clk(Clk),
.Rst_n(Rst_n),
.En(1'b1),
.disp_data(disp_data),
.sel(sel),
.seg(seg)
);
endmodule
工程代码
输入:Clk(时钟),Rst_n(复位信号),En(数码管使能信号),disp_data(8位数码管显示值,每位对应一个数码管,16进制,一个16进制数算占4位,所以有32位)
输出:sel(选取哪段数码管显示),seg(sel选取后对应数码管后显示的数字内容)
module HXE8(Clk,Rst_n,En,disp_data,sel,seg);
input Clk; //50M
input Rst_n;
input En; //数码管显示使能,1使能,0关闭
input [31:0]disp_data;
output [7:0] sel;//数码管位选(选择当前要显示的数码管)
output reg [6:0] seg;//数码管段选(当前要显示的内容)
reg [14:0]divider_cnt;//25000-1
reg clk_1K;
reg [7:0]sel_r;
reg [3:0]data_tmp;//数据缓存
// 分频计数器计数模块
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
divider_cnt <= 15'd0;
else if(!En)
divider_cnt <= 15'd0;
else if(divider_cnt == 24999) //分屏到1Khz时钟,因为1M=1000k,所以1khz对应每次计数1000,000ns,
//而50Mhz每次计数20ns,所以需要50000,半个周期也就是25000
divider_cnt <= 15'd0;
else
divider_cnt <= divider_cnt + 1'b1;
//1K扫描时钟生成模块
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
clk_1K <= 1'b0;
else if(divider_cnt == 24999)
clk_1K <= ~clk_1K;
else
clk_1K <= clk_1K;
//8位循环移位寄存器 通过移位来改变状态,每个状态值对应一个数码管
always@(posedge clk_1K or negedge Rst_n)
if(!Rst_n)
sel_r <= 8'b0000_0001;
else if(sel_r == 8'b1000_0000)
sel_r <= 8'b0000_0001;
else
sel_r <= sel_r << 1;
always@(*)//通过上面的移位来判断哪个数码管赋值,因为移位很快,所以通过视觉残影来使人看数码管
case(sel_r)
8'b0000_0001:data_tmp = disp_data[3:0];
8'b0000_0010:data_tmp = disp_data[7:4];
8'b0000_0100:data_tmp = disp_data[11:8];
8'b0000_1000:data_tmp = disp_data[15:12];
8'b0001_0000:data_tmp = disp_data[19:16];
8'b0010_0000:data_tmp = disp_data[23:20];
8'b0100_0000:data_tmp = disp_data[27:24];
8'b1000_0000:data_tmp = disp_data[31:28];
default:data_tmp = 4'b0000;
endcase
always@(*)//查表,每个值对应数码管上面状态
case(data_tmp)
4'h0:seg = 7'b1000000;
4'h1:seg = 7'b1111001;
4'h2:seg = 7'b0100100;
4'h3:seg = 7'b0110000;
4'h4:seg = 7'b0011001;
4'h5:seg = 7'b0010010;
4'h6:seg = 7'b0000010;
4'h7:seg = 7'b1111000;
4'h8:seg = 7'b0000000;
4'h9:seg = 7'b0010000;
4'ha:seg = 7'b0001000;
4'hb:seg = 7'b0000011;
4'hc:seg = 7'b1000110;
4'hd:seg = 7'b0100001;
4'he:seg = 7'b0000110;
4'hf:seg = 7'b0001110;
endcase
assign sel = (En)?sel_r:8'b0000_0000;
endmodule
测试代码:
`timescale 1ns/1ns
`define clk_period 20
module HXE_tb;
reg Clk; //50M
reg Rst_n;
reg En; //数码管显示使能,1使能,0关闭
reg [31:0]disp_data;
wire [7:0] sel;//数码管位选(选择当前要显示的数码管)
wire [6:0] seg;//数码管段选(当前要显示的内容)
HXE8 HXE8(
.Clk(Clk),
.Rst_n(Rst_n),
.En(En),
.disp_data(disp_data),
.sel(sel),
.seg(seg)
);
initial Clk = 1;
always#(`clk_period/2) Clk = ~Clk;
initial begin
Rst_n = 1'b0;
En = 1;
disp_data = 32'h12345678;
#(`clk_period*20);
Rst_n = 1;
#(`clk_period*20);
#20000000;
disp_data = 32'h87654321;
#20000000;
disp_data = 32'h89abcdef;
#20000000;
$stop;
end
endmodule
ISSP调试工具:
将代码下载入开发板后
设置值为16进制