Obținerea de cecuri precise dintr-un cronometru în C #

Încerc să reconstruiesc o aplicație metronomică veche care a fost inițial scrisă folosind MFC în C ++ pentru a fi scrisă în .NET folosind C #. Una dintre problemele pe care le întâlnesc este să primești timer-ul pentru a "bifa" suficient de precis.

De exemplu, presupunând un BPM ușor (bate pe minut) de 120, timer-ul ar trebui să bifeze la fiecare 5 secunde (sau 500 milisecunde). Folosind acest lucru ca bază pentru căpușe, cu toate acestea, nu este complet exacte, deoarece .NET garantează doar că timer-ul dvs. nu va bifa înainte de a trecut timpul scurs.

În prezent, pentru a obține în jurul valorii de acest lucru pentru același exemplu de BPM de 120 de mai sus, am setarea căpușe la ceva de genul 100 de milisecunde și numai redarea sunetului de clic pe fiecare cronometru cronometrul 5. Acest lucru îmbunătățește destul de mult precizia, dar dacă se simte ca un pic de hack.

Deci, care este cel mai bun mod de a obține căpușe exacte? Știu că există mai multe temporizatoare disponibile decât timer-urile pentru ferestre, care sunt disponibile în Visual Studio, dar nu sunt cu adevărat familiarizați cu ele.

0
fr hi bn

6 răspunsuri

Ce este aplicația C ++? Puteți folosi întotdeauna același lucru sau puteți împacheta codul cronometrului din C ++ într-o clasă C ++/CLI.

0
adăugat

Există trei clase de timp numite "Timer" în .NET. Se pare că utilizați Windows Forms unul, dar de fapt, ați putea găsi clasa System.Threading.Timer mai utilă - dar aveți grijă pentru că apelează înapoi la un fir de rezervă, astfel încât să nu puteți interacționa direct cu formularul dvs. apelul invers.

O altă abordare ar putea fi p/invocarea cronometrelor multimedia Win32 - timeGetTime, timeSetPeriod, etc.

A quick Google found this, which might be useful http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx

"Multimedia" (temporizator) este cuvântul buzunar pe care îl căutați în acest context.

0
adăugat

Clasele de temporizare pot începe să se comporte ciudat atunci când codul evenimentului "bifați" nu este terminat executând până când apare următoarea "bifare". O modalitate de a combate acest lucru este de a dezactiva temporizatorul la începutul evenimentului de bifare, apoi reactivați-l la sfârșit.

Cu toate acestea, această abordare nu este adecvată în cazurile în care timpul de execuție a codului "tick" nu este o eroare acceptabilă în momentul cronometrării, deoarece timerul va fi dezactivat (nu se ia în calcul) în acel moment.

Dacă dezactivarea cronometrului este o opțiune, atunci puteți obține același efect creând un fir separat care execută, doarme pentru milisecunde, execută, doarme, etc.

0
adăugat
Dreapta. Sunt de acord cu ceea ce ați spus despre faptul că nu ați reușit să identificați momentul următoarei bifaturi. Ideea a ceea ce spun este că nu doriți să executați codul evenimentului de bifare dintr-o bifă anterioară când apare bifarea următoare.
adăugat autor Brad Barker, sursa
Dar atunci nu poți fi decât sigur că firul doarme cel puțin x milisecunde; planificatorul de fire nu certifică faptul că firul va rula la numărul exact de millesond
adăugat autor Wilhelm, sursa

System.Windows.Forms.Timer is limited to an accuracy of 55 milliseconds...

0
adăugat
@MajesticRa: msdn.microsoft.com/en-us/biblioteca/& hellip; Vezi Text în casetă galbenă
adăugat autor Anthony Sottile, sursa
Există niște documente oficiale despre asta?
adăugat autor MajesticRa, sursa
Mulțumesc! Când am scris-o mi-a lipsit punctul în care yazanpro înseamnă exact Former timer. Și sa gândit că vorbește despre timeri în general. Dar vă mulțumesc foarte mult pentru răspunsul dvs.!
adăugat autor MajesticRa, sursa

I have had this problem when developing a recent data-logging project. The problem with the .NET timers ( windows.forms, system.threading, and system.timer ) is that they are only accurate down to around 10 milli seconds which is due to the event scheduling built into .NET I believe. ( I am talking about .NET 2 here ). This wasn't acceptable for me and so I had to use the multimedia timer ( you need to import the dll ). I also wrote a wrapper class for all the timers and so you can switch between them if necessary using minimal code changes. Check out my blog post here: http://www.indigo79.net/archives/27

0
adăugat

O altă posibilitate este că există o eroare în implementarea wpf a DispatcherTimer (există o nepotrivire între milisecunde și căpușe care cauzează inexactitate potențială în funcție de timpul de execuție exact al procesului), după cum se arată mai jos:

http://referencesource.microsoft.com/#WindowsBase /Base/System/Windows/Threading/DispatcherTimer.cs,143

class DispatcherTimer
{
    public TimeSpan Interval
    {
        set
        {
            ...
            _interval = value;
           //Notice below bug: ticks1 + milliseconds [Bug1]
            _dueTimeInTicks = Environment.TickCount + (int)_interval.TotalMilliseconds;
        }
    }
}

http://referencesource.microsoft.com/#WindowsBase/Base /System/Windows/Threading/Dispatcher.cs

class Dispatcher
{
    private object UpdateWin32TimerFromDispatcherThread(object unused)
    {
        ...
        _dueTimeInTicks = timer._dueTimeInTicks;
        SetWin32Timer(_dueTimeInTicks);
    }

    private void SetWin32Timer(int dueTimeInTicks)
    {
        ...
       //Notice below bug: (ticks1 + milliseconds) - ticks2  [Bug2 - almost cancels Bug1, delta is mostly milliseconds not ticks]
        int delta = dueTimeInTicks - Environment.TickCount; 
        SafeNativeMethods.SetTimer( 
            new HandleRef(this, _window.Value.Handle),
            TIMERID_TIMERS,
            delta);//<-- [Bug3 - if delta is ticks, it should be divided by TimeSpan.TicksPerMillisecond = 10000]
    }
}

http://referencesource.microsoft.com/#WindowsBase/Shared /MS/Win32/SafeNativeMethodsCLR.cs,505

class SafeNativeMethodsPrivate
{
    ...
    [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling=true, CharSet=System.Runtime.InteropServices.CharSet.Auto)]
    public static extern IntPtr SetTimer(HandleRef hWnd, int nIDEvent, int uElapse, NativeMethods.TimerProc lpTimerFunc);
}

http://msdn.microsoft .com/ro-ne/biblioteca/ferestre/de masă/ms644906% 28V = vs.85% 29.aspx

uElapse [in]
Type: UINT
The time-out value, in milliseconds.//<-- milliseconds were needed eventually
0
adăugat