Подсчет входной частоты параллельного порта - C #

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

    [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;
            }
        }
    }

ВЫХОД:

введите описание изображения здесь введите описание изображения здесь  введите описание изображения здесь

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


person Farid-ur-Rahman    schedule 16.07.2012    source источник
comment
Всегда ли значение импульса выключения равно 120 или оно может быть немного больше или меньше 120?   -  person Monroe Thomas    schedule 18.07.2012


Ответы (3)


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

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

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

person zmbq    schedule 16.07.2012

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

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.

person Alvin Wong    schedule 16.07.2012

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

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

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

Вот пример создания сэмплов. Вы можете заменить использование 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);
        }
    }
}
person Monroe Thomas    schedule 17.07.2012