FPGA巡游之旅——在数码管上进行数字时钟显示
1.更改数据生成模块生成一个时钟(时分秒)显示在数码管上
需要更改动态数码管的data_gen模块,按照时钟数据格式和逻辑生成时分秒数据,并不断刷新数据,第四个和第二个小数点显示,即point[2]和point[4]取低有效;
此外还要将seg_deynamic模块中的 else if((h_hun) || (point[5]))改为else if((h_hun) || (point[5])||(point[4])),使最开始最高位没有数字的部分显示为0,而不是不显示,这样更美观一点。
data_gen.v
`timescale 1ns/1ns
module data_gen
#(
parameter CNT_MAX_1S = 26'd49_999_999 //1s计数值
)
(
input sys_clk , //系统时钟,频率50MHz
input sys_rst_n , //复位信号,低电平有效
output reg [19:0] data , //数码管要显示的值 时钟最大为23:59:59 最小为00:00:00
output [5:0] point , //小数点显示,高电平有效
output reg seg_en , //数码管使能信号,高电平有效
output sign //符号位,高电平显示负号
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg [25:0] cnt_1s ; //1s计数器
reg cnt_flag_1s ; //1s标志信号
reg [5:0 ] hour ;
reg [6:0 ] min ;
reg [6:0 ] sec ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//显示小数点以及负数
assign point = 6'b010_100;
assign sign = 1'b0;
//cnt_1s:用50MHz时钟从0到49_999_999计数即为1s
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1s <= 26'd0;
else if(cnt_1s == CNT_MAX_1S)
cnt_1s <= 26'd0;
else
cnt_1s <= cnt_1s + 1'b1;
//cnt_flag_1s:每1s产生一个标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_flag_1s <= 1'b0;
else if(cnt_1s == CNT_MAX_1S - 1'b1)
cnt_flag_1s <= 1'b1;
else
cnt_flag_1s <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)//
if(sys_rst_n == 1'b0)
hour <= 5'd0;
else if((hour == 5'd23 && min == 6'd59 && sec == 6'd59 && cnt_flag_1s == 1'b1))
hour <= 5'd0;
else if(min==6'd59 && sec==6'd59 && cnt_flag_1s)
hour <= hour + 5'd1;
else
hour <= hour;
//min
always@(posedge sys_clk or negedge sys_rst_n)//
if(sys_rst_n == 1'b0)
min <= 6'd0;
else if((min == 6'd59 && sec == 6'd59 && cnt_flag_1s == 1'b1))
min <= 6'd0;
else if(sec==6'd59 && cnt_flag_1s)//
min <= min + 6'd1;
else
min <= min;
//sec
always@(posedge sys_clk or negedge sys_rst_n)//
if(sys_rst_n == 1'b0)
sec <= 6'd0;
else if((sec == 6'd59 && cnt_flag_1s == 1'b1))
sec <= 6'd0;
else if(cnt_flag_1s)
sec <= sec + 6'd1;
else
sec <= sec;
//数码管使能信号给高即可
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg_en <= 1'b0;
else
seg_en <= 1'b1;
//data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 20'd0;
else
data <= 10000 * hour + 100 * min + sec;
endmodule
data_gen_tb.v
`include "../rtl/data_gen.v"
`timescale 1ns/1ns
module data_gen_tb;
reg sys_clk ;
reg sys_rst_n ;
wire [19:0] data ;
wire [5:0] point ;
wire seg_e ;
wire sign ;
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#200 sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
initial begin
$dumpfile("data_gen.vcd");
$dumpvars();
end
initial begin
#4000000 $finish;
end
data_gen
#(
.CNT_MAX_1S(26'd49) //1s计数值
)
data_gen_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.data (data ), //数码管要显示的值 时钟最大为23:59:59 最小为00:00:00
.point (point ), //小数点显示,高电平有效
.seg_en (seg_en ), //数码管使能信号,高电平有效
.sign (sign ) //符号位,高电平显示负号
);
endmodule
Vscode WaveTrace插件观测波形正常,上板调试功能正常。
note:在做这种数字系统设计时 写tb进行波形仿真调试时很有必要的,对着波形一步一步的debug,可以很快帮我们理清思路,更改设计逻辑代码。
2.在1的基础上加入按键信号,可通过按键去设置时钟值
思路:通过按键设置时钟的值也就是通过外部按键提供输入给data_gen模块,然后在data_gen模块内部通过按键输入产生相应的时分秒位的数据,因为是机械按键,所以需要用到按键消抖模块。这里我们使用四个按键,key1-key4;
key1用于秒计数器的增加,按下后从当前值开始累加,随后每按一下+1s,在0-59s之间循环;
key2用于分计时器的增加,按下后从当前值开始累加,随后每按一下+1,在0-59之间循环;
key3用于小时计时器的增加,按下后从当前值开始累加,随后每按一下+1,在0-23h之间循环;
key4为设置键,未按下时时钟正常运行,key1-key3无效;按下后时钟暂停,key1-key3有效,可对时钟值进行设定,当设定完成时再次按下key4键,时钟按照设定值启动,继续正常运行。
key_setting.v
module key_setting
#(
parameter CNT_MAX = 20'd999_999 // 按键消抖计数器
)
(
input sys_clk , // 系统时钟
input sys_rst_n , // 复位信号
input key_add_sec ,
input key_add_min ,
input key_add_hour ,
input key_setting ,
output add_sec ,
output add_min ,
output add_hour ,
output setting
);
/*按键消抖 定义中间参数*/
reg [19:0] cnt_20ms; // 按键消抖计数器
reg key_flag; //1:表示消抖后检测到按键被按下;0:表示没有检测到按键被按下
reg setting_en;
/************************************************************************按键消抖代码****************************************************************************/
//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_20ms <= 20'b0;
else if(key_add_sec == 1'b1 && key_add_min == 1'b1 && key_add_hour == 1'b1 && key_setting == 1'b1)//一旦有按键出现高电平,说明就是抖动,要么就是没有按过
cnt_20ms <= 20'b0;
else if(cnt_20ms == CNT_MAX && (key_add_sec == 1'b0 || key_add_min == 1'b0 || key_add_hour ==1'b0 || key_setting == 1'b0))//一旦计数满20ms 且有按键仍按下,停止计数,并保持
cnt_20ms <= cnt_20ms;
else
cnt_20ms <= cnt_20ms + 1'b1;
//key_flag:当计数满20ms后产生按键有效标志位
//且key_flag在999_999时拉高,维持一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
key_flag <= 1'b0;
else if(cnt_20ms == CNT_MAX-1)//999_998时拉高,若在999_999时拉高,后面是长长的高电平
key_flag <= 1'b1;
else
key_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
setting_en <= 1'b0;
else if(!key_setting && key_flag)
setting_en <= ~setting_en;
assign add_sec = !key_add_sec && key_flag;
assign add_min = !key_add_min && key_flag;
assign add_hour = !key_add_hour && key_flag;
assign setting = setting_en;
endmodule
data_gen.v
`timescale 1ns/1ns
module data_gen
#(
parameter CNT_MAX_1S = 26'd49_999_999 //1s计数值
)
(
input sys_clk , //系统时钟,频率50MHz
input sys_rst_n , //复位信号,低电平有效
input add_sec ,
input add_min ,
input add_hour ,
input setting ,
output reg [19:0] data , //数码管要显示的值 时钟最大为23:59:59 最小为00:00:00
output [5:0] point , //小数点显示,高电平有效
output reg seg_en , //数码管使能信号,高电平有效
output sign //符号位,高电平显示负号
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg [25:0] cnt_1s ; //1s计数器
reg cnt_flag_1s ; //1s标志信号
reg [5:0 ] hour ;
reg [6:0 ] min ;
reg [6:0 ] sec ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//不显示小数点以及负数
assign point = 6'b010_100;
assign sign = 1'b0;
//cnt_1s:用50MHz时钟从0到49_999_999计数即为1s
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1s <= 26'd0;
else if(cnt_1s == CNT_MAX_1S)
cnt_1s <= 26'd0;
else if(setting)
cnt_1s <= cnt_1s;
else if(~setting)
cnt_1s <= cnt_1s + 1'b1;
//cnt_flag_1s:每1s产生一个标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_flag_1s <= 1'b0;
else if(cnt_1s == CNT_MAX_1S - 1'b1)
cnt_flag_1s <= 1'b1;
else
cnt_flag_1s <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)//
if(sys_rst_n == 1'b0)
hour <= 5'd0;
else if((hour == 5'd23 && min == 6'd59 && sec == 6'd59 && cnt_flag_1s == 1'b1))
hour <= 5'd0;
else if(hour == 5'd23 && setting && add_hour)
hour <= 5'd0;
else if(setting && add_hour)
hour <= hour + 5'd1;
else if(min==6'd59 && sec==6'd59 && cnt_flag_1s)
hour <= hour + 5'd1;
else
hour <= hour;
//min
always@(posedge sys_clk or negedge sys_rst_n)//
if(sys_rst_n == 1'b0)
min <= 6'd0;
else if((min == 6'd59 && sec == 6'd59 && cnt_flag_1s == 1'b1))
min <= 6'd0;
else if(min == 6'd59 && setting && add_min)
min <= 6'd0;
else if(setting && add_min)
min <= min + 6'd1;
else if(sec==6'd59 && cnt_flag_1s)//
min <= min + 6'd1;
else
min <= min;
//sec
always@(posedge sys_clk or negedge sys_rst_n)//
if(sys_rst_n == 1'b0)
sec <= 6'd0;
else if((sec == 6'd59 && cnt_flag_1s == 1'b1))
sec <= 6'd0;
else if(sec == 6'd59 && setting && add_sec)
sec <= 6'd0;
else if(setting && add_sec)
sec <= sec + 6'd1;
else if(cnt_flag_1s)
sec <= sec + 6'd1;
else
sec <= sec;
//数码管使能信号给高即可
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg_en <= 1'b0;
else
seg_en <= 1'b1;
//data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 20'd0;
else
data <= 10000 * hour + 100 * min + sec;
endmodule
bcd_8421.v
`timescale 1ns/1ns
module bcd_8421
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire [19:0] data , //输入需要转换的数据
output reg [3:0] unit , //个位BCD码
output reg [3:0] ten , //十位BCD码
output reg [3:0] hun , //百位BCD码
output reg [3:0] tho , //千位BCD码
output reg [3:0] t_tho , //万位BCD码
output reg [3:0] h_hun //十万位BCD码
);
//********************************************************************//
//******************** Parameter And Internal Signal *****************//
//********************************************************************//
//reg define
reg [4:0] cnt_shift ; //移位判断计数器
reg [43:0] data_shift ; //移位判断数据寄存器
reg shift_flag ; //移位判断标志信号
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//cnt_shift:从0到21循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_shift <= 5'd0;
else if((cnt_shift == 5'd21) && (shift_flag == 1'b1))
cnt_shift <= 5'd0;
else if(shift_flag == 1'b1)
cnt_shift <= cnt_shift + 1'b1;
else
cnt_shift <= cnt_shift;
//data_shift:计数器为0时赋初值,计数器为1~20时进行移位判断操作
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_shift <= 44'b0;
else if(cnt_shift == 5'd0)
data_shift <= {24'b0,data};
else if((cnt_shift <= 20) && (shift_flag == 1'b0))
begin
data_shift[23:20] <= (data_shift[23:20] > 4) ? (data_shift[23:20] + 2'd3) : (data_shift[23:20]);
data_shift[27:24] <= (data_shift[27:24] > 4) ? (data_shift[27:24] + 2'd3) : (data_shift[27:24]);
data_shift[31:28] <= (data_shift[31:28] > 4) ? (data_shift[31:28] + 2'd3) : (data_shift[31:28]);
data_shift[35:32] <= (data_shift[35:32] > 4) ? (data_shift[35:32] + 2'd3) : (data_shift[35:32]);
data_shift[39:36] <= (data_shift[39:36] > 4) ? (data_shift[39:36] + 2'd3) : (data_shift[39:36]);
data_shift[43:40] <= (data_shift[43:40] > 4) ? (data_shift[43:40] + 2'd3) : (data_shift[43:40]);
end
else if((cnt_shift <= 20) && (shift_flag == 1'b1))
data_shift <= data_shift << 1;
else
data_shift <= data_shift;
//shift_flag:移位判断标志信号,用于控制移位判断的先后顺序
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag;
//当计数器等于20时,移位判断操作完成,对各个位数的BCD码进行赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
unit <= 4'b0;
ten <= 4'b0;
hun <= 4'b0;
tho <= 4'b0;
t_tho <= 4'b0;
h_hun <= 4'b0;
end
else if(cnt_shift == 5'd21)
begin
unit <= data_shift[23:20];
ten <= data_shift[27:24];
hun <= data_shift[31:28];
tho <= data_shift[35:32];
t_tho <= data_shift[39:36];
h_hun <= data_shift[43:40];
end
endmodule
hc595_ctrl.v
`timescale 1ns/1ns
module hc595_ctrl
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低有效
input wire [5:0] sel , //数码管位选信号
input wire [7:0] seg , //数码管段选信号
output reg stcp , //数据存储器时钟
output reg shcp , //移位寄存器时钟
output reg ds , //串行数据输入
output wire oe //使能信号,低有效
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg [1:0] cnt_4 ; //分频计数器
reg [3:0] cnt_bit ; //传输位数计数器
//wire define
wire [13:0] data ; //数码管信号寄存
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//将数码管信号寄存
assign data = {seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel};
//将复位取反后赋值给其即可
assign oe = ~sys_rst_n;
//分频计数器:0~3循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_4 <= 2'd0;
else if(cnt_4 == 2'd3)
cnt_4 <= 2'd0;
else
cnt_4 <= cnt_4 + 1'b1;
//cnt_bit:每输入一位数据加一
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 4'd0;
else if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
cnt_bit <= 4'd0;
else if(cnt_4 == 2'd3)
cnt_bit <= cnt_bit + 1'b1;
else
cnt_bit <= cnt_bit;
//stcp:14个信号传输完成之后产生一个上升沿
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
stcp <= 1'b0;
else if(cnt_bit == 4'd13 && cnt_4 == 2'd3)
stcp <= 1'b1;
else
stcp <= 1'b0;
//shcp:产生四分频移位时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shcp <= 1'b0;
else if(cnt_4 >= 4'd2)
shcp <= 1'b1;
else
shcp <= 1'b0;
//ds:将寄存器里存储的数码管信号输入即
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
ds <= 1'b0;
else if(cnt_4 == 2'd0)
ds <= data[cnt_bit];
else
ds <= ds;
endmodule
seg_595_dynamic.v
`timescale 1ns/1ns
module seg_595_dynamic
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低有效
input wire [19:0] data , //数码管要显示的值
input wire [5:0] point , //小数点显示,高电平有效
input wire seg_en , //数码管使能信号,高电平有效
input wire sign , //符号位,高电平显示负号
output wire stcp , //数据存储器时钟
output wire shcp , //移位寄存器时钟
output wire ds , //串行数据输入
output wire oe //使能信号
);
//********************************************************************//
//******************** Parameter And Internal Signal *****************//
//********************************************************************//
//wire define
wire [5:0] sel; //数码管位选信号
wire [7:0] seg; //数码管段选信号
//************************************************************************//
//***************************** Instantiation ****************************//
//************************************************************************//
//---------- seg_dynamic_inst ----------
seg_dynamic seg_dynamic_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n), //复位信号,低有效
.data (data ), //数码管要显示的值
.point (point ), //小数点显示,高电平有效
.seg_en (seg_en ), //数码管使能信号,高电平有效
.sign (sign ), //符号位,高电平显示负号
.sel (sel ), //数码管位选信号
.seg (seg ) //数码管段选信号
);
//---------- hc595_ctrl_inst ----------
hc595_ctrl hc595_ctrl_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n), //复位信号,低有效
.sel (sel ), //数码管位选信号
.seg (seg ), //数码管段选信号
.stcp (stcp ), //输出数据存储寄时钟
.shcp (shcp ), //移位寄存器的时钟输入
.ds (ds ), //串行数据输入
.oe (oe )
);
endmodule
seg_dynamic.v
`timescale 1ns/1ns
module seg_dynamic
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低有效
input wire [19:0] data , //数码管要显示的值
input wire [5:0] point , //小数点显示,高电平有效
input wire seg_en , //数码管使能信号,高电平有效
input wire sign , //符号位,高电平显示负号
output reg [5:0] sel , //数码管位选信号
output reg [7:0] seg //数码管段选信号
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter CNT_MAX = 16'd49_999; //数码管刷新时间计数最大值
//wire define
wire [3:0] unit ; //个位数
wire [3:0] ten ; //十位数
wire [3:0] hun ; //百位数
wire [3:0] tho ; //千位数
wire [3:0] t_tho ; //万位数
wire [3:0] h_hun ; //十万位数
//reg define
reg [23:0] data_reg ; //待显示数据寄存器
reg [15:0] cnt_1ms ; //1ms计数器
reg flag_1ms ; //1ms标志信号
reg [2:0] cnt_sel ; //数码管位选计数器
reg [5:0] sel_reg ; //位选信号
reg [3:0] data_disp ; //当前数码管显示的数据
reg dot_disp ; //当前数码管显示的小数点
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//data_reg:控制数码管显示数据
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_reg <= 24'b0;
//若显示的十进制数的十万位为非零数据或需显示小数点,则六个数码管全显示
else if((h_hun) || (point[5])||(point[4]))//else if((h_hun) || (point[5]))
data_reg <= {h_hun,t_tho,tho,hun,ten,unit};
//若显示的十进制数的万位为非零数据或需显示小数点,则值显示在5个数码管上
//打比方我们输入的十进制数据为20’d12345,我们就让数码管显示12345而不是012345
else if(((t_tho) || (point[4])) && (sign == 1'b1))//显示负号
data_reg <= {4'd10,t_tho,tho,hun,ten,unit};//4'd10我们定义为显示负号
else if(((t_tho) || (point[4])) && (sign == 1'b0))
data_reg <= {4'd11,t_tho,tho,hun,ten,unit};//4'd11我们定义为不显示
//若显示的十进制数的千位为非零数据或需显示小数点,则值显示4个数码管
else if(((tho) || (point[3])) && (sign == 1'b1))
data_reg <= {4'd11,4'd10,tho,hun,ten,unit};
else if(((tho) || (point[3])) && (sign == 1'b0))
data_reg <= {4'd11,4'd11,tho,hun,ten,unit};
//若显示的十进制数的百位为非零数据或需显示小数点,则值显示3个数码管
else if(((hun) || (point[2])) && (sign == 1'b1))
data_reg <= {4'd11,4'd11,4'd10,hun,ten,unit};
else if(((hun) || (point[2])) && (sign == 1'b0))
data_reg <= {4'd11,4'd11,4'd11,hun,ten,unit};
//若显示的十进制数的十位为非零数据或需显示小数点,则值显示2个数码管
else if(((ten) || (point[1])) && (sign == 1'b1))
data_reg <= {4'd11,4'd11,4'd11,4'd10,ten,unit};
else if(((ten) || (point[1])) && (sign == 1'b0))
data_reg <= {4'd11,4'd11,4'd11,4'd11,ten,unit};
//若显示的十进制数的个位且需显示负号
else if(((unit) || (point[0])) && (sign == 1'b1))
data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd10,unit};
//若上面都不满足都只显示一位数码管
else
data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd11,unit};
//cnt_1ms:1ms循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1ms <= 16'd0;
else if(cnt_1ms == CNT_MAX)
cnt_1ms <= 16'd0;
else
cnt_1ms <= cnt_1ms + 1'b1;
//flag_1ms:1ms标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_1ms <= 1'b0;
else if(cnt_1ms == CNT_MAX - 1'b1)
flag_1ms <= 1'b1;
else
flag_1ms <= 1'b0;
//cnt_sel:从0到5循环数,用于选择当前显示的数码管
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sel <= 3'd0;
else if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))
cnt_sel <= 3'd0;
else if(flag_1ms == 1'b1)
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= cnt_sel;
//数码管位选信号寄存器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel_reg <= 6'b000_000;
else if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
sel_reg <= 6'b000_001;
else if(flag_1ms == 1'b1)
sel_reg <= sel_reg << 1;
else
sel_reg <= sel_reg;
//控制数码管的位选信号,使六个数码管轮流显示
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_disp <= 4'b0;
else if((seg_en == 1'b1) && (flag_1ms == 1'b1))
case(cnt_sel)
3'd0: data_disp <= data_reg[3:0] ; //给第1个数码管赋个位值
3'd1: data_disp <= data_reg[7:4] ; //给第2个数码管赋十位值
3'd2: data_disp <= data_reg[11:8] ; //给第3个数码管赋百位值
3'd3: data_disp <= data_reg[15:12]; //给第4个数码管赋千位值
3'd4: data_disp <= data_reg[19:16]; //给第5个数码管赋万位值
3'd5: data_disp <= data_reg[23:20]; //给第6个数码管赋十万位值
default:data_disp <= 4'b0 ;
endcase
else
data_disp <= data_disp;
//dot_disp:小数点低电平点亮,需对小数点有效信号取反
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
dot_disp <= 1'b1;
else if(flag_1ms == 1'b1)
dot_disp <= ~point[cnt_sel];
else
dot_disp <= dot_disp;
//控制数码管段选信号,显示数字
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg <= 8'b1111_1111;
else
case(data_disp)
4'd0 : seg <= {dot_disp,7'b100_0000}; //显示数字0
4'd1 : seg <= {dot_disp,7'b111_1001}; //显示数字1
4'd2 : seg <= {dot_disp,7'b010_0100}; //显示数字2
4'd3 : seg <= {dot_disp,7'b011_0000}; //显示数字3
4'd4 : seg <= {dot_disp,7'b001_1001}; //显示数字4
4'd5 : seg <= {dot_disp,7'b001_0010}; //显示数字5
4'd6 : seg <= {dot_disp,7'b000_0010}; //显示数字6
4'd7 : seg <= {dot_disp,7'b111_1000}; //显示数字7
4'd8 : seg <= {dot_disp,7'b000_0000}; //显示数字8
4'd9 : seg <= {dot_disp,7'b001_0000}; //显示数字9
4'd10 : seg <= 8'b1011_1111 ; //显示负号
4'd11 : seg <= 8'b1111_1111 ; //不显示任何字符
default:seg <= 8'b1100_0000;
endcase
//sel:数码管位选信号赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel <= 6'b000_000;
else
sel <= sel_reg;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//---------- bsd_8421_inst ----------
bcd_8421 bcd_8421_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n), //复位信号,低电平有效
.data (data ), //输入需要转换的数据
.unit (unit ), //个位BCD码
.ten (ten ), //十位BCD码
.hun (hun ), //百位BCD码
.tho (tho ), //千位BCD码
.t_tho (t_tho ), //万位BCD码
.h_hun (h_hun ) //十万位BCD码
);
endmodule
top_seg_595.v
`timescale 1ns/1ns
module top_seg_595
(
input sys_clk , //系统时钟,频率50MHz
input sys_rst_n , //复位信号,低电平有效
input key_add_sec ,
input key_add_min ,
input key_add_hour,
input key_setting ,
output stcp , //输出数据存储寄时钟
output shcp , //移位寄存器的时钟输入
output ds , //串行数据输入
output oe //输出使能信号
);
//********************************************************************//
//******************** Parameter And Internal Signal *****************//
//********************************************************************//
//wire define
wire [19:0] data ; //数码管要显示的值
wire [5:0] point ; //小数点显示,高电平有效top_seg_595
wire seg_en ; //数码管使能信号,高电平有效
wire sign ; //符号位,高电平显示负号
//********************************************************************//
//**************************** Main Code *****************************//
//********************************************************************//
//-------------key_setting_inst-----------
key_setting key_setting_inst
(
.sys_clk (sys_clk ), // 系统时钟
.sys_rst_n (sys_rst_n ), // 复位信号
.key_add_sec (key_add_sec ),
.key_add_min (key_add_min ),
.key_add_hour(key_add_hour),
.key_setting (key_setting ),
.add_sec (add_sec ),
.add_min (add_min ),
.add_hour (add_hour ),
.setting (setting )
);
//-------------data_gen_inst--------------
data_gen data_gen_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.add_sec (add_sec ),
.add_min (add_min ),
.add_hour (add_hour ),
.setting (setting ),
.data (data ), //数码管要显示的值
.point (point ), //小数点显示,高电平有效
.seg_en (seg_en ), //数码管使能信号,高电平有效
.sign (sign ) //符号位,高电平显示负号
);
//-------------seg7_dynamic_inst--------------
seg_595_dynamic seg_595_dynamic_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低有效
.data (data ), //数码管要显示的值
.point (point ), //小数点显示,高电平有效
.seg_en (seg_en ), //数码管使能信号,高电平有效
.sign (sign ), //符号位,高电平显示负号
.stcp (stcp ), //输出数据存储寄时钟
.shcp (shcp ), //移位寄存器的时钟输入
.ds (ds ), //串行数据输入
.oe (oe ) //输出使能信号
);
endmodule
上板验证后功能正确
浙公网安备 33010602011771号