Stoper, odliczanie czasu - niedokładne odlicznaie

0

Witam.
Mam pewnien kłopot z odliczaniem czasu. Chciałem zrobić program stoper. Naciskam start, zaczyna liczyc i wyswietla na bieŻąco czas jaki upływa.
Gdy odliczam w sekundach jest ok. Ale gdy odliczam w milisekundach, sekunda na ekranie jest o kilkanaście milisekund dłuższa od tej z zegarka (z systemu na przykład).

Wykorzystuję Timer'a z toolbox'a w Visual Studio. Gdy Interval jest ustawiony na 1000 wszystko jest ok, ale gdy ustawie na 100 ms to już sie zaczyna sypać. Rozumiem ze pewnie inne rzeczy w tle zajmują ten dodatkowy czas, no ale stoper powinien działać nawet mimo to.

Prawdopodobnie nie znam jakiegoś haczyka. Czy mógłby ktoś podnunąć pomysł?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace licznik
{
public partial class Licznik : Form
{
Stoper nowyStoper;

    public Licznik()
    {
        nowyStoper = new Stoper() { Godzny = 0, Minuty = 0, Sekundy = 0, Mili=0 };
        
        InitializeComponent();
    }


    private void buttonStart_Click(object sender, EventArgs e)
    {
      timer1.Enabled = true;   
    }

    private void buttonStop_Click(object sender, EventArgs e)
    {
      timer1.Enabled = false;
      nowyStoper.wyswietl(ref labelStoper);              
    }

    private void timer1_Tick(object sender, EventArgs e)
    {

     nowyStoper.liczCzas();  
     nowyStoper.wyswietl(ref labelStoper);

    }

    private void buttonReset_Click(object sender, EventArgs e)
    {
      timer1.Enabled = false;
      nowyStoper.reset();
      nowyStoper.wyswietl(ref labelStoper);
    }

   
}

}


<code class="c#">using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace licznik
{
    class Stoper
    {
        private int godziny;
        private int minuty;
        private int sekundy;
        private int mili;
        

        public void liczCzas()
        {

            mili++;
            if(mili>9)
            {
                sekundy++;
                mili = 0;
                if (sekundy > 59)
                {
                    minuty++;
                    sekundy = 0;
                    if (minuty > 59)
                    {
                        godziny++;
                        minuty = 0;
                    }
                }
            }

        
        }

        public void wyswietl(ref Label pokaz)
        {
            pokaz.Text = godziny.ToString("00") + ":" + minuty.ToString("00") + ":" + sekundy.ToString("00") + ":" + mili.ToString("0");
        }
        
        public void reset ()
        {
            godziny = minuty = sekundy = mili = 0;
        }

        public int Mili { get { return mili; } set { mili = value; } }
        public int Sekundy { get { return sekundy; } set { sekundy = value; } }
        public int Minuty { get { return minuty; } set { minuty = value; } }
        public int Godzny { get { return godziny; } set { godziny = value; } }
        

    }
}

 
0

W dużym skrócie:

The default timer resolution on Windows is 15.6 ms – a timer interrupt 64 times a second.

Nigdy nie osiągniesz dokładnego wyniku, pamiętaj, że Windows nie jest systemem realtime.
Skupiłbym się raczej na wyświetlaniu czasu z dokładnością do 1 sekundy.

Linki do poczytania:
https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/
http://stackoverflow.com/questions/1512294/what-is-the-maximum-precision-of-the-timer-in-net

0

Używaj różnicy czasów startowego i aktualnego zamiast ręcznego liczenia milisekundami - komputer się chwilę zwiesi, a twój program zakrzywi czasoprzestrzeń.

1

Dokładnie tak jak napisał kolega @spartanPAGE z tym, że zamiast wyliczać różnice czasu możesz użyć gotowej klasy: https://msdn.microsoft.com/pl-pl/library/system.diagnostics.stopwatch%28v=vs.110%29.aspx

0

Tego też sie obawiałem, że czas nie bedzie dokładnie liczony. Lecz ciągle mi siedzi jedna myśl w głowie. Przecież w grach, np wyścigowych, też czas jest liczony w ms.
Czy tamten też jest liczony źle? Albo stoper z Windows Phone, też powinien liczyć dokładnie. Więc czy istnieje sposób, żeby jakoś zniwelować tą słabą rozdzielczość?

0

Wysoką precyzję masz w Stopwatch, na timer-ach wbudowanych w system nie masz co polegać.

Obczaj sobie jeszcze to, opiera się właśnie o Stopwatch:
http://ideveloper-dotnet.blogspot.com/2013/07/real-time-timer-in-c.html

0

Dziękuję za pomoc. Udało się rozwiązać problem przez Stopwatch. Timera uzywam tylko zeby odświeżać ekran (no chyba ze sa lepsze sposoby).

Dodaję kod, może komuś się przyda.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace licznik2
{
public partial class Form1 : Form
{
Stopwatch stoper = new Stopwatch();
public Form1()
{
InitializeComponent();
}

    private void buttonStart_Click(object sender, EventArgs e)
    {//==========BUTON=START==============
        timer1.Enabled = true;
    }

    private void buttonStop_Click(object sender, EventArgs e)
    {//=========BUTTON=STOP================
        timer1.Enabled = false;
        stoper.Stop();
        TimeSpan ts = stoper.Elapsed;
        string elapsedTime = String.Format
             ("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
        labelStoper.Text=elapsedTime;
    }

    private void buttonReset_Click(object sender, EventArgs e)
    {//========BUTTON=RESET=================
        stoper.Reset();
        string resetTime = String.Format
            ("{0:00}:{1:00}:{2:00}.{3:00}", 0, 0, 0, 0);
        labelStoper.Text = resetTime;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {//===========TIMER1================
        stoper.Stop();
        TimeSpan ts = stoper.Elapsed;
        string elapsedTime = String.Format
            ("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds,ts.Milliseconds / 10);
        labelStoper.Text = elapsedTime;
        stoper.Start();
    }
}

}

1 użytkowników online, w tym zalogowanych: 0, gości: 1