Count Входная частота параллельного порта - С#
Я должен подсчитать входную частоту параллельного порта на выводе № 13, начиная с таймера 555 таймера, реальная частота должна составлять около 3-4 Гц (ON Pulse). Я несколько раз пробовал несколько кодов, но каждый раз, когда они дают разные значения. Я пробовал следующий код:
[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
для управления параллельным портом.
Ответы
Ответ 1
Попробуйте вместо этого использовать следующую функцию:
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
.
Ответ 2
Ты делаешь все, что-то не так. Во-первых, вы считаете импульсы целую секунду, вы считаете импульсы до секунды (зависит от того, где вызывается второй GetFreq).
Во-вторых, вы подсчитываете импульсы вверх и вниз, хотя я думаю, что частота должна быть числом импульсов up (или down) каждую секунду, а не их обоих (это будет вдвое больше частоты).
И, наконец, если вы хотите измерить 3 или 4 Гц, измерение в течение одной секунды приведет к ошибкам округления. Попробуйте измерить в течение 5 секунд. Используйте Stopwatch
для измерения этих 5 секунд.
Ответ 3
Вам нужно пробовать свой сигнал со скоростью, которая по крайней мере вдвое превышает максимальную частоту вашего сигнала. Если ваша ожидаемая максимальная частота составляет около 4 Гц, то выборка сигнала в любом месте от 15 до 20 Гц должна давать хорошие результаты.
К счастью, выборка с такой скоростью - это то, что можно сделать без чрезмерного использования с высокоточными таймерами в Windows (если вам не требуется большая точность). Частота дискретизации 20 Гц соответствует периоду выборки в 50 мс, поэтому вы можете использовать цикл, в котором вы спите около 50 мс между значениями записи образца. Вы не получите сверхточную дельта-T между образцами (вы можете видеть вариации до 15-30 мс за время между каждым образцом, в зависимости от вашей системы), но он должен быть достаточно хорош для частот, с которыми вы работаете с.
Вы можете записать несколько секунд образцов (и связанных временных меток), а затем экспортировать данные в электронную таблицу. Однажды в электронной таблице вы можете выполнить анализ и графику. Или вы можете найти код анализа временных рядов для анализа списка образцов, например, с использованием преобразования Фурье (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);
}
}
}