我必须计算引脚号为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
来控制并行端口。
答案 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);
}
}
}