FPGA项目设计:数字时钟

项目要求:

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

项目设计:

系统框架图:

计数模块时序图:

代码实现:
计数模块:

verilog 复制代码
/*
 * @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

数码管显示模块:

verilog 复制代码
/*
 * @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

顶层文件:

verilog 复制代码
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
相关推荐
DS小龙哥4 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
上理考研周导师14 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战15 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
bigbig猩猩1 天前
FPGA(现场可编程门阵列)的时序分析
fpga开发
Terasic友晶科技1 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪1 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
江山如画,佳人北望1 天前
EDA技术简介
fpga开发
淘晶驰AK1 天前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
最好有梦想~1 天前
FPGA时序分析和约束学习笔记(4、IO传输模型)
笔记·学习·fpga开发