0

我必须在 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;
            }
        }
    }

输出:

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述

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

4

3 回答 3

0

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

幸运的是,在这种速率下采样是可以在 Windows 上使用高精度计时器完成的(如果您不需要很高的准确性)。20Hz 采样率对应于 50ms 的采样周期,因此您可以使用循环,在记录采样值之间睡眠约 50ms。您不会在样本之间获得超精确的 delta-T(您可能会看到每个样本之间的时间变化高达 15-30 毫秒,具体取决于您的系统),但对于您正在处理的频率应该足够好和。

您可以记录几秒钟的样本(以及相关的时间戳),然后将数据导出到电子表格。进入电子表格后,您可以进行一些分析和绘图。或者您可以找到一些时间序列分析代码来分析样本列表,例如使用傅里叶变换(FFT)将信号从时域转换到频域。

这是创建示例的示例。如果您确实需要更准确的时间戳,您可以DateTime.NowStopWatchin替换使用。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);
        }
    }
}
于 2012-07-17T22:35:48.963 回答
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. 请记住,当结果是按位计算时,切勿直接使用==or!=运算符进行比较。

我使用System.Diagnostics.Stopwatch了比使用精确的DateTime.Now.Second.

于 2012-07-16T06:50:10.497 回答
0

你做的各种事情都有点不对劲。首先,您要计算一整秒的脉冲数,最多计算一秒钟的脉冲数(取决于第二次调用 GetFreq 的位置)。

其次,您正在计算向上和向下脉冲,尽管我认为频率应该是每秒向上(或向下)脉冲的数量,而不是两者(这将是频率的两倍)。

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

于 2012-07-16T06:50:45.853 回答