C# Windows 10中的串行端口缺少传入字节
我正在从一个串行端口读取数据,该端口在发送start命令后连续发送数据。我工作的波特率非常高,为1408000,采样率为2000。我必须以以下方式处理传入数据:2个起始字节(0xAA,0x55),后跟68个字节的实际数据。 在Win 7中运行该程序不是问题,但在Win 10中运行该程序会导致丢失一些字节-有时我只得到20个字节的数据,有时我得到72个字节的数据(总是改变值)。我错过什么了吗 这是我的密码:C# Windows 10中的串行端口缺少传入字节,c#,serial-port,C#,Serial Port,我正在从一个串行端口读取数据,该端口在发送start命令后连续发送数据。我工作的波特率非常高,为1408000,采样率为2000。我必须以以下方式处理传入数据:2个起始字节(0xAA,0x55),后跟68个字节的实际数据。 在Win 7中运行该程序不是问题,但在Win 10中运行该程序会导致丢失一些字节-有时我只得到20个字节的数据,有时我得到72个字节的数据(总是改变值)。我错过什么了吗 这是我的密码: SerialPort m_serialPort = new System.IO.Ports
SerialPort m_serialPort = new System.IO.Ports.SerialPort("COM8");
private static System.Timers.Timer timer = new System.Timers.Timer();
private static ConcurrentQueue<List<byte>> incomingdataQueue = new ConcurrentQueue<List<byte>>();
private static readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
static bool isProcessing = false;
private static List<byte> sampleData = new List<byte>();
public Form1()
{
InitializeComponent();
timer.Interval = 250;//250ms
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
m_serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
SetComConnectParam("COM8");
if (!ComOpen()){UpdateStatus("Problem!\n");}
init_System(gain, sample, trigger); // sends a signal to the port to init the system
UpdateStatus("start data recording " + DateTime.Now.ToString());
Start_Data(); // sends a signal to the port to start data processing
timer.Start();
}
public void SetComConnectParam(string portName, int baudRate = 1408000)
{
m_serialPort.PortName = portName;
m_serialPort.BaudRate = baudRate;
m_serialPort.Parity = Parity.None;
m_serialPort.DataBits = 8;
m_serialPort.StopBits = StopBits.One;
}
private bool ComOpen()
{
// Closing serial port if it is open
if (m_serialPort != null && m_serialPort.IsOpen){m_serialPort.Close();}
if (false == m_serialPort.IsOpen)
{
try
{
m_serialPort.Open();
m_serialPort.DiscardInBuffer();
}
catch { return false; }
}
return true;
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort comport = sender as SerialPort;
if (comport == null || comport.BytesToRead == 0 || !comport.IsOpen) { return; }
int dataLength = comport.BytesToRead;
byte[] buffer = new byte[dataLength];
int nbrDataRead = comport.Read(buffer, 0, dataLength);
if (nbrDataRead == 0) { return; }
incomingdataQueue.Enqueue(buffer.Take(nbrDataRead).ToList());
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (incomingdataQueue.Count == 0) { return; }
ProcessData();
}
private void ProcessData()
{
int byteperdatasample = 68;
if (incomingdataQueue.Count == 0) { return; }
if (!locker.TryEnterWriteLock(100)) { return; }
if (isProcessing)
{
locker.ExitWriteLock();
return;
}
isProcessing = true;
List<byte> currentData = new List<byte>();
while (incomingdataQueue.Count > 0)
{
incomingdataQueue.TryDequeue(out currentData);
for (int i = 0; i < currentData.Count; i++)
{
// problem: startseq is 0xAA, 0x55. 0xAA might be last entry in currentData list and 0x55 might be first entry in next data list
if (i == currentData.Count - 1 && currentData[i].Equals(170)) { startIndex = -99; startFound = false; }
if (i == 0 && currentData[i].Equals(85))
{
if (startIndex.Equals(-99)){startFound = true;}
else{startFound = false;}
}
if (i < currentData.Count - 1 && currentData[i].Equals(170) && currentData[i + 1].Equals(85))
{
startFound = true;
startIndex = i;
}
if (startFound)
{
if (startIndex == -99){sampleData.RemoveAt(sampleData.Count - 1);}//remove latest item (first start item 0xaa was added in last currentData list)
if (sampleData.Count == byteperdatasample)//
{
/* whole block of data processing */
}
else{//error}
else
{
if (i != startIndex + 1){sampleData.Add(currentData[i]);}
}
}
}
isProcessing = false;
locker.ExitWriteLock();
}
private void ButtonStop_Click(object sender, EventArgs e)
{
Stop_Data();
timer.Stop();
}
SerialPort m_SerialPort=new System.IO.port.SerialPort(“COM8”);
private static System.Timers.Timer Timer=新的System.Timers.Timer();
私有静态ConcurrentQueue incomingdataQueue=新ConcurrentQueue();
私有静态ReaderWriterLockSlim locker=new ReaderWriterLockSlim();
静态bool isProcessing=false;
私有静态列表sampleData=new List();
公共表格1()
{
初始化组件();
timer.Interval=250;//250ms
timer.appeased+=新的ElapsedEventHandler(timer\u appeased);
m_serialPort.DataReceived+=新的SerialDataReceivedEventHandler(DataReceivedHandler);
SetComConnectParam(“COM8”);
如果(!ComOpen()){UpdateStatus(“问题!\n”);}
init_系统(增益、采样、触发器);//向端口发送信号以初始化系统
UpdateStatus(“开始数据记录”+DateTime.Now.ToString());
Start_Data();//向端口发送信号以开始数据处理
timer.Start();
}
public void SetComConnectParam(字符串端口名,int波特率=1408000)
{
m_serialPort.PortName=PortName;
m_serialPort.BaudRate=波特率;
m_serialPort.Parity=奇偶校验.None;
m_serialPort.DataBits=8;
m_serialPort.StopBits=StopBits.One;
}
二等兵布尔·科莫彭()
{
//关闭串行端口(如果打开)
如果(m_serialPort!=null&&m_serialPort.IsOpen){m_serialPort.Close()}
if(false==m_serialPort.IsOpen)
{
尝试
{
m_serialPort.Open();
m_serialPort.DiscardInBuffer();
}
catch{return false;}
}
返回true;
}
私有静态void DataReceivedHandler(对象发送方,SerialDataReceivedEventArgs e)
{
SerialPort comport=发送方作为SerialPort;
如果(comport==null | | comport.BytesToRead==0 | |!comport.IsOpen){return;}
int dataLength=comport.BytesToRead;
字节[]缓冲区=新字节[dataLength];
int nbrDataRead=comport.Read(缓冲区,0,数据长度);
如果(nbrDataRead==0){return;}
incomingdataQueue.Enqueue(buffer.Take(nbrDataRead.ToList());
}
无效计时器已过(对象发送器,ElapsedEventArgs e)
{
如果(incomingdataQueue.Count==0){return;}
ProcessData();
}
私有void ProcessData()
{
int byteperdatasample=68;
如果(incomingdataQueue.Count==0){return;}
如果(!locker.TryEnterWriteLock(100)){return;}
如果(i处理)
{
locker.ExitWriteLock();
返回;
}
isProcessing=true;
List currentData=新列表();
而(incomingdataQueue.Count>0)
{
incomingdataQueue.TryDequeue(OutCurrentData);
对于(int i=0;i
可以尝试在没有计时器的情况下工作
如果(incomingdataQueue.Count==0){return;}添加新任务
在DataReceivedHandler处理程序中运行(()=>ProcessData())
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort comport = sender as SerialPort;
if (comport == null || comport.BytesToRead == 0 || !comport.IsOpen) { return; }
int dataLength = comport.BytesToRead;
byte[] buffer = new byte[dataLength];
int nbrDataRead = comport.Read(buffer, 0, dataLength);
if (nbrDataRead == 0) { return; }
incomingdataQueue.Enqueue(buffer.Take(nbrDataRead).ToList());
if (incomingdataQueue.Count > 0) {
Task.Run(()=>ProcessData());
}
}
我猜是并发访问。您保护队列不受可重入访问的影响,但不受通过DataReceived和ProcessData进行的并发访问的影响。无关:如果端口实际上已打开,则关闭端口并立即打开很可能不起作用。操作系统需要一些时间来“清理”。乍一看,我甚至更加困惑。ProcessData似乎从未使用
incomingdataQueue
,currentData
似乎从未添加到???locker
似乎没有声明任何位置…我是否遗漏了什么?抱歉,我忘记复制这些行。添加了edit。我不确定是否必须保护这些行使用锁定器排队,因为它已经是ConcurrentQueue。这只是在旧计算机上意外工作,得益于它速度较慢,因此能够在调用事件处理程序之前接收更多字节。从根本上讲,您将读取多少字节是不可预测的,请确保继续调用read()直到你得到“消息”中的所有字节。故意使用低波特率来确信代码是正确的。