Count Входная частота параллельного порта - С#

Я должен подсчитать входную частоту параллельного порта на выводе № 13, начиная с таймера 555 таймера, реальная частота должна составлять около 3-4 Гц (ON Pulse). Я несколько раз пробовал несколько кодов, но каждый раз, когда они дают разные значения. Я пробовал следующий код:

    [DllImport("inpout32.dll", EntryPoint = "Inp32")]
    public static extern int Input(int adress);

    private void button1_Click(object sender, EventArgs e)
    {
        int currentState = Input(889);
        int LastState;
        while (true)
        {
            int State = Input(889);
            if (State != currentState)
            {
                if (Input(889) == 120)
                {
                    LastState = 0;
                }
                else
                {
                    LastState = 1;
                }
                break;
            }
        }
        GetFreq(LastState);

    }
    void GetFreq(int LastPulse)
    {
        int highPulseFreq = 0;
        int lowPulseFreq = 0;
        if (LastPulse == 1)
        {
            highPulseFreq++;
        }
        if (LastPulse == 0)
        {
            lowPulseFreq++;
        }
        int startTime = DateTime.Now.Second;
        while (true)
        {
            if (startTime == DateTime.Now.Second)
            {
                if (Input(889) != 120)// ON
                {
                    if (LastPulse == 0)
                    {
                        highPulseFreq++;
                        LastPulse = 1;
                    }
                }
                else
                {
                    if (LastPulse == 1)
                    {
                        lowPulseFreq++;
                        LastPulse = 0;
                    }
                }
            }
            else
            {
                MessageBox.Show("ON Pulses: " + highPulseFreq.ToString() + Environment.NewLine + "OFF Pulses: " + lowPulseFreq.ToString());
                break;
            }
        }
    }

ВЫВОД:

enter image description hereenter image description hereenter image description here

Что мне делать, чтобы получить точную частоту? Что-то не так в моем коде? Я использую inpout32.dll для управления параллельным портом.

Ответ 1

Попробуйте вместо этого использовать следующую функцию:

double GetFreq(long time, out int highCount, out int lowCount)
{
    const int ADDRESS = 0x378 + 1, MASK = 0x10;
    highCount = lowCount = 0;
    bool LastState = (Input(ADDRESS) & MASK) == MASK;
    if (LastState)
    {
        highCount++;
    }
    else
    {
        lowCount++;
    }
    System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
    stopwatch.Start();
    while (stopwatch.ElapsedMilliseconds <= time)
    {
        if ((Input(ADDRESS) & MASK) == MASK) // High
        {
            if (!LastState)
            {
                highCount++;
                LastState = true;
            }
        }
        else
        {
            if (!LastState)
            {
                lowCount++;
                LastState = false;
            }
        }
    }
    stopwatch.Stop();
    return ((double)(highCount + lowCount)) / time * 500
}

И когда вам нужно вызвать функцию, просто выполните следующие действия:

int highCount, lowCount;
double frequenct = GetFreq(1000, out highCount, out lowCount);

В моем коде я использовал побитовый оператор AND для маскировки ненужных битов, который должен быть лучше, чем прямое сравнение с 120. Помните, когда результаты побитовые, никогда не сравнивайте напрямую с помощью операторов == или !=.

Я использовал System.Diagnostics.Stopwatch, который больше намного больше, чем при использовании DateTime.Now.Second.

Ответ 2

Ты делаешь все, что-то не так. Во-первых, вы считаете импульсы целую секунду, вы считаете импульсы до секунды (зависит от того, где вызывается второй GetFreq).

Во-вторых, вы подсчитываете импульсы вверх и вниз, хотя я думаю, что частота должна быть числом импульсов up (или down) каждую секунду, а не их обоих (это будет вдвое больше частоты).

И, наконец, если вы хотите измерить 3 или 4 Гц, измерение в течение одной секунды приведет к ошибкам округления. Попробуйте измерить в течение 5 секунд. Используйте Stopwatch для измерения этих 5 секунд.

Ответ 3

Вам нужно пробовать свой сигнал со скоростью, которая по крайней мере вдвое превышает максимальную частоту вашего сигнала. Если ваша ожидаемая максимальная частота составляет около 4 Гц, то выборка сигнала в любом месте от 15 до 20 Гц должна давать хорошие результаты.

К счастью, выборка с такой скоростью - это то, что можно сделать без чрезмерного использования с высокоточными таймерами в Windows (если вам не требуется большая точность). Частота дискретизации 20 Гц соответствует периоду выборки в 50 мс, поэтому вы можете использовать цикл, в котором вы спите около 50 мс между значениями записи образца. Вы не получите сверхточную дельта-T между образцами (вы можете видеть вариации до 15-30 мс за время между каждым образцом, в зависимости от вашей системы), но он должен быть достаточно хорош для частот, с которыми вы работаете с.

Вы можете записать несколько секунд образцов (и связанных временных меток), а затем экспортировать данные в электронную таблицу. Однажды в электронной таблице вы можете выполнить анализ и графику. Или вы можете найти код анализа временных рядов для анализа списка образцов, например, с использованием преобразования Фурье (FFT) для преобразования сигнала из временной области в частотную область.

Вот пример создания образцов. Вы можете заменить использование DateTime.Now на StopWatch в GetInputSamples, если вам действительно нужна более высокая точность в метках времени.

[DllImport("inpout32.dll", EntryPoint = "Inp32")] 
public static extern int Input(int adress); 

struct Sample 
{
    public int Value;
    public int Milliseconds;
};

private void button1_Click(object sender, EventArgs e) 
{ 
    TimeSpan duration = TimeSpan.FromSeconds(5);
    TimeSpan samplePeriod = TimeSpan.FromMilliseconds(50);

    var samples = GetInputSamples(889, duration, samplePeriod);
    SaveSamplesCSV(samples, "test.csv");
} 

private static List<Sample> GetInputSamples(int inputPort, TimeSpan duration, TimeSpan samplePeriod)
{ 
    List<Sample> samples = new List<Sample>();

    var oldPriority = Thread.CurrentThread.Priority;
    try
    {
        Thread.CurrentThread.Priority = ThreadPriority.Highest;

        DateTime start = DateTime.Now;
        while (DateTime.Now - start < duration)
        {
            int value = Input(inputPort); 
            TimeSpan timestamp = DateTime.Now - start;

            samples.Add(new Sample() { Value = value, Milliseconds = (int)timestamp.TotalMilliseconds });

            Thread.Sleep(samplePeriod);
        }
    }
    finally
    {
        Thread.CurrentThread.Priority = oldPriority;
    }

    return samples;
}

private static void SaveSamplesCSV(List<Sample> samples, string fileName)
{
    using (StreamWriter writer = File.CreateText(fileName))
    {
        writer.WriteLine("Sample, Time (ms)");
        foreach (var sample in samples)
        {
            writer.WriteLine("{0}, {1}", sample.Value, sample.Milliseconds);
        }
    }
}