C語言實現電子秒表

秒表是我們生活中常見的計時工具,特別是在運動會等比賽中,今天我就來寫一個簡單的電子秒表。

實現思路

這裡簡單介紹一下我的實現思路:

1、簡單版:簡單版本隻實現瞭單次計時功能,即每次開啟程序後就開始計時,如果按下鍵盤任意鍵,就結束計時,計時通過Sleep(1000)延時實現,每過1秒,計數值(總秒數)cnt加1,打印時,將總秒數cnt轉換成時分秒進行顯示。【Sleep()函數並不準確,隻能實現粗略延時】

2、高級版:實現毫秒級計時,可重復計時(暫停、清零),計時使用gettimeofday()函數,用來獲取系統的秒數和毫秒數,將計時開始和計時暫停的秒數相減,即可獲得計時期間的秒數。細節請看代碼部分。

簡易版本

#include <stdio.h>
#include <conio.h>              //kbhit()/_kbhit()
#include <Windows.h>            //Sleep(ms)

int main()
{
    int hour = 0, min = 0, sec = 0;
    int cnt = 0;

    printf("按任意鍵停止計時\n");
    while(!_kbhit())            //任意鍵退出循環(結束計時)
    {
        hour = cnt / 3600;      //獲取計時小時數
        min = cnt / 60;          //獲取計時分鐘數
        sec = cnt % 60;         //獲取計時秒數
        printf("  %02d:%02d:%02d\r", hour, min, sec);
        Sleep(1000);            //1s延時
        cnt++;
    }
    printf("\n程序退出\n");
    return 0;
}

運行效果:

高級版本

代碼可能一般,但至少功能已經實現,僅供參考

下面給出幾個註釋的解釋:

  • 計時初始時間指的是開始計時或繼續計時時的系統時間(第一次暫停後,如果繼續計時,此時的系統時間即為新的計時初始時間)
  • 當前累計計時時長指的是從開始計時到當前時刻的時間差,即真正的有效計時時長
  • 總累計計時時長指的是計時初始時間之前的計時時間,這個值隻有在計時暫停時才進行更新(如第一次暫停時,總累計計時時長 = 第一次暫停的系統時間 – 開始計時時的系統時間;第二次暫停時,總累計計時長 = 總累計計時時長 + 第二次在暫停的系統時間 – 上次繼續計時時的系統時間…)
#include <stdio.h>
#include <conio.h>                 //kbhit()/_kbhit() getch()
#include <Windows.h>               //Sleep(ms)
#include <sys/time.h>              //struct timeval
#include <unistd.h>                //struct timeval

/******************************************************************************
 * @brief       獲取系統當前秒數和毫秒(1970-1-1 0:0:0到現在)
 * @param tv    timeval結構體變量
 * @param tv_s  返回的秒數
 * @param tv_ms 返回的毫秒數
 ******************************************************************************/
void Get_Current_Timeval(struct timeval *tv, long *tv_s, long *tv_ms)
{
    gettimeofday(tv,NULL);      //獲取1970-1-1到現在的時間保存到timeval變量
    *tv_s = tv->tv_sec;         //獲取秒
    *tv_ms = tv->tv_usec / 1000;//獲取毫秒
}

/******************************************************************************
 * @brief            獲取兩個timeval成員的差值,通過tv_s_diff和tv_ms_diff返回
 * @param tv_s_cur   當前系統時間秒數
 * @param tv_ms_cur  當前系統時間毫秒數
 * @param tv_s_old   計時初始時間(s)
 * @param tv_ms_old  計時初始時間(ms)
 * @param tv_s_diff  秒數的差值
 * @param tv_ms_diff 毫秒的差值
 ******************************************************************************/
void Get_Diff_Timeval(long tv_s_cur, long tv_ms_cur,\
                      long tv_s_old, long tv_ms_old,\
                      long *tv_s_diff, long *tv_ms_diff)
{
    if(tv_ms_cur < tv_ms_old)
    {
        *tv_ms_diff = tv_ms_cur + 1000 - tv_ms_old;  //獲取這段時間的毫秒數
        *tv_s_diff = tv_s_cur - tv_s_old - 1; //獲取這段時間的秒數(自上次暫停或自初始時間)
    }
    else
    {
        *tv_ms_diff = tv_ms_cur - tv_ms_old;  //獲取這段時間的毫秒數(自上次暫停或自初始時間)
        *tv_s_diff = tv_s_cur - tv_s_old;     //獲取這段時間的秒數(自上次暫停或自初始時間)
    }
}

/******************************************************************************
 * 主函數
 * ****************************************************************************/
int main(void)
{
    struct timeval tv;
    long tv_s_cur = 0, tv_ms_cur = 0;   //當前系統時間
    long tv_s_old = 0, tv_ms_old = 0;   //計時初始時間
    long tv_s_diff = 0, tv_ms_diff = 0; //存放時間的差值
    int sec_cnt = 0, msec_cnt = 0;      //當前累計計時時長
    int hour = 0, min = 0, sec = 0, msec = 0;
    int timer_step = 0;                 //計時步驟 0:未開始,
                                        //1:開始,2:暫停
    char key = 0;

    /**************** 菜單打印 ****************/
    printf("================================\n"); //菜單
    printf("| 空格:開始/暫停 R:清零 Q:退出 |\n");
    printf("================================\n");
    printf("\t%02d:%02d:%02d %02d\r", 0, 0, 0, 0);
    while(1)
    {
        /**************** 鍵盤按鍵掃描+操作 ****************/
        key = 0;
        if(_kbhit())                      //檢測到按鍵按下
            key = getch();                //讀取按鍵
        switch(key)
        {
            case ' ':                     //按空格鍵開始/暫停計時
                if(timer_step == 0)       //如果還未開啟計時
                {
                    //獲取當前秒和毫秒作為計時初始時間
                    Get_Current_Timeval(&tv, &tv_s_old, &tv_ms_old);
                    timer_step = 1;       //開始計時
                }
                else if(timer_step == 1)  //如果正在計時
                {
                    timer_step = 2;       //暫停計時
                    //獲取當前秒和毫秒
                    Get_Current_Timeval(&tv, &tv_s_cur, &tv_ms_cur);
                    //獲取當前系統時間與計時初始時間的差值
                    Get_Diff_Timeval(tv_s_cur, tv_ms_cur, tv_s_old,\
                                     tv_ms_old, &tv_s_diff, &tv_ms_diff);
                    msec_cnt += tv_ms_diff;       //更新總累計計時時長(ms)
                    if(msec_cnt >= 1000)
                    {
                        msec_cnt -= 1000;
                        sec_cnt += tv_s_diff + 1; //更新總累計計時時長(s)
                    }
                    else
                        sec_cnt += tv_s_diff;
                }
                else if(timer_step == 2)
                {
                    timer_step = 1;                //繼續計時
                    //獲取當前秒和毫秒
                    Get_Current_Timeval(&tv, &tv_s_cur, &tv_ms_cur);
                    tv_s_old = tv_s_cur;           //更新計時初始時間(s)
                    tv_ms_old = tv_ms_cur;         //更新計時初始時間(ms)
                }
                break;
            case 'r':                     //按r/R清零計時時間
            case 'R':
                sec_cnt = msec_cnt = 0;   //總累計計時值清零
                tv_s_old = tv_s_cur;      //更新計時初始時間(s)
                tv_ms_old = tv_ms_cur;    //更新計時初始時間(ms)
                timer_step = 0;           //回到步驟0(未開始計時)
                printf("\t%02d:%02d:%02d %02d\r", 0, 0, 0, 0);
                break;
            case 'q':
            case 'Q': printf("程序退出\n");return 0;
        }

        /**************** 計時操作 ****************/
        if(timer_step == 1)
        {
            //獲取當前秒和毫秒
            Get_Current_Timeval(&tv, &tv_s_cur, &tv_ms_cur);
            //獲取當前系統時間與計時初始時間的差值
            Get_Diff_Timeval(tv_s_cur, tv_ms_cur, tv_s_old,\
                             tv_ms_old, &tv_s_diff, &tv_ms_diff);
            tv_ms_diff += msec_cnt;          //當前累計計時時長(ms)
            if(tv_ms_diff >= 1000)
            {
                tv_ms_diff -= 1000;
                tv_s_diff += sec_cnt + 1;    //當前累計計時時長(s)
            }
            else
                tv_s_diff += sec_cnt;
            hour = tv_s_diff / 3600;         //獲取計時小時數
            min = tv_s_diff /60;             //獲取計時分鐘數
            sec = tv_s_diff % 60;            //獲取計時秒數
            msec = tv_ms_diff / 10;          //獲取毫秒(單位10ms)
            //打印當前累計計時時長
            printf("\t%02d:%02d:%02d %02d\r", hour, min, sec, msec);

        }
        Sleep(10);       //10ms延時,防止打印太快導致顯示效果不佳
    }
    return 0;
}

運行效果:

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: