2012-07-16 47 views
0

我必須在13號引腳上計算並行端口的輸入頻率,來自555定時器IC,實際頻率應該在3-4赫茲(ON脈衝)左右。我嘗試了幾次代碼,但是每次都給出不同的值。我曾嘗試下面的代碼:計數並行端口輸入頻率 - C#

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

OUTPUT:

enter image description here enter image description here enter image description here

我應該怎麼做,才能得到準確的頻率是多少?我的代碼中有任何錯誤嗎? 我正在使用inpout32.dll來控制並行端口。

+0

關閉脈衝值是否始終等於120,或者可以略大於或小於120? – 2012-07-17 22:50:21

回答

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更精確。

0

你正在做各種各樣的事情有點不對。首先,你需要整秒鐘對脈衝進行計數,你計數脈衝的時間爲,最多爲秒(取決於第二次調用GetFreq的位置)。其次,你正在計數上下脈衝,儘管我認爲頻率應該是每秒上升(或下降)脈衝的數量,而不是兩者(這將是頻率的兩倍)。

最後,如果你想測量3或4赫茲,測量一秒會引入舍入誤差。嘗試測量5秒。使用Stopwatch來測量那5秒鐘。

0

您需要以至少是信號中最高頻率兩倍的速率對信號進行採樣。如果您預期的最高頻率約爲4Hz,那麼在15-20Hz的任何地方對信號進行採樣應該會給出好的結果。

幸運的是,以這種速率進行採樣是可以在Windows上使用高精度計時器(如果您不需要太多精度的話)實現的。 20Hz採樣率對應於50ms的採樣週期,因此您可以使用一個循環,在記錄採樣值之間您可以休眠約50ms。你不會在樣本之間得到超精確的delta-T(你可能會發現在每個樣本之間的時間差異可達15-30ms,這取決於你的系統),但是它對於你處理的頻率應該足夠好用。

您可以記錄價值數秒的樣本(和相關時間戳),然後將數據導出到電子表格。一旦進入電子表格,您可以進行一些分析和繪圖。或者您可以找到一些時間序列分析代碼來分析樣本列表,例如使用傅里葉變換(FFT)將信號從時域轉換到頻域。

以下是創建示例的示例。如果您確實需要時間戳中的更高精度,則可以將DateTime.Now替換爲GetInputSamples中的StopWatch

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