一、需求分析
时钟控制模块,需要生成秒,分,时三路信号,需要有外部信号能对其进行控制。
按照正常时钟逻辑:
秒满60归零;
分在秒满60时进1,分满60归零;
时在分满60时进1,时满24归零。
外部控制方案选用键盘,因此需要引入按键消抖模块(见本人博客 基于FPGA的数字钟——(二)按键消抖模块设计)
本文链接:https://blog.csdn.net/qq_43650722/article/details/103808539
二、方案实现
方案一:
直接产生秒,分,时信号,以二进制数进行编码:
模块代码如下:
//
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
//
// Create Date: 2019/12/29 15:55:40
// Design Name: clock
// Module Name: clock
// Project Name: Clock
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module clock(
input clk, //system clock
input rst, //system rst
output reg[4:0] h, //output h,0-24
output reg[5:0] min, //output min,0-60
output reg[5:0] s, //output s,0-60
output reg[9:0] ms, //output ms,0-1000
input h_plus, //h_plus_signal(posedge valid)
input min_plus, //min_plus_signal(posedge valid)
input s_plus //s_plus_signal(posedge valid)
);
reg[15:0] ms_cnt;
reg h_plus_temp0;
reg h_plus_temp1;
reg min_plus_temp0;
reg min_plus_temp1;
reg s_plus_temp0;
reg s_plus_temp1;
wire h_plus_pedge;
wire min_plus_pedge;
wire s_plus_pedge;
assign h_plus_pedge = (h_plus_temp0)&(!h_plus_temp1);//时间改变信号上升沿检测
assign min_plus_pedge = (min_plus_temp0)&(!min_plus_temp1);
assign s_plus_pedge = (s_plus_temp0)&(!s_plus_temp1);
//**************************************
//外部增加时间信号采集
always@(posedge clk or negedge rst)begin
if(!rst)begin
h_plus_temp0 <= 1'b0;
h_plus_temp1 <= 1'b0;
end
else begin
h_plus_temp0 <= h_plus;
h_plus_temp1 <= h_plus_temp0;
end
end
always@(posedge clk or negedge rst)begin
if(!rst)begin
min_plus_temp0 <= 1'b0;
min_plus_temp1 <= 1'b0;
end
else begin
min_plus_temp0 <= min_plus;
min_plus_temp1 <= min_plus_temp0;
end
end
always@(posedge clk or negedge rst)begin
if(!rst)begin
s_plus_temp0 <= 1'b0;
s_plus_temp1 <= 1'b0;
end
else begin
s_plus_temp0 <= s_plus;
s_plus_temp1 <= s_plus_temp0;
end
end
//****************************************************
//毫秒计数器,计数值50000
always@(posedge clk or negedge rst)begin
if(!rst)
ms_cnt <= 16'd0;
else
if(ms_cnt == 16'd50000)
ms_cnt <= 16'd0;
else
ms_cnt <= ms_cnt + 1'b1;
end
//毫秒逻辑,满1000归零
always@(posedge clk or negedge rst)begin
if(!rst)
ms <= 10'd0;
else
if(ms == 10'd1000)
ms <= 10'd0;
else
if(ms_cnt == 16'd50000)
ms <= ms + 1'b1;
else
ms <= ms;
end
//秒逻辑,逢毫秒满1000进1,满60归零
always@(posedge clk or negedge rst)begin
if(!rst)
s <= 6'd0;
else
if(s == 6'd60)
s <= 6'd0;
else
if(ms == 10'd1000)
s <= s + 1'b1;
else
if(s_plus_pedge)
s <= s + 1'b1;
else
s <= s;
end
//分钟逻辑,逢秒满60进1,满60归零
always@(posedge clk or negedge rst)begin
if(!rst)
min <= 6'd0;
else
if(min == 6'd60)
min <= 6'd0;
else
if(s == 6'd60)
min <= min + 1'b1;
else
if(min_plus_pedge)
min <= min + 1'b1;
else
min <= min;
end
//时逻辑,逢分钟满60进1,满24归零
always@(posedge clk or negedge rst)begin
if(!rst)
h <= 5'd0;
else
if(h == 5'd24)
h <= 5'd0;
else
if(min == 6'd60)
h <= h + 1'b1;
else
if(h_plus_pedge)
h <= h + 1'b1;
else
h <= h;
end
endmodule
此方案由于直接生成三路二进制编码时间信号,而数码管显示模块中每个数码管是独立的,每一位数码管只能显示个位数,而多位数码管无法在输入以二进制编码数据情况下直接显示多位数。参照(基于FPGA的数字钟——(三)时钟显示模块(数码管)本文链接:https://blog.csdn.net/qq_43650722/article/details/104010569)
例:若需要显示数字56,则需要将56分为5和6分别给两位数码管进行显示。
在此情况下则需要引入 数据解码模块 将两位十进制数分离出单独的十位和个位
在此情境下,有两种方案可选择
方案1:
此方法转载自 stubben_bear 的 利用verilog将二进制码转换为十进制BCD码 文
原文链接:https://blog.csdn.net/li200503028/article/details/19507061
方法:
首先给出二进制码转换为十进制BCD码的几个步骤(以8bit二进制码为例):
1.将二进制码左移一位(或者乘2)
2.找到左移后的码所对应的个,十,百位。
3.判断在个位和百位的码是否大于5,如果是则该段码加3。
4.继续重复以上三步直到移位8次后停止。
代码:
`timescale 1ns / 1ps
module bin_dec(clk,bin,rst_n,one,ten,hun,count,shift_reg
);
input [7:0] bin;
input clk,rst_n;
output [3:0] one,ten;
output [3:0] count;
output [1:0] hun;
output [17:0]shift_reg;
reg [3:0] one,ten;
reg [1:0] hun;
reg [3:0] count;
reg [17:0]shift_reg=18'b000000000000000000;
// 计数部分
always @ ( posedge clk or negedge rst_n )
begin
if( !rst_n )
count<=0;
else if (count==9)
count<=0;
else
count<=count+1;
end
// 二进制转换为十进制 /
always @ (posedge clk or negedge rst_n )
begin
if (!rst_n)
shift_reg=0;
else if (count==0)
shift_reg={10'b0000000000,bin};
else if ( count<=8) //实现8次移位操作
begin
if(shift_reg[11:8]>=5) //判断个位是否>5,如果是则+3
begin
if(shift_reg[15:12]>=5) //判断十位是否>5,如果是则+3
begin
shift_reg[15:12]=shift_reg[15:12]+2'b11;
shift_reg[11:8]=shift_reg[11:8]+2'b11;
shift_reg=shift_reg<<1; //对个位和十位操作结束后,整体左移
end
else
begin
shift_reg[15:12]=shift_reg[15:12];
shift_reg[11:8]=shift_reg[11:8]+2'b11;
shift_reg=shift_reg<<1;
end
end
else
begin
if(shift_reg[15:12]>=5)
begin
shift_reg[15:12]=shift_reg[15:12]+2'b11;
shift_reg[11:8]=shift_reg[11:8];
shift_reg=shift_reg<<1;
end
else
begin
shift_reg[15:12]=shift_reg[15:12];
shift_reg[11:8]=shift_reg[11:8];
shift_reg=shift_reg<<1;
end
end
end
end
/输出赋值//
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
begin
one<=0;
ten<=0;
hun<=0;
end
else if (count==9) //此时8次移位全部完成,将对应的值分别赋给个,十,百位
begin
one<=shift_reg[11:8];
ten<=shift_reg[15:12];
hun<=shift_reg[17:16];
end
end
endmodule
仿真结果:
方案2:
由于本设计中需要显示的数字最大为59,数据量并不大,因此可以采用查找表法将十位数分离。
代码:
//
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
//
// Create Date: 2019/12/29 15:55:40
// Design Name: seg_encoder
// Module Name: seg_encoder
// Project Name: Clock
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module seg_encoder(
clk,
rst,
data_in,
out_10bit,
out_1bit
);
input clk;
input rst;
input[5:0] data_in;
output reg[3:0] out_10bit;
output reg[3:0] out_1bit;
always@(posedge clk or negedge rst)
if(!rst)begin
out_10bit <= 4'd0;
out_1bit <= 4'd0;
end
else begin
case(data_in)
6'd0:begin
out_10bit <= 4'd0;
out_1bit <= 4'd0;
end
6'd1:begin
out_10bit <= 4'd0;
out_1bit <= 4'd1;
end
6'd2:begin
out_10bit <= 4'd0;
out_1bit <= 4'd2;
end
6'd3:begin
out_10bit <= 4'd0;
out_1bit <= 4'd3;
end
6'd4:begin
out_10bit <= 4'd0;
out_1bit <= 4'd4;
end
6'd5:begin
out_10bit <= 4'd0;
out_1bit <= 4'd5;
end
6'd6:begin
out_10bit <= 4'd0;
out_1bit <= 4'd6;
end
6'd7:begin
out_10bit <= 4'd0;
out_1bit <= 4'd7;
end
6'd8:begin
out_10bit <= 4'd0;
out_1bit <= 4'd8;
end
6'd9:begin
out_10bit <= 4'd0;
out_1bit <= 4'd9;
end
6'd10:begin
out_10bit <= 4'd1;
out_1bit <= 4'd0;
end
6'd11:begin
out_10bit <= 4'd1;
out_1bit <= 4'd1;
end
6'd12:begin
out_10bit <= 4'd1;
out_1bit <= 4'd2;
end
6'd13:begin
out_10bit <= 4'd1;
out_1bit <= 4'd4;
end
6'd15:begin
out_10bit <= 4'd1;
out_1bit <= 4'd5;
end
6'd16:begin
out_10bit <= 4'd1;
out_1bit <= 4'd6;
end
6'd17:begin
out_10bit <= 4'd1;
out_1bit <= 4'd7;
end
6'd18:begin
out_10bit <= 4'd1;
out_1bit <= 4'd8;
end
6'd19:begin
out_10bit <= 4'd1;
out_1bit <= 4'd9;
end
6'd20:begin
out_10bit <= 4'd2;
out_1bit <= 4'd0;
end
6'd21:begin
out_10bit <= 4'd2;
out_1bit <= 4'd1;
end
6'd22:begin
out_10bit <= 4'd2;
out_1bit <= 4'd2;
end
6'd23:begin
out_10bit <= 4'd2;
out_1bit <= 4'd3;
end
6'd24:begin
out_10bit <= 4'd2;
out_1bit <= 4'd4;
end
6'd25:begin
out_10bit <= 4'd2;
out_1bit <= 4'd5;
end
6'd26:begin
out_10bit <= 4'd2;
out_1bit <= 4'd6;
end
6'd27:begin
out_10bit <= 4'd2;
out_1bit <= 4'd7;
end
6'd28:begin
out_10bit <= 4'd2;
out_1bit <= 4'd8;
end
6'd29:begin
out_10bit <= 4'd2;
out_1bit <= 4'd9;
end
6'd30:begin
out_10bit <= 4'd3;
out_1bit <= 4'd0;
end
6'd31:begin
out_10bit <= 4'd3;
out_1bit <= 4'd1;
end
6'd32:begin
out_10bit <= 4'd3;
out_1bit <= 4'd2;
end
6'd33:begin
out_10bit <= 4'd3;
out_1bit <= 4'd3;
end
6'd34:begin
out_10bit <= 4'd3;
out_1bit <= 4'd4;
end
6'd35:begin
out_10bit <= 4'd3;
out_1bit <= 4'd5;
end
6'd36:begin
out_10bit <= 4'd3;
out_1bit <= 4'd6;
end
6'd37:begin
out_10bit <= 4'd3;
out_1bit <= 4'd7;
end
6'd38:begin
out_10bit <= 4'd3;
out_1bit <= 4'd8;
end
6'd39:begin
out_10bit <= 4'd3;
out_1bit <= 4'd9;
end
6'd40:begin
out_10bit <= 4'd4;
out_1bit <= 4'd0;
end
6'd41:begin
out_10bit <= 4'd4;
out_1bit <= 4'd1;
end
6'd42:begin
out_10bit <= 4'd4;
out_1bit <= 4'd2;
end
6'd43:begin
out_10bit <= 4'd4;
out_1bit <= 4'd3;
end
6'd44:begin
out_10bit <= 4'd4;
out_1bit <= 4'd4;
end
6'd45:begin
out_10bit <= 4'd4;
out_1bit <= 4'd5;
end
6'd46:begin
out_10bit <= 4'd4;
out_1bit <= 4'd6;
end
6'd47:begin
out_10bit <= 4'd4;
out_1bit <= 4'd7;
end
6'd48:begin
out_10bit <= 4'd4;
out_1bit <= 4'd8;
end
6'd49:begin
out_10bit <= 4'd4;
out_1bit <= 4'd9;
end
6'd50:begin
out_10bit <= 4'd5;
out_1bit <= 4'd0;
end
6'd51:begin
out_10bit <= 4'd5;
out_1bit <= 4'd1;
end
6'd52:begin
out_10bit <= 4'd5;
out_1bit <= 4'd2;
end
6'd53:begin
out_10bit <= 4'd5;
out_1bit <= 4'd3;
end
6'd54:begin
out_10bit <= 4'd5;
out_1bit <= 4'd4;
end
6'd55:begin
out_10bit <= 4'd5;
out_1bit <= 4'd5;
end
6'd56:begin
out_10bit <= 4'd5;
out_1bit <= 4'd6;
end
6'd57:begin
out_10bit <= 4'd5;
out_1bit <= 4'd7;
end
6'd58:begin
out_10bit <= 4'd5;
out_1bit <= 4'd8;
end
6'd59:begin
out_10bit <= 4'd5;
out_1bit <= 4'd9;
end
6'd60:begin
out_10bit <= 4'd6;
out_1bit <= 4'd0;
end
default:begin
out_10bit <= 4'd0;
out_1bit <= 4'd0;
end
endcase
end
endmodule
仿真图(部分):