zoukankan      html  css  js  c++  java
  • C# 消除累计误差的倒计时

    使用 C# 中自带的各种 timer 计时,都会有累计误差,以下代码实现了一种消除累计误差的方法,使得每次计时的误差,空值在 100 ms 以内(可以通过修改代码提升精度。)
    对于精度要求在秒级别的简单计时应用来说,误差可接受,并且消除累计误差。

    以下是代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Timers;
    
    namespace Xxx.Utils
    {
        /// <summary>
        /// 带有校准功能的秒钟计时器(误差最大100ms)
        /// </summary>
        public class ClockTimer : IDisposable
        {
            private readonly Timer _driveTimer;
            private int _intervalSeconds = 1;
            private double _startMilliSeconds;
            private long _tickCount;
            private bool _enabled;
    
            public ClockTimer()
            {
                _driveTimer = new Timer(100);
                _driveTimer.Elapsed += DriveTimerOnElapsed;
            }
    
            public ClockTimer(int intervalSeconds) : this()
            {
                _intervalSeconds = intervalSeconds;
            }
    
            /// <summary>
            /// 获取或设置<see cref="ClockTimer"/>的触发时间间隔,单位:秒。
            /// </summary>
            public int IntervalSeconds
            {
                get => _intervalSeconds;
                set => _intervalSeconds = value < 1 ? 1 : value;
            }
    
            /// <summary>
            /// 获取或设置一个值,该值指示<see cref="ClockTimer"/>是否引发<see cref="Elapsed"/>事件。
            /// </summary>
            public bool Enabled
            {
                get => _enabled;
                set
                {
                    if (value)
                    {
                        Start();
                    }
                    else
                    {
                        Stop();
                    }
                }
            }
    
            /// <summary>
            /// 到达时间间隔时发生。
            /// </summary>
            public event EventHandler<ElapsedEventArgs> Elapsed;
    
            /// <summary>
            /// 开始计时
            /// </summary>
            public void Start()
            {
                _driveTimer.Start();
                _enabled = true;
                _startMilliSeconds = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
            }
    
            /// <summary>
            /// 结束计时
            /// </summary>
            public void Stop()
            {
                _driveTimer.Stop();
                _tickCount = 0;
                _enabled = false;
            }
    
            private void DriveTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
            {
                double currentMilliseconds = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
    
                // 第一个 100 ms,直接返回。
                if (_tickCount == 0 && Math.Abs(currentMilliseconds - _startMilliSeconds) < 100)
                {
                    return;
                }
    
                if (Math.Abs(currentMilliseconds - (_startMilliSeconds + (_tickCount + 1) * 1000)) <= 100)
                {
                    _tickCount++;
                    if (_tickCount % IntervalSeconds == 0)
                    {
                        Elapsed?.Invoke(this, elapsedEventArgs);
                    }
                }
            }
    
            public void Dispose()
            {
                _driveTimer?.Dispose();
            }
        }
    }
    
  • 相关阅读:
    软件工程---作业---分析
    软件体系结构---团队项目---个人工作-4
    软件体系结构---团队项目---个人工作-3
    软件体系结构---团队项目---个人工作-2
    软件体系结构---团队项目---个人工作
    软件工程博客---团队项目---个人设计1
    UML-类图
    工大助手--C#之DataGrid
    团队项目——工大助手界面(查询部分)
    团队项目——工大助手界面(登录部分)
  • 原文地址:https://www.cnblogs.com/jasongrass/p/10422855.html
Copyright © 2011-2022 走看看