FPGA-based digital stopwatch design (complete project)

Table of Contents

Overview

design features

The purpose of digital stopwatch design

Module simulation

design code


Overview

This design is a digital stopwatch for sports competitions. It is programmed using VHDL language based on FPGA under the Quartus II 9.0sp2 software. Computer simulation is carried out using the EP2C8Q208 chip of ALTRA’s CycloneII series, and the corresponding simulation results are given. This design effectively overcomes the shortcomings of the traditional digital stopwatch and adopts EDA technology to adopt a top-down design idea. The specific logic circuit was drawn, and finally it was debugged and verified on hardware. This circuit can achieve good timing function, high timing accuracy, and the longest timing time can reach one hour.

Design function

1. Complete a digital stopwatch with hours, minutes and seconds display;
2, 12, and 24 hours can be adjusted;
3. Can be used as a stopwatch;
4. Able to display countdown;

The purpose of digital stopwatch design

The purpose of this design is to understand EDA technology on the basis of mastering the preliminary use of the EDA experimental development system, further understand the clock control system in the computer system, master the working principle of the state machine, and understand how computer clock pulses are generated and work. (omitted here)

Module Simulation

Design Code

(The code is long, complete The project is shared for free, if you need to obtain it, please follow: FPGA Garden)
module time_clock(
    clk,
    reset_n,
    hour_select_key,
    second_counter_key,
    second_countdown_key,
    pause_key,
    Duan,
    wei
    );
    
    input clk; //clk:50MHZ clock input;
    input reset_n; //Reset signal input, low level is active;
    
    input hour_select_key; //The key can be adjusted for 12 and 24 hours. When it is '1', it is 24, and when it is '0', it is 12 hours;
    input second_counter_key; //When the key is '1', it is the stopwatch timing function, and when '0', it is the normal function;
    input second_countdown_key; //When the key is '1', it is the countdown function, and when '0', it is the normal function;
    input pause_key; //Pause function button, you can use this button to pause when performing stopwatch timing and countdown, '1' pauses, '0' continues
    
    output [7:0] duan; //duan: digital tube segment code;
    output [7:0] wei; //wei: digital tube bit code;
    
    reg [7:0] duan; //duan: digital tube segment code;
    reg [7:0] wei; //wei: digital tube bit code;

    reg [24:0] count; //1HZ clock counter
    reg [13:0] count2; //Scan clock counter
    reg clk_1hz; //1HZ clock signal

    reg [3:0] miao_ge; //Second single digit BCD code
    reg [2:0] miao_shi; //Ten-digit second BCD binary code
    reg [3:0] fen_ge; //Single digit number of minutes
    reg [2:0] fen_shi; //tens of minutes
    reg [1:0] shi_ge; //clock single digit
    reg [1:0] shi_shi; //clock ten digits
    reg [1:0] shi_select_ge; //clock selection single digit, used to adjust the time system
    reg [1:0] shi_select_shi; //Clock selects ten digits, used to adjust the time system

    reg clk_scan; //Nigital tube scan clock
    reg [2:0] select; //Used to select display bitcode when scanning

    //************************************************ *************************************************** **
    //Module name: second clock frequency division module
    // Function description:
    //************************************************ *************************************************** **
    always @(posedge clk or negedge reset_n)//1HZ clock process
    begin
        if(reset_n == 1'b0)
        begin
            count <= 25'd0;
            clk_1hz <= 1'b0;
        end
        else
            if(count == 25'd25000000)
            begin
                clk_1hz <= ~clk_1hz;
                count <= 25'd0;
            end
            else
                count <= count + 1'b1;
    end
    
    reg [17:0] counter_count;
    reg clk_100hz;
    always @(posedge clk or negedge reset_n)//100HZ clock process
    begin
        if(reset_n == 1'b0)
        begin
            counter_count <= 18'd0;
            clk_100hz <= 1'b0;
        end
        else
            if(~pause_key == 1'b0)
                if(counter_count == 18'd250000)
                begin
                    clk_100hz <= ~clk_100hz;
                    counter_count <= 18'd0;
                end
                else
                    counter_count <= counter_count + 1'b1;
            else
            begin
                clk_100hz <= 1'b0;
                counter_count <= 18'd0;
            end
    end
    //************************************************ *************************************************** **
    //Module name: timing adjustment module
    // Function description:
    //************************************************ *************************************************** **
    always @(posedge clk or negedge reset_n)//1HZ clock process
    begin
        if(reset_n == 1'b0)
        begin
            shi_select_ge <= 2'd3;
            shi_select_shi <= 2'd2;
        end
        else
            if(hour_select_key == 1'b1)//The key can be adjusted for 12 and 24 hours. When it is '1', it is 24, and when it is '0', it is 12 hours
            begin
                shi_select_ge <= 2'd3;
                shi_select_shi <= 2'd2;
            end
            else
            begin
                shi_select_ge <= 2'd1;
                shi_select_shi <= 2'd1;
            end
    end
    //************************************************ *************************************************** **
    //Module name: Second timing module
    // Function description:
    //************************************************ *************************************************** **
    always @(posedge clk_1hz or negedge reset_n)//Every second and minute accumulation function process
    begin
        if(reset_n == 1'b0)
        begin
            miao_ge <= 4'd9;
            miao_shi <= 3'd5;
            fen_ge <= 4'd9;
            fen_shi <= 3'd5;
            shi_ge <= 2'd3;
            shi_shi <= 2'd2;
        end
        else
            if(miao_ge ==4'd9)
            begin
                miao_ge <= 4'd0;
                if(miao_shi == 3'd5)
                begin
                    miao_shi <= 3'd0;
                    if(fen_ge == 4'd9)
                    begin
                        fen_ge <= 4'd0;
                        if(fen_shi == 3'd5)
                        begin
                            fen_shi <= 3'd0;
                            if(shi_ge == shi_select_ge)//The 24-hour format corresponds to 3, and the 12-hour format corresponds to 1
                            begin
                                shi_ge <= 2'd0;
                                if(shi_shi == shi_select_shi)//The 24-hour clock corresponds to 2, and the 12-hour clock corresponds to 1
                                    shi_shi <= 2'd0;
                                else
                                    shi_shi <= shi_shi + 1'b1;
                            end
                            else
                                shi_ge <= shi_ge + 1'b1;
                        end
                        else
                            fen_shi <= fen_shi + 1'b1;
                    end
                    else
                        fen_ge <= fen_ge + 1'b1;
                end
                else
                    miao_shi <= miao_shi + 1'b1;
            end
            else
                miao_ge <= miao_ge + 1'b1;
    end
    //************************************************ *************************************************** **
    //Module name: Digital tube bit selection clock generation module
    // Function description:
    //************************************************ *************************************************** **
    always @(posedge clk or negedge reset_n)//Nigital tube scanning clock generation process
    begin
        if(reset_n == 1'b0)
        begin
            count2 <= 14'd0;
            clk_scan <= 1'b0;
        end
        else
            if(count2 == 14'd10000)
            begin
                count2 <= 14'd0;
                clk_scan <= ~clk_scan;
            end
            else
                count2 <= count2 + 1'b1;
    end
    //************************************************ *************************************************** **
    //Module name: digital tube bit selection generation signal module
    // Function description:
    //************************************************ *************************************************** **
    always @(posedge clk_scan or negedge reset_n)
    begin
        if(reset_n == 1'b0)
            select <= 3'b000;
        else
            select <= select + 1'b1;
    end
    //************************************************ *************************************************** **
    //Module name: Stopwatch timing
    // Function description: Stopwatch timing
    //************************************************ *************************************************** **
    reg [3:0] counter_haomiao_ge; //Stopwatch timing, millisecond single digit BCD code
    reg [3:0] counter_haomiao_shi; //Stopwatch timing, millisecond ten-digit BCD code
    reg [3:0] counter_miao_ge; //Stopwatch timing, second single digit BCD code
    reg [2:0] counter_miao_shi; //Stopwatch timing, seconds ten-digit BCD binary code
    reg [3:0] counter_fen_ge; //Stopwatch timing, minute digits
    reg [2:0] counter_fen_shi; //Stopwatch timing, ten digits of minutes
    reg [1:0] counter_shi_ge; //Stopwatch timing, clock single digits
    reg [1:0] counter_shi_shi; //Stopwatch timing, clock ten digits
    always @(posedge clk_100hz or negedge reset_n)
    begin
        if(reset_n == 1'b0)
        begin
            counter_haomiao_ge <= 4'd0;
            counter_haomiao_shi <= 4'd0;
            counter_miao_ge <= 4'd0;
            counter_miao_shi <= 3'd0;
            counter_fen_ge <= 4'd0;
            counter_fen_shi <= 3'd0;
            counter_shi_ge <= 2'd0;
            counter_shi_shi <= 2'd0;
        end
        else
            if(~second_counter_key == 1'b1)
                if(counter_haomiao_ge == 4'd9)
                begin
                    counter_haomiao_ge <= 4'd0;
                    if(counter_haomiao_shi == 4'd9)
                    begin
                        counter_haomiao_shi <= 4'd0;
                        if(counter_miao_ge ==4'd9)
                        begin
                            counter_miao_ge <= 4'd0;
                            if(counter_miao_shi == 3'd5)
                            begin
                                counter_miao_shi <= 3'd0;
                                if(counter_fen_ge == 4'd9)
                                begin
                                    counter_fen_ge <= 4'd0;
                                    if(counter_fen_shi == 3'd5)
                                    begin
                                        counter_fen_shi <= 3'd0;
                                        if(counter_shi_ge == 2'd3)//The 24-hour clock corresponds to 3, the 12-hour clock corresponds to 1
                                        begin
                                            counter_shi_ge <= 2'd0;
                                            if(counter_shi_shi == 2'd2)//The 24-hour clock corresponds to 2, the 12-hour clock corresponds to 1
                                                counter_shi_shi <= 2'd0;
                                            else
                                                counter_shi_shi <= counter_shi_shi + 1'b1;
                                        end
                                        else
                                            counter_shi_ge <= counter_shi_ge + 1'b1;
                                    end
                                    else
                                        counter_fen_shi <= counter_fen_shi + 1'b1;
                                end
                                else
                                    counter_fen_ge <= counter_fen_ge + 1'b1;
                            end
                            else
                               counter_miao_shi <= counter_miao_shi + 1'b1;
                        end
                        else
                            counter_miao_ge <= counter_miao_ge + 1'b1;
                    end
                    else
                        counter_haomiao_shi <= counter_haomiao_shi + 1'b1;
                end
                else
                    counter_haomiao_ge <= counter_haomiao_ge + 1'b1;
            else
            begin
                counter_haomiao_ge <= 4'd0;
                counter_haomiao_shi <= 4'd0;
                counter_miao_ge <= 4'd0;
                counter_miao_shi <= 3'd0;
                counter_fen_ge <= 4'd0;
                counter_fen_shi <= 3'd0;
                counter_shi_ge <= 2'd0;
                counter_shi_shi <= 2'd0;
            end
    end
    //************************************************ *************************************************** **
    //Module name: countdown module
    // Function description:
    //************************************************ *************************************************** **
    reg [3:0] countdown_haomiao_ge; //Countdown, millisecond single digit BCD code
    reg [3:0] countdown_haomiao_shi; //Countdown, ten-digit millisecond BCD code
    reg [3:0] countdown_miao_ge; //Countdown, second single digit BCD code
    reg [2:0] countdown_miao_shi; //Countdown, ten-digit second BCD binary code
    always @(posedge clk_100hz or negedge reset_n)//Second and minute accumulation function process
    begin
        if(reset_n == 1'b0)
        begin
            countdown_haomiao_ge <= 4'd9;
            countdown_haomiao_shi <= 4'd9;
            countdown_miao_ge <= 4'd9;
            countdown_miao_shi <= 3'd5;
        end
        else
            if(~second_countdown_key == 1'b1)
                if(countdown_haomiao_ge == 4'd0)
                begin
                    countdown_haomiao_ge <= 4'd9;
                    if(countdown_haomiao_shi == 4'd0)
                    begin
                        countdown_haomiao_shi <= 4'd9;
                        if(countdown_miao_ge ==4'd0)
                        begin
                            countdown_miao_ge <= 4'd9;
                            if(countdown_miao_shi == 3'd0)
                            begin
                                countdown_miao_shi <= 3'd5;
                            end
                            else
                               countdown_miao_shi <= countdown_miao_shi - 1'b1;
                        end
                        else
                            countdown_miao_ge <= countdown_miao_ge - 1'b1;
                    end
                    else
                        countdown_haomiao_shi <= countdown_haomiao_shi - 1'b1;
                end
                else
                    countdown_haomiao_ge <= countdown_haomiao_ge - 1'b1;
            else
            begin
                countdown_haomiao_ge <= 4'd9;
                countdown_haomiao_shi <= 4'd9;
                countdown_miao_ge <= 4'd9;
                countdown_miao_shi <= 3'd5;
            end
    end
    //************************************************ *************************************************** **
    //Module name: function selection module
    // Function description:
    //************************************************ *************************************************** **
    reg [3:0] reg_haomiao_ge; //Millisecond single digit BCD code
    reg [3:0] reg_haomiao_shi; //Millisecond ten-digit BCD code
    reg [3:0] reg_miao_ge; //Second single digit BCD code
    reg [2:0] reg_miao_shi; //Ten-digit second BCD binary code
    reg [3:0] reg_fen_ge; //Single digit number of minutes
    reg [2:0] reg_fen_shi; //tens of minutes
    reg [3:0] reg_shi_ge; //clock single digit
    reg [1:0] reg_shi_shi; //clock ten digits
    always @(posedge clk or negedge reset_n)
    begin
        if(reset_n == 1'b0)
        begin
            reg_haomiao_ge <= 4'd9;
            reg_haomiao_shi <= 4'd9;
            reg_miao_ge <= 4'd9;
            reg_miao_shi <= 3'd5;
            reg_fen_ge <= 4'd9;
            reg_fen_shi <= 3'd5;
            reg_shi_ge <= 4'd3;
            reg_shi_shi <= 2'd2;
        end
        else
        begin
            case({~second_counter_key,~second_countdown_key})
                2'b10://Stopwatch function
                begin
                    reg_haomiao_ge <= counter_haomiao_ge;
                    reg_haomiao_shi <= counter_haomiao_shi;
                    reg_miao_ge <= counter_miao_ge;
                    reg_miao_shi <= counter_miao_shi;
                    reg_fen_ge <= counter_fen_ge;
                    reg_fen_shi <= counter_fen_shi;
                    reg_shi_ge <= counter_shi_ge;
                    reg_shi_shi <= counter_shi_shi;
                end
                2'b01://Countdown function
                begin
                    reg_haomiao_ge <= countdown_haomiao_ge;
                    reg_haomiao_shi <= countdown_haomiao_shi;
                    reg_miao_ge <= countdown_miao_ge;
                    reg_miao_shi <= countdown_miao_shi;
                    reg_fen_ge <= 4'hf; //Do not display
                    reg_fen_shi <= 3'b111; //Do not display
                    reg_shi_ge <= 4'b1111; //Do not display
                    reg_shi_shi <= 2'b11; //Do not display
                end
                default://Normal function, display hours, minutes and seconds
                begin
                    reg_haomiao_ge <= 4'hf; //Do not display
                    reg_haomiao_shi <= 4'hf; //Do not display
                    reg_miao_ge <= miao_ge;
                    reg_miao_shi <= miao_shi;
                    reg_fen_ge <= fen_ge;
                    reg_fen_shi <= fen_shi;
                    reg_shi_ge <= shi_ge;
                    reg_shi_shi <= shi_shi;
                end
            endcase
        end
    end
    //************************************************ *************************************************** **
    //Module name: decoding circuit
    // Function description:
    //************************************************ *************************************************** **
    always @(posedge clk)//Sensitive signal list reg_haomiao_ge or miao_ge or miao_shi or fen_ge or fen_shi or shi_ge or shi_shi or select
    begin
        if(select == 3'd0)
        begin
            wei <= 8'b11111110; //Millisecond single digit display
            case(reg_haomiao_ge)
                4'b0000:duan <= 8'b1100_0000;//0
                4'b0001:duan <= 8'b1111_1001;//1
                4'b0010:duan <= 8'b1010_0100;//2
                4'b0011:duan <= 8'b1011_0000;//3
                4'b0100:duan <= 8'b1001_1001;//4
                4'b0101:duan <= 8'b1001_0010;//5
                4'b0110:duan <= 8'b1000_0010;//6
                4'b0111:duan <= 8'b1111_1000;//7
                4'b1000:duan <= 8'b1000_0000;//8
                4'b1001:duan <= 8'b1001_0000;//9
                default:duan <= 8'hff;
            endcase
        end
        else if(select == 3'd1)
        begin
            wei <= 8'b11111101;//Tens digit display of milliseconds
            case(reg_haomiao_shi)
                4'b0000:duan <= 8'b1100_0000;//0
                4'b0001:duan <= 8'b1111_1001;//1
                4'b0010:duan <= 8'b1010_0100;//2
                4'b0011:duan <= 8'b1011_0000;//3
                4'b0100:duan <= 8'b1001_1001;//4
                4'b0101:duan <= 8'b1001_0010;//5
                4'b0110:duan <= 8'b1000_0010;//6
                4'b0111:duan <= 8'b1111_1000;//7
                4'b1000:duan <= 8'b1000_0000;//8
                4'b1001:duan <= 8'b1001_0000;//9
                default:duan <= 8'hff;
            endcase
        end
        else if(select == 3'd2)
        begin
            wei <= 8'b11111011;//Single digit display of seconds
            case(reg_miao_ge)
                4'b0000:duan <= 8'b1100_0000;//0
                4'b0001:duan <= 8'b1111_1001;//1
                4'b0010:duan <= 8'b1010_0100;//2
                4'b0011:duan <= 8'b1011_0000;//3
                4'b0100:duan <= 8'b1001_1001;//4
                4'b0101:duan <= 8'b1001_0010;//5
                4'b0110:duan <= 8'b1000_0010;//6
                4'b0111:duan <= 8'b1111_1000;//7
                4'b1000:duan <= 8'b1000_0000;//8
                4'b1001:duan <= 8'b1001_0000;//9
                default:duan <= 8'hff;
            endcase
        end

        else if(select == 3'd3)
        begin
            wei <= 8'b11110111;//Ten digit display of seconds
            case(reg_miao_shi)
                3'b000:duan <= 8'b1100_0000;
                3'b001:duan <= 8'b1111_1001;
                3'b010:duan <= 8'b1010_0100;
                3'b011:duan <= 8'b1011_0000;
                3'b100:duan <= 8'b1001_1001;
                3'b101:duan <= 8'b1001_0010;
                3'b110:duan <= 8'b1000_0010;
                default:duan <= 8'hff;
            endcase
        end

        else if(select == 3'd4)
        begin
            wei <= 8'b11101111;//Single digit display of minutes
            case(reg_fen_ge)
            4'b0000:duan <= 8'b1100_0000;
            4'b0001:duan <= 8'b1111_1001;
            4'b0010:duan <= 8'b1010_0100;
            4'b0011:duan <= 8'b1011_0000;
            4'b0100:duan <= 8'b1001_1001;
            4'b0101:duan <= 8'b1001_0010;
            4'b0110:duan <= 8'b1000_0010;
            4'b0111:duan <= 8'b1111_1000;
            4'b1000:duan <= 8'b1000_0000;
            4'b1001:duan <= 8'b1001_0000;
            default:duan <= 8'hff;
            endcase
        end

        else if(select == 3'd5)
        begin
            wei <= 8'b11011111;//Ten digit display of minutes
            case(reg_fen_shi)
            3'b000:duan <= 8'b1100_0000;
            3'b001:duan <= 8'b1111_1001;
            3'b010:duan <= 8'b1010_0100;
            3'b011:duan <= 8'b1011_0000;
            3'b100:duan <= 8'b1001_1001;
            3'b101:duan <= 8'b1001_0010;
            3'b110:duan <= 8'b1000_0010;
            default:duan <= 8'hff;
            endcase
        end

        else if(select == 3'd6)
        begin
            wei <= 8'b10111111; //clock single digit display
            case(reg_shi_ge)
            4'b0000:duan <= 8'b1100_0000;
            4'b0001:duan <= 8'b1111_1001;
            4'b0010:duan <= 8'b1010_0100;
            4'b0011:duan <= 8'b1011_0000;
            default:duan <= 8'hff;
            endcase
        end

        else
            begin
            wei <= 8'b01111111;//clock ten digit display
            case(reg_shi_shi)
            3'b000:duan <= 8'b1100_0000;
            3'b001:duan <= 8'b1111_1001;
            3'b010:duan <= 8'b1010_0100;
            default:duan <= 8'hff;
            endcase
        end
    end
endmodule