问题描述
我正在从事一个项目,该项目要求我从连接到编码器(带 QSB 的美国数字 S5 光学轴编码器)的串行端口读取的每个数据条目都需要精确的时间 (ms).
I am working on a project which requires precise time(ms) for each data entry I read from a serial port connected to an encoder (US digital S5 Optical Shaft Encoder with a QSB).
我在一辆小推车上安装了编码器,我用它来计算推车的速度.
I installed the encoder on a small cart where I use it to count the speed of the cart.
这是我目前所做的:
连接到串口并向QSB写入命令以告诉编码器流式传输数据.此处可用的命令:
connect to the serial port and write command to QSB to tell the encoder to stream data. commands available here:
www.usdigital.com/assets/general/QSB%20Commands%20List_1.pdfwww.usdigital.com/assets/general/QSB%20Applications%20Examples.pdf
www.usdigital.com/assets/general/QSB%20Commands%20List_1.pdfwww.usdigital.com/assets/general/QSB%20Applications%20Examples.pdf
使用 readline() 读取接收到的数据.
Use readline() to read received data.
当我将输出值阈值和间隔率设置为尽可能快时,我能够在 1 毫秒内获取数据条目.这是我得到的:
I am able to get data entries in between 1ms when I set the output value threshold and interval rate to as fast as possible.Here is what I got:
----time stamp(h/m/s/ms)-------value
具有正确时间戳的数据:https://www.dropbox.com/s/pvo1dz56my4o99y/Capture1.JPG
data with correct time stamp: https://www.dropbox.com/s/pvo1dz56my4o99y/Capture1.JPG
然而,有突然的跳跃",数据连续时大约200ms(我正在以恒定速度滚动推车)
However, there are abrupt "jumps", roughly 200ms when data is continuous (I am rolling the cart in a constant speed)
时间戳不正确的数据:https://www.dropbox.com/s/sz3sxwv4qwsb2cn/Capture2.JPG
这是我的代码:
private void buttonOpenEncoderPort_Click(object sender, EventArgs e)
{
serialPortEncoder.Write("S0E\r\n");//start streaming data
System.Threading.Thread.Sleep(500);
serialPortEncoder.Write("W0B0\r\n");//set threshold to 0 so the encoder will stream data a the interval I set.
System.Threading.Thread.Sleep(500);
serialPortEncoder.Write("W0C0000\r\n");//set output interval to 0 so it will stream as fast as possible
System.Threading.Thread.Sleep(1500);
backgroundWorkerEncoder.RunWorkerAsync();}
//I am using a background worker to pull data out.
private void backgroundWorkerEncoder_DoWork(object sender, DoWorkEventArgs e)
{
while (serialPortEncoder.IsOpen)
{
if (serialPortEncoder.BytesToRead != 0)
{
try
{
String s = serialPortEncoder.ReadLine();//read from encoder
LazerBucket.Add(getCurrentTimeWithMS(timeEncoder) + "-----" + s + "\r\n");//put one line of data with time stamp in a List<String>
richTextBoxEncoderData.BeginInvoke(new MethodInvoker(delegate()
{
richTextBoxEncoderData.Text = s; })); //update UI
}
catch (Exception ex) { MessageBox.Show(ex.ToString()); }
}
}
}
private String getCurrentTimeWithMS(DateTime d)//to get time
{
StringBuilder s = new StringBuilder();
d = DateTime.Now;
int hour = d.Hour;
int minute = d.Minute;
int second = d.Second;
int ms = d.Millisecond;
s.Append(" ----" + hour.ToString() + ":" + minute.ToString() + ":" + second.ToString() + ":" + ms.ToString());
return s.ToString();
}
如果有人能找到时间跳跃的原因,我会很高兴.200 毫秒太多了,不容忽视.
I would appericiate it if someone could find the cause of the time jump. 200ms is too much to be ignored.
EDIT:
按照建议,我尝试了 Stopwatch
但仍然有 200 毫秒的延迟.但是当我一起打印时间戳和 BytesToRead 时,我发现缓冲区中的数据随着 readLine() 的执行而减少.最终 BytesToRead 将下降到个位数,这就是延迟发生的地方.我正在寻找关于如何实现线程的更好的解决方案.还有延迟的解释.也许我读得太快了,所以缓冲区跟不上我?
As suggested, I tried Stopwatch
but still there are 200ms delay. But when I print out time stamps and BytesToRead together, I found that data in the buffer is decreasing as readLine() is being executed. Eventually BytesToRead will drop to single digit and that's where the delay happens. I am looking for better solutions on how to implement threads. And also explanations for the delay. Maybe I am reading to fast so the buffer can't keep up with me?
EDIT:
问题解决了.请参阅下面的我的答案.谢谢你的回复.秒表真的很有帮助.现在我正在尝试确定事件驱动或轮询哪个更好.
problem solved. see my answer below. Thanks for replying though. Stopwatch really helps. Now I am trying to work out whether event driven or polling is better.
推荐答案
您使用的是 C# 4.5 吗?如果是这样,我强烈建议使用 async
/await
而不是 BackgroundWorker
.
Are you using C# 4.5? If so, I highly recommend using async
/await
over BackgroundWorker
.
此外,DateTime
对于实时应用程序来说并不准确.我会严格推荐 DateTime
作为 开始时间,然后在 System.Diagnostics
中使用 Stopwatch
来获取 自开始时间以来的时间.
Also, DateTime
isn't really accurate for real-time applications. I would recommend DateTime
strictly as a start time and then using Stopwatch
in System.Diagnostics
to get the elapsed time since the start time.
private void backgroundWorkerEncoder_DoWork(object sender, DoWorkEventArgs e)
{
var startTime = DateTime.Now;
var stopwatch = Stopwatch.StartNew();
while (serialPort.IsOpen && !backgroundWorker.CancellationPending)
{
if (serialPort.BytesToRead > 0)
{
try
{
var line = serialPort.ReadLine();
var timestamp = (startTime + stopwatch.Elapsed);
var lineString = string.Format("{0} ----{1}",
line,
timestamp.ToString("HH:mm:ss:fff"));
// Handle formatted line string here.
}
catch (Exception ex)
{
// Handle exception here.
}
}
}
至于 200 毫秒 的差异,可能是多种原因.也许 BackgroundWorker
的优先级较低,并且没有您希望的那么多 CPU 时间.也可能是 SerialPort
或实际串行设备本身的 I/O 端.
As for the 200 ms discrepancy, it could be a variety of things. Perhaps the BackgroundWorker
is on a lower priority and doesn't get as much CPU time as you hoped. Could also be something on the I/O side of either SerialPort
or the actual serial device itself.
这篇关于串口数据精确时间戳的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!