Netduino home hardware projects downloads community

Jump to content


Photo

System.Diagnostics.Stopwatch class


  • Please log in to reply
8 replies to this topic

#1 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 15 August 2010 - 05:03 PM

Sometimes we need a way to time things.

Here is a performance-optimized StopWatch class, placed in the System.Diagnostics namespace for code compatibility with desktop/mobile C# applications.

System.Diagnostics.Stopwatch.cs
using System;
using Microsoft.SPOT;

namespace System.Diagnostics
{
    class Stopwatch
    {
        private long m_startTicks = 0;
        private long m_stopTicks = 0;
        private bool m_isRunning = false;

        private const long m_ticksPerMillisecond = System.TimeSpan.TicksPerMillisecond;

        public static Stopwatch StartNew()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            return stopwatch;
        }

        private Stopwatch()
        {
        }

        public void Reset()
        {
            m_startTicks = 0;
            m_stopTicks = 0;
            m_isRunning = false;
        }

        public void Start()
        {
            if (m_startTicks != 0 && m_stopTicks != 0)
                m_startTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks - (m_stopTicks - m_startTicks); // resume existing timer
            else
                m_startTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks; // start new timer
            m_isRunning = true;
        }

        public void Stop()
        {
            m_stopTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks;
            m_isRunning = false;
        }

        public long ElapsedMilliseconds
        {
            get
            {
                if (m_startTicks != 0 && m_isRunning)
                    return (Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks - m_startTicks) / m_ticksPerMillisecond;
                else if (m_startTicks != 0 && !m_isRunning)
                    return (m_stopTicks - m_startTicks) / m_ticksPerMillisecond;
                else
                    throw new InvalidOperationException();
            }
        }
    }
}

Attached Files



#2 Don

Don

    New Member

  • Members
  • Pip
  • 2 posts

Posted 08 December 2010 - 09:32 PM

How accurate is time you get back from GetMachineTime on the Netduino? What is the precision and how much drift whould it have over time? I'm wondering if it could be used for timing in sporting events down to the 100th of a second over a 15-20 minute event? Also does the time that is passed in from an InteruptPort event in sync with the GetMachineTime call. I'd like to use program logic to start a timer and then a interupt driven event to stop the timing. I'm assuming they use the same timer source. Many thanks!

#3 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 09 December 2010 - 01:31 AM

How accurate is time you get back from GetMachineTime on the Netduino? What is the precision and how much drift whould it have over time? I'm wondering if it could be used for timing in sporting events down to the 100th of a second over a 15-20 minute event?

Also does the time that is passed in from an InteruptPort event in sync with the GetMachineTime call. I'd like to use program logic to start a timer and then a interupt driven event to stop the timing. I'm assuming they use the same timer source.

Many thanks!


Hi Don,

Among other things, the crystal isn't guaranteed to drive an 18.432MHz crystal with 0% variance, but it's pretty close. It would be interesting to run a test over a few hours/days/months and see exactly how close the time stayed to atomic time.

For 15-20 minutes, I'm guessing that you're fine...but again you may want to take 15-20 minutes and do a quick test.

Welcome to the Netduino community,

Chris

#4 Don

Don

    New Member

  • Members
  • Pip
  • 2 posts

Posted 13 December 2010 - 06:06 PM

Does DateTime.Now and GetMachineTime both use the same underlying time mechanism (tick count I presume)? I did a test with DateTime.Now and it drifted about .4 seconds over an hour. Didn't test GetMachineTime directly but I'm guessing it is the same. I need a bit more accuracy for my application. I was thinking about adding some Real Time Clock (RTC) component and interface it to the Netduino... but I'm not familiar with specific RTC's or how they work. The downside of this is that I really liked how the InteruptPorts took a snapshot of the time and includes it in the event because it accounts for delay int he event queueing in .NET code. I guess I could write some driver level or system code in c++ to modify the interupt to use an RTC component. Could I also use an RTC component (or manual calibration) to just figure out a factor to adjust thee standard time facilities by a fixed percentage> Should the rate at which the clock is fast or slow stay consistant under most conditions (temp, battery conditions, etc)? If so then maybe I can just do a calibration factor and hide it in a wrapper DateTime class. Maybe an extension method to DateTime like DateTime.Adjusted() or DateTime.Calibrated()... which returns an adjusted DateTime from the system ones. thanks Don

#5 Gilberto Garcia

Gilberto Garcia

    New Member

  • Members
  • Pip
  • 8 posts

Posted 08 May 2012 - 05:07 PM

Chris,

Thank you so much for this library. It was a time saver. I added two more methods to the library (ElapsedSeconds and ElapsedMinutes).

public double ElapsedSeconds
        {
            get
            {
                if (m_startTicks != 0 && m_isRunning)
                {
                    TimeSpan duration = new TimeSpan((Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks - m_startTicks));
                    return duration.Seconds;
                }
                else if (m_startTicks != 0 && !m_isRunning)
                {
                    TimeSpan duration = new TimeSpan((m_stopTicks - m_startTicks));
                    return duration.Seconds;
                }
                else
                    throw new InvalidOperationException();
            }
        }

        public double ElapsedMinutes
        {
            get
            {
                if (m_startTicks != 0 && m_isRunning)
                {
                    TimeSpan duration = new TimeSpan((Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks - m_startTicks));
                    return duration.Minutes;
                }
                else if (m_startTicks != 0 && !m_isRunning)
                {
                    TimeSpan duration = new TimeSpan((m_stopTicks - m_startTicks));
                    return duration.Minutes;
                }
                else
                    throw new InvalidOperationException();
            }
        }

Attached Files



#6 Drasive

Drasive

    New Member

  • Members
  • Pip
  • 2 posts

Posted 03 June 2013 - 01:54 PM

I extended the class a little further:

using System;

namespace System.Diagnostics {
    
    public class Stopwatch {
        
        private long _ticksAtStart;
        private long _ticksNow;
        
        
        public bool IsRunning { get; private set; }
        
        public TimeSpan ElapsedDuration {
            get {
                return IsRunning ? new TimeSpan(0, 0, 0, 0, (int)((Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks - _ticksAtStart) / TimeSpan.TicksPerMillisecond))
                                 : new TimeSpan(0, 0, 0, 0, (int)((_ticksNow - _ticksAtStart) / TimeSpan.TicksPerMillisecond));
            }
        }
        
        
        public void Start() {
            _ticksAtStart = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks;
            IsRunning = true;
        }
        
        public void Stop() {
            if (!IsRunning) {
                throw new InvalidOperationException();
            }
            
            _ticksNow = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks;
            IsRunning = false;
        }
        
        public void Resume() {
            if (IsRunning) {
                throw new InvalidOperationException();
            }
            
            _ticksAtStart = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks - (_ticksNow - _ticksAtStart);
            IsRunning = true;
        }
        
        public void Reset() {
            _ticksAtStart = 0;
            _ticksNow = 0;
            IsRunning = false;
        }
        
    }
    
}

Attached Files



#7 84td

84td

    New Member

  • Members
  • Pip
  • 2 posts

Posted 27 December 2013 - 05:01 PM

Hi,

 

Sorry to bump an old thread, but when making use of this code 30 seconds seems to only equal 3 milliseconds?

 

Tested as follows

 

Stopwatch s = new Stopwatch();s.Start();Thread.Sleep(3000);s.Stop();

 

When checking s.ElapsedDuration in Watch I only get 3000 ticks and 3ms..

 

Any ideas?



#8 84td

84td

    New Member

  • Members
  • Pip
  • 2 posts

Posted 27 December 2013 - 05:14 PM

Removed "/ TimeSpan.TicksPerMillisecond" and it now seems to be working fine.



#9 Drasive

Drasive

    New Member

  • Members
  • Pip
  • 2 posts

Posted 30 December 2013 - 09:35 PM

You are correct, my class had a pretty big bug in it, thanks for pointing that out. I updated it and it should work fine now.






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.