LoginSignup
1
1

More than 5 years have passed since last update.

C++ Builder XE4 > TTimer > 100ミリ秒程度の誤差で1秒インターバルを行う (蓄積しない誤差)

Last updated at Posted at 2018-12-06
動作環境
C++ Builder XE4

蓄積する誤差

  • TTimerを1,000ミリ秒で動かす
    • 1,014ミリ秒程度のインターバルになる
      • 実測

14ミリ秒の誤差は86400秒/日で1秒/回コールすると
86400 * 14 / 1000 = 1209.6秒のずれになる。

蓄積しないための実装を検討した。

実装案

  • 別のタイマー(アラームタイマー)を用意
  • TTimerは短いインターバル(例:100ミリ秒)で実施する
  • TTimer内でアラームタイマーの時刻と現在時刻を比較する

実装例

Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE で管理されるコンポーネント
    TTimer *Timer1;
    void __fastcall Timer1Timer(TObject *Sender);
    void __fastcall FormShow(TObject *Sender);
private:    // ユーザー宣言
    TDateTime m_nextAlarm;  // 次のアラーム時刻
public:     // ユーザー宣言
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <DateUtils.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    Timer1->Enabled = false;
    Timer1->Interval = 100;  // 55ミリ秒以下にはしない (発火しない)
    Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    if (Now() < m_nextAlarm) {
        return;
    }

    m_nextAlarm = IncSecond(m_nextAlarm, 1);
    OutputDebugString(Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz").c_str());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
    m_nextAlarm = Now();
}
//---------------------------------------------------------------------------

動作例

デバッグ出力: 2018/12/06 12:05:24.772 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:25.758 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:26.735 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:27.721 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:28.704 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:29.687 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:30.779 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:31.763 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:05:32.743 プロセス Project1.exe (1348)
(中略)
デバッグ出力: 2018/12/06 12:08:35.728 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:36.709 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:37.689 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:38.785 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:39.768 プロセス Project1.exe (1348)
デバッグ出力: 2018/12/06 12:08:40.749 プロセス Project1.exe (1348)

100ミリ秒程度の誤差であるが、その誤差は蓄積されない。

関連

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1