FPGA项目设计:数字时钟

项目要求:
设计一个数字时钟,数码管前两位显示小时,数码管中间两位显示分钟,数码管后面两位显示秒。

项目设计:
系统框架图:
FPGA项目设计:数字时钟_第1张图片
计数模块时序图:
FPGA项目设计:数字时钟_第2张图片
代码实现:
计数模块:

/*
 * @Description: 用于记数产生时钟
 * @Author: Fu Yu
 * @Date: 2023-08-02 11:16:46
 * @LastEditTime: 2023-08-02 15:23:14
 * @LastEditors: Fu Yu
 */

module counter (
    input       wire            clk         ,
    input       wire            rst_n       ,

    output      wire [23:0]     clock_data      //输出时钟数值
);

parameter   MAX_1S    = 26'd49_999_999;//1s
parameter   MAX_S     = 6'd59;//1S*60 = 1min
parameter   MAX_MIN   = 6'd59;//1min*60 = 1h
parameter   MAX_H     = 5'd23;//1h*24 = 1d

localparam  INIT_S = 40,//赋初值
            INIT_M = 58,
            INIT_H = 23;

reg [25:0]  cnt_1s;
reg [5:0]   cnt_s;
reg [5:0]   cnt_min;
reg [4:0]   cnt_h;

reg [3:0]   time_s_low;
reg [3:0]   time_s_high;
reg [3:0]   time_min_low;
reg [3:0]   time_min_high;
reg [3:0]   time_h_low;
reg [3:0]   time_h_high;

wire add_cnt_1s;
wire end_cnt_1s;

wire add_cnt_s;
wire end_cnt_s;

wire add_cnt_min;
wire end_cnt_min;

wire add_cnt_h;
wire end_cnt_h;

//****************************************************************
//--1s计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_1s <= 26'd0;
    end
    else if(add_cnt_1s) begin
        if(end_cnt_1s) begin
            cnt_1s <= 26'd0;
        end
        else begin
            cnt_1s <= cnt_1s + 1'd1;
        end
    end
    else begin
        cnt_1s <= cnt_1s;
    end
end

assign add_cnt_1s = 1'b1;
assign end_cnt_1s = add_cnt_1s && cnt_1s == MAX_1S;

//****************************************************************
//--秒计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_s <= INIT_S;
    end
    else if(add_cnt_s) begin
        if(end_cnt_s) begin
            cnt_s <= 6'd0;
        end
        else begin
            cnt_s <= cnt_s + 1'd1;
        end
    end
    else begin
        cnt_s <= cnt_s;
    end
end

assign add_cnt_s = end_cnt_1s;
assign end_cnt_s = add_cnt_s && cnt_s == MAX_S;

//****************************************************************
//--分钟计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_min <= INIT_M;
    end
    else if(add_cnt_min) begin
        if(end_cnt_min) begin
            cnt_min <= 6'd0;
        end
        else begin
            cnt_min <= cnt_min + 1'd1;
        end
    end
    else begin
        cnt_min <= cnt_min;
    end
end

assign add_cnt_min = end_cnt_s;
assign end_cnt_min = add_cnt_min && cnt_min == MAX_MIN;

//****************************************************************
//--小时计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_h <= INIT_H;
    end
    else if(add_cnt_h) begin
        if(end_cnt_h) begin
            cnt_h <= 5'd0;
        end
        else begin
            cnt_h <= cnt_h + 1'd1;
        end
    end
    else begin
        cnt_h <= cnt_h;
    end
end

assign add_cnt_h = end_cnt_min;
assign end_cnt_h = add_cnt_h && cnt_h == MAX_H;

//****************************************************************
//--clock_data
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        time_s_high <= 4'd0;
        time_s_low <= 4'd0;
        time_min_high <= 4'd0;
        time_min_low <= 4'b0;
        time_h_high <= 4'd0;
        time_h_low <= 4'd0;
    end
    else begin
        time_h_high <= cnt_h/10;
        time_h_low <= cnt_h%10;
        time_min_high <= cnt_min/10;
        time_min_low <= cnt_min%10;
        time_s_high <= cnt_s/10;
        time_s_low <= cnt_s%10;
    end
end

assign clock_data = {time_h_high,time_h_low,time_min_high,time_min_low,time_s_high,time_s_low};

endmodule //counter

数码管显示模块:

/*
 * @Description: 数码管显示模块,前两位显示时钟数据的小时,中间两位显示时间数据的分钟,最后两位显示时间数据的秒
 * @Author: Fu Yu
 * @Date: 2023-08-02 13:43:47
 * @LastEditTime: 2023-08-02 14:00:00
 * @LastEditors: Fu Yu
 */


module seg_driver (
    input       wire            clk             ,
    input       wire            rst_n           ,
    input       wire [23:0]     clock_data_in   ,

    output      wire [5:0]      sel             ,//位选信号
    output      wire [7:0]      dig                 //段选信号
);

parameter MAX_1MS = 16'd49_999;//1ms

parameter   ZERO  = 7'b100_0000,
            ONE   = 7'b111_1001,
            TWO   = 7'b010_0100,
            THREE = 7'b011_0000,
            FOUR  = 7'b001_1001,
            FIVE  = 7'b001_0010,
            SIX   = 7'b000_0010,
            SEVEN = 7'b111_1000,
            EIGHT = 7'b000_0000,
            NINE  = 7'b001_0000;

reg [5:0] sel_r;
reg [7:0] dig_r;
reg [5:0] point_n;//小数点
reg point_n_r;
reg [3:0]   disp_data   ;//每一位数码管显示的数值

reg [15:0]  cnt_1ms;
wire add_cnt_1ms;
wire end_cnt_1ms;

//****************************************************************
//--1ms计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_1ms <= 16'd0;
    end 
    else if(add_cnt_1ms)begin 
        if(end_cnt_1ms)begin 
            cnt_1ms <= 16'd0;
        end
        else begin 
            cnt_1ms <= cnt_1ms + 1'b1;
        end 
    end
end 

assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1MS;

//****************************************************************
//--point_n
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        point_n <= 6'b111_111;
    end
    else begin
        point_n <= 6'b110101;
    end
end

//****************************************************************
//--sel
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        sel_r <= 6'b111110;
    end
    else if(end_cnt_1ms) begin
        sel_r <= {sel_r[4:0],sel_r[5]};
    end
    else begin
        sel_r <= sel_r;
    end
end

assign sel = sel_r;

//****************************************************************
//-- disp_data   
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        disp_data <= 4'd0;
        point_n_r <= 1'b1;
    end
    else begin
        case (sel_r)
            6'b111110 : begin
                disp_data <= clock_data_in[23:20];
                point_n_r <= point_n[0];
            end
            
            6'b111101 : begin
                disp_data <= clock_data_in[19:16];
                point_n_r <= point_n[1];
            end

            6'b111011 : begin
                disp_data <= clock_data_in[15:12];
                point_n_r <= point_n[2];
            end

            6'b110111 : begin
                disp_data <= clock_data_in[11:8];
                point_n_r <= point_n[3];
            end

             6'b101111 : begin
                disp_data <= clock_data_in[7:4];
                point_n_r <= point_n[4];
            end

            6'b011111 : begin
                disp_data <= clock_data_in[3:0];
                point_n_r <= point_n[5];
            end
        endcase
    end
end

//****************************************************************
//--dig
//****************************************************************
always @(*)begin 
        case (disp_data)
            0 :  dig_r <= {point_n_r,ZERO  };
            1 :  dig_r <= {point_n_r,ONE   };
            2 :  dig_r <= {point_n_r,TWO   };
            3 :  dig_r <= {point_n_r,THREE };
            4 :  dig_r <= {point_n_r,FOUR  };
            5 :  dig_r <= {point_n_r,FIVE  };
            6 :  dig_r <= {point_n_r,SIX   };
            7 :  dig_r <= {point_n_r,SEVEN };
            8 :  dig_r <= {point_n_r,EIGHT };
            9 :  dig_r <= {point_n_r,NINE  };
           
            default: dig_r <= 8'hff;
        endcase
    end

assign dig = dig_r;

endmodule //seg_driver

顶层文件:

module top (
    input           wire        clk     ,
    input           wire        rst_n   ,

    output          wire [5:0]  sel     ,
    output          wire [7:0]  dig         
);

wire [23:0] data;

counter u_counter(
    .     clk        (clk) ,
    .     rst_n      (rst_n) ,

    .     clock_data    (data)
);


seg_driver u_seg_driver (
    .     clk            (clk) ,
    .     rst_n          (rst_n) ,
    .     clock_data_in  (data),

    .     sel            (sel) ,
    .     dig              (dig)
);

endmodule //top

你可能感兴趣的:(fpga开发)