计数并行端口输入频率 - C#

时间:2012-07-16 06:30:46

标签: c# input parallel-port time-frequency

我必须计算引脚号为13的并行端口的输入频率,来自555定时器IC,实际频率应为3-4 Hz左右(ON脉冲)。我已经尝试了几次代码,但是每次都会给出不同的值。我尝试了以下代码:

    [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 here enter image description here enter image description here

我该怎么做才能获得准确的频率?我的代码有什么问题吗? 我正在使用inpout32.dll来控制并行端口。

3 个答案:

答案 0 :(得分:0)

请尝试使用以下功能:

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更精确

答案 1 :(得分:0)

你做各种各样的事情有点不对劲。首先,你计算脉冲一整秒,你计算脉冲直到一秒钟(取决于第二个GetFreq被调用的位置)。

其次,你是在计数上下脉冲,虽然我认为频率应该是每秒上升(或下降)脉冲的数量,而不是它们两者(这将是频率的两倍)。

最后,如果你想测量3或4 Hz,测量一秒钟会引入舍入误差。尝试测量5秒钟。使用Stopwatch来衡量这5秒。

答案 2 :(得分:0)

您需要以至少是信号中最高频率两倍的速率对信号进行采样。如果您预期的最高频率约为4Hz,那么在15-20Hz的任何地方对信号进行采样都应该会产生良好的效果。

幸运的是,以这种速率进行采样是可以在Windows上使用高精度计时器进行过多考虑(如果您不需要很高的准确度)。 20Hz的采样率对应于50ms的采样周期,因此您可以使用一个循环,在您记录采样值之间约50ms。您不会在样本之间获得超精确的delta-T(根据您的系统,您可能会在每个样本之间看到最多15-30ms的变化,这取决于您的系统),但它应该足以满足您处理的频率用。

您可以记录几秒钟的样本(以及相关的时间戳),然后将数据导出到电子表格中。进入电子表格后,您可以进行一些分析和绘图。或者您可以找到一些时间序列分析代码来分析样本列表,例如使用傅里叶变换(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);
        }
    }
}