FPGA简易版数字钟
之前在学校里任选课上做过一次,因为少上了第一堂课,所以当时连verilog最简单的语法都不会,做起来十分痛苦,最后还是参考CSDN上的代码才做起来的。现在有空,同时也为了理顺思路,自己又独立做了一个,代码可能没其他大佬的精简,但个人认为和我一样的初学者还是可以参考的。后面有空的话会加上按键调时的功能,毕竟现在还要上网课。.
module CLK(
input sys_clk,//50MHz
input rst_n,
output reg [5:0]sel_seg,//位选
output reg [7:0]seg_led//段选
);
localparam MAX_NUM = 14'd5000;
reg [7:0]sec;
reg [7:0]min;
reg [7:0]hour;
reg flag_sec;//秒进位信号
reg flag_min;//分进位信号
//分频模块
parameter CLK_DIV=4'd10;//分频系数
reg dri_clk;//5MHz数码管驱动时钟
reg [3:0]div_cnt;//分频计数
reg [23:0]sec_cnt;//秒计数,sec_cnt计满5M次为1s
wire [3:0]data0;//秒个位
wire [3:0]data1;//秒十位
wire [3:0]data2;//分个位
wire [3:0]data3;//分十位
wire [3:0]data4;//时个位
wire [3:0]data5;//时十位
assign data5=hour/4'd10;
assign data4=hour%4'd10;
assign data3=min/4'd10;
assign data2=min%4'd10;
assign data1=sec/4'd10;
assign data0=sec%4'd10;
//分频模块
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)begin
div_cnt<=1'b0;
dri_clk<=1'b0;
end
else if(div_cnt==CLK_DIV/2-1)begin
dri_clk<=~dri_clk;
div_cnt<=4'd0;
end
else begin
div_cnt<=div_cnt+1'b1;
dri_clk<=dri_clk;
end
end
//秒计数模块
always @(posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
sec_cnt<=1'b0;
sec<=8'd0;
flag_sec<=1'b0;
end
else if(sec_cnt==24'd500_0000)begin
if(sec==8'd59)begin
sec_cnt<=24'd0;
sec<=8'd0;
flag_sec<=1'b1;
end
else begin
flag_sec<=1'b0;
sec_cnt<=24'd0;
sec<=sec+1'b1;
end
end
else begin
flag_sec<=1'b0;
sec<=sec;
sec_cnt<=sec_cnt+1'b1;
end
end
//分计数模块
always @(posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
min<=8'd0;
flag_min<=1'b0;
end
else if(flag_sec)begin
if(min==8'd59)begin
flag_min<=1'b1;
min<=8'd0;
end
else begin
flag_min<=1'b0;
min<=min+1'b1;
end
end
else begin
flag_min<=1'b0;
min<=min;
end
end
//时计数模块
always @(posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
hour<=8'd0;
end
else if(flag_min)begin
if(hour==8'd24)
hour<=8'd0;
else hour<=hour+1'b1;
end
else hour<=hour;
end
//数码管控制
//reg [5:0]sel_seg,//位选
//reg [7:0]seg_led//段选
reg [3:0]display_num;
reg [2:0]cnt0;//位选计数
reg [13:0]cnt1;
//数码管位选
reg flag;
always @(posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
cnt1<=14'd0;
flag<=1'b0;
end
else if(cnt1==MAX_NUM-1)begin
cnt1<=14'd0;
flag<=1'b1;
end
else begin
flag<=1'b0;
cnt1<=cnt1+1'b1;
end
end
always @(posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
cnt0<=3'd0;
end
else if(flag)begin
if(cnt0==3'd5)
cnt0<=3'd0;
else cnt0<=cnt0+1'b1;
end
else cnt0<=cnt0;
end
always @(posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
sel_seg<=6'b111111;
display_num<=4'd0;
end
else begin
case(cnt0)
3'd0:begin
sel_seg<=6'b111110;
display_num<=data0;
end
3'd1:begin
sel_seg<=6'b111101;
display_num<=data1;
end
3'd2:begin
sel_seg<=6'b111011;
display_num<=data2;
end
3'd3:begin
sel_seg<=6'b110111;
display_num<=data3;
end
3'd4:begin
sel_seg<=6'b101111;
display_num<=data4;
end
3'd5:begin
sel_seg<=6'b011111;
display_num<=data5;
end
default:begin
sel_seg<=6'b111111;
display_num<=4'd0;
end
endcase
end
end
//数码管显示
always@(posedge dri_clk or negedge rst_n)begin
if(!rst_n)
seg_led<=8'd1111111;
else begin
case(display_num)
4'd0:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b01000000;
else seg_led<=8'b11000000;
end
4'd1:begin
if(cnt0==3'd2||cnt0==3'd4) seg_led<=8'b01111001;
else seg_led<=8'b11111001;
end
4'd2:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b00100100;
else seg_led<=8'b10100100;
end
4'd3:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b00110000;
else seg_led<=8'b10110000;
end
4'd4:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b00011001;
else seg_led<=8'b10011001;
end
4'd5:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b00010010;
else
seg_led<=8'b10010010;
end
4'd6:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b00000010;
else seg_led<=8'b10000010;
end
4'd7:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b01111000;
else seg_led<=8'b11111000;
end
4'd8:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b00000000;
else seg_led<=8'b10000000;
end
4'd9:begin
if(cnt0==3'd2||cnt0==3'd4)
seg_led<=8'b00010000;
else seg_led<=8'b10010000;
end
default:seg_led<=8'b1111111;
endcase
end
end
endmodule
仿真代码:
`timescale 1 ns/ 1 ns
module tb_clk();
reg sys_clk;
reg rst_n;
wire [3:0]sec;
wire [3:0]min;
wire [3:0]hour;
CLK u1(.sys_clk(sys_clk),.rst_n(rst_n),.sec(sec),.min(min),.hour(hour));
initial begin
sys_clk<=1'b0;
rst_n<=1'b0;
#100 rst_n<=1'b1;
end
always #5 sys_clk<=~sys_clk;
endmodule
仿真时需要将源代码的MAX_NUM改为5,sec_cnt==24’d500_0000改为等于50,CLK_DIV改为4,加快仿真速度
仿真波形:
当时间在光标所指的1:3:39时,各个数据显示均正常,至此实验成功。
附图:
稍微改进了下,可以通过两个按键调分秒了,在下篇文章里。