关于串口通信线程池

易2017 2017-09-14 09:57:17
之前看到sp大神关于串口数据解析的一篇回答http://bbs.csdn.net/topics/390930620,试了试以下的串口数据处理代码
private List<byte> RevBuffer = new List<byte>();

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
lock (RevBuffer)
{
var buffer = new byte[4000];
var len = 0;
while ((len = serialPort1.Read(buffer, 0, buffer.Length)) > 0)
RevBuffer.AddRange(buffer.Take(len));
ThreadPool.QueueUserWorkItem(h => //不等ProcessCommand执行完,立即重新读取串口新数据
{
while (ProcessCommand()) ; //处理收到的所有消息,直到再没有任务
});
}
}

private bool ProcessCommand()
{
lock (RevBuffer)
{
var len = 查找一个命令的长度(RevBuffer);
if (len == 0) //不包含任何完整的任务(比如说还没有接受到第一个消息的结束标志
return false;

var command = new byte[len];
Array.Copy( RevBuffer.ToArray() , command, len );
RevBuffer.RemoveRange(0, len ); //从接收缓冲区移除第一个消息内容
ThreadPool.QueueUserWorkItem(h => 执行一条命令(command));
return true; //通知调用程序,收到了一个任务
}
}

现在存在一个问题,当串口处理因为某种原因存在阻塞,导致线程池中的线程队列不断增加,最后卡死程序,报错停止工作,针对这个问题,各位说说自己的想法
...全文
603 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
ilikeff8 2017-09-14
  • 打赏
  • 举报
回复
收到了完整数据并处理 用线程去处理,我上面的wpf代码里是触发一个属性, 而且扫描枪的特性是扫一个码后必须处理完才能扫下一个,和工控机流程还是很不一样的
ilikeff8 2017-09-14
  • 打赏
  • 举报
回复
引用 26 楼 yuhijk2055 的回复:
[quote=引用 17 楼 ilikeff8 的回复:] 给你贴的就是项目里实际用的代码,是进过反复测试和正在使用的,没出现过任何问题 你可以看到串口扫描枪扫一次,会发来若干次数据

        #region 事件定义
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                if (CurrentSortingStatus.ID == ESortingStatus.ScanStaffMode || CurrentSortingStatus.ID == ESortingStatus.ScanStaffID || CurrentSortingStatus.ID == ESortingStatus.ScanStaff2ID
                    || CurrentSortingStatus.ID == ESortingStatus.ScanTaskID || CurrentSortingStatus.ID == ESortingStatus.ScanGoodsID || CurrentSortingStatus.ID == ESortingStatus.Start)
                {
                    lock (lock_SerialPort_DataReceived)
                    {
                        int byteCount = serialPort.BytesToRead;
                        byte[] receiveBytes = new byte[byteCount];
                        serialPort.Read(receiveBytes, 0, byteCount);

                        serialPortScanGunText += Encoding.UTF8.GetString(receiveBytes);

                        if (!isFirstSerialPortScanGunScaning)
                        {
                            isFirstSerialPortScanGunScaning = true;
                        }

                        if (serialPortScanGunText.EndsWith(Environment.NewLine))
                        {
                            isFirstSerialPortScanGunScanDone = true;
                            CurrentScanText = serialPortScanGunText.Trim();
                            serialPortScanGunText = string.Empty;
                        }
                    }
                }
                else
                {
                    serialPort.DiscardInBuffer();
                }
            }
            catch
            {
            }
        }

[code=csharp]
        string currentScanText;
        public string CurrentScanText
        {
            get
            { return currentScanText; }
            set
            {
                //  if (currentScanText != value) // 扫描相同号码也视为变动
                {
                    currentScanText = value;
                    try
                    {
                        OnPropertyChanged(nameof(CurrentScanText));
                    }
                    finally
                    {
                        if (CurrentSortingStatus.ID != ESortingStatus.NoStart)
                        {
                            ProcessScan();
                        }
                    }
                }
            }
        }
[/code]
看了您的上线代码是以回车结尾 如果在缓冲区第一次读取的数据这:QWERT\r\nASDFG 第二次读取的数据为:\r\nHJKLO\r\nCVB 第三次读取数据为:GH\r\nASD 这样的一些数据,而且每次数据+=以后结尾都没有我们要的回车 if (serialPortScanGunText.EndsWith(Environment.NewLine)) 那我们扫描枪就不会在第一时间扫出来物品 我的做法是收到数据后,对serialPortScanGunText里的数据轮循,只要是数据里有回车,并且数据向前能取到规定的长度或者包头名,不是以回车结尾,也是可以第一时间取到扫描的物品[/quote] 这个就要根据业务需要来修改了 由于扫描枪发数据本身最后才会带回车,本身就是回车作为终结符的,所以回车\r\n只可能出现在某个包的尾部,绝对不可能出现在中间,所以我这里只定义这个全局变量累加即可,同时,在我的业务里,为了方便,使用了字符串,而如果是不可识别的数据,例如chr(1) 自然要换成字节数据来存储 string serialPortScanGunText = string.Empty; 如果你这种情况,j就需要分段,检查到回车后做一点处理 if (收到的数据中出现了回车) { +=回车前的, 收到了完整数据并处理 serialPortScanGunText =回车后的部分 } 当然写法不是唯一的,轮询也是一样的
无情时尚 2017-09-14
  • 打赏
  • 举报
回复
比如,我的做法是以 < 符号开始, > 符号结尾,中间就是所需要的数据,如 <qwert>

如果我接收到的是 yui><hjiio><hy 的数据,我就只解析出<hjiio>

无情时尚 2017-09-14
  • 打赏
  • 举报
回复
引用 17 楼 ilikeff8 的回复:
给你贴的就是项目里实际用的代码,是进过反复测试和正在使用的,没出现过任何问题 你可以看到串口扫描枪扫一次,会发来若干次数据

        #region 事件定义
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                if (CurrentSortingStatus.ID == ESortingStatus.ScanStaffMode || CurrentSortingStatus.ID == ESortingStatus.ScanStaffID || CurrentSortingStatus.ID == ESortingStatus.ScanStaff2ID
                    || CurrentSortingStatus.ID == ESortingStatus.ScanTaskID || CurrentSortingStatus.ID == ESortingStatus.ScanGoodsID || CurrentSortingStatus.ID == ESortingStatus.Start)
                {
                    lock (lock_SerialPort_DataReceived)
                    {
                        int byteCount = serialPort.BytesToRead;
                        byte[] receiveBytes = new byte[byteCount];
                        serialPort.Read(receiveBytes, 0, byteCount);

                        serialPortScanGunText += Encoding.UTF8.GetString(receiveBytes);

                        if (!isFirstSerialPortScanGunScaning)
                        {
                            isFirstSerialPortScanGunScaning = true;
                        }

                        if (serialPortScanGunText.EndsWith(Environment.NewLine))
                        {
                            isFirstSerialPortScanGunScanDone = true;
                            CurrentScanText = serialPortScanGunText.Trim();
                            serialPortScanGunText = string.Empty;
                        }
                    }
                }
                else
                {
                    serialPort.DiscardInBuffer();
                }
            }
            catch
            {
            }
        }

[code=csharp]
        string currentScanText;
        public string CurrentScanText
        {
            get
            { return currentScanText; }
            set
            {
                //  if (currentScanText != value) // 扫描相同号码也视为变动
                {
                    currentScanText = value;
                    try
                    {
                        OnPropertyChanged(nameof(CurrentScanText));
                    }
                    finally
                    {
                        if (CurrentSortingStatus.ID != ESortingStatus.NoStart)
                        {
                            ProcessScan();
                        }
                    }
                }
            }
        }
[/code]
看了您的上线代码是以回车结尾 如果在缓冲区第一次读取的数据这:QWERT\r\nASDFG 第二次读取的数据为:\r\nHJKLO\r\nCVB 第三次读取数据为:GH\r\nASD 这样的一些数据,而且每次数据+=以后结尾都没有我们要的回车 if (serialPortScanGunText.EndsWith(Environment.NewLine)) 那我们扫描枪就不会在第一时间扫出来物品 我的做法是收到数据后,对serialPortScanGunText里的数据轮循,只要是数据里有回车,并且数据向前能取到规定的长度或者包头名,不是以回车结尾,也是可以第一时间取到扫描的物品
易2017 2017-09-14
  • 打赏
  • 举报
回复
引用 24 楼 ilikeff8 的回复:
[quote=引用 22 楼 qq_38588710 的回复:] [quote=引用 19 楼 ilikeff8 的回复:] 分包和读取 Encoding.UTF8.GetString(receiveBytes) 没任何关系。,因为有lock,如果高速发送2个包过来,无非2种情况 1 2个datareceived事件各处理了一段数据 2 第一个datareceived事件读取缓冲区数据时,顺便获取到了后一次的数据,一并处理了,lock解锁,后一次datareceived事件读取缓冲区无数据, serialPortScanGunText += "", 空转
这个我就不明白了,这个lock的是哪个数据,既然会出现第二种情况,这个lock有什么效果,还有,我贴的代码只是我为了学习测试的代码,新手上路,老司机带我[/quote] 如果一个数据"ABC",例如被拆除2个包"A" 和"BC" 收到 A 触发一次 datareceived 顺带 lock掉lock_SerialPort_DataReceived static object lock_SerialPort_DataReceived = new object(); 这时候如果"BC"也收到了。会触发第二次datareceived事件的,2个事件是会并发处理,如果你断点单步跟踪,会发现在同一个datareceived事件里光标跳来跳去的,类似于开了2个线程一样 然后因为第一个A的datareceived还在lock lock_SerialPort_DataReceived 所以BC的这个datareceived 尝试lock lock_SerialPort_DataReceived 时会被阻塞在这里,直到 A的处理完了,退出lock快,解锁了 lock_SerialPort_DataReceived ,BC这里才得以lock lock_SerialPort_DataReceived 并进行处理,然后这是再取读取缓冲区里还没有被处理过的数据,这新数据可能是BC,也可能处理A的时候又来新数据,就变成处理BCDEF [/quote] get,谢谢
ilikeff8 2017-09-14
  • 打赏
  • 举报
回复
引用 22 楼 qq_38588710 的回复:
[quote=引用 19 楼 ilikeff8 的回复:] 分包和读取 Encoding.UTF8.GetString(receiveBytes) 没任何关系。,因为有lock,如果高速发送2个包过来,无非2种情况 1 2个datareceived事件各处理了一段数据 2 第一个datareceived事件读取缓冲区数据时,顺便获取到了后一次的数据,一并处理了,lock解锁,后一次datareceived事件读取缓冲区无数据, serialPortScanGunText += "", 空转
这个我就不明白了,这个lock的是哪个数据,既然会出现第二种情况,这个lock有什么效果,还有,我贴的代码只是我为了学习测试的代码,新手上路,老司机带我[/quote] 如果一个数据"ABC",例如被拆除2个包"A" 和"BC" 收到 A 触发一次 datareceived 顺带 lock掉lock_SerialPort_DataReceived static object lock_SerialPort_DataReceived = new object(); 这时候如果"BC"也收到了。会触发第二次datareceived事件的,2个事件是会并发处理,如果你断点单步跟踪,会发现在同一个datareceived事件里光标跳来跳去的,类似于开了2个线程一样 然后因为第一个A的datareceived还在lock lock_SerialPort_DataReceived 所以BC的这个datareceived 尝试lock lock_SerialPort_DataReceived 时会被阻塞在这里,直到 A的处理完了,退出lock快,解锁了 lock_SerialPort_DataReceived ,BC这里才得以lock lock_SerialPort_DataReceived 并进行处理,然后这是再取读取缓冲区里还没有被处理过的数据,这新数据可能是BC,也可能处理A的时候又来新数据,就变成处理BCDEF
易2017 2017-09-14
  • 打赏
  • 举报
回复
引用 21 楼 ilikeff8 的回复:
但原理都是一样的,扫描枪扫一串数据同时也是拆分几个包来发的,你再多的数据,无法也是轮流收很多包,触发多次事件而已,和数据量有什么关系, byte[] receviedBuf = new byte[8]; //因为扭力计上抛的数据帧只有8个字节,为了节约资源,写死8个字节 try { for (int i = 0; i < 8; i++) { receviedBuf[i] = Convert.ToByte(comPort.ReadByte());//读取数据 } 这样写肯定是会出问题的,连正常流程都通不过
我的串口设备一次写8个数据byte,这样是没问题的,就是数据连续上抛有点快,担心处理不了所有的数据帧
易2017 2017-09-14
  • 打赏
  • 举报
回复
引用 19 楼 ilikeff8 的回复:
分包和读取 Encoding.UTF8.GetString(receiveBytes) 没任何关系。,因为有lock,如果高速发送2个包过来,无非2种情况 1 2个datareceived事件各处理了一段数据 2 第一个datareceived事件读取缓冲区数据时,顺便获取到了后一次的数据,一并处理了,lock解锁,后一次datareceived事件读取缓冲区无数据, serialPortScanGunText += "", 空转
这个我就不明白了,这个lock的是哪个数据,既然会出现第二种情况,这个lock有什么效果,还有,我贴的代码只是我为了学习测试的代码,新手上路,老司机带我
ilikeff8 2017-09-14
  • 打赏
  • 举报
回复
但原理都是一样的,扫描枪扫一串数据同时也是拆分几个包来发的,你再多的数据,无法也是轮流收很多包,触发多次事件而已,和数据量有什么关系, byte[] receviedBuf = new byte[8]; //因为扭力计上抛的数据帧只有8个字节,为了节约资源,写死8个字节 try { for (int i = 0; i < 8; i++) { receviedBuf[i] = Convert.ToByte(comPort.ReadByte());//读取数据 } 这样写肯定是会出问题的,连正常流程都通不过
ilikeff8 2017-09-14
  • 打赏
  • 举报
回复
引用 18 楼 qq_38588710 的回复:
[quote=引用 17 楼 ilikeff8 的回复:] 给你贴的就是项目里实际用的代码,是进过反复测试和正在使用的,没出现过任何问题 你可以看到串口扫描枪扫一次,会发来若干次数据
测试当然是没问题,毕竟扫码枪或者其他的数据采集设备上传的数据都是很小的,只不过我想钻研一下这方面的问题,多假设几种情况[/quote] 你听明白我的话了么,反复测试和使用,上线几个月了,当然我的是扫描枪,你的是什么串口设备我就不知道了,还是好好检查检查你自己的代码
ilikeff8 2017-09-14
  • 打赏
  • 举报
回复
引用 12 楼 sp1234 的回复:
无论如何都不会丢包,如果丢包那就是程序问题。 [quote=引用 3 楼 ilikeff8 的回复:] 写的太复杂了, 例如接收串口扫描枪发过来的数据,以回车结束

            serialPort.DataReceived += (sender, e) =>
            {
                try
                {
                    if (isStartReceiving)
                    {
                        lock (lock_SerialPort_DataReceived)
                        {
                            int byteCount = serialPort.BytesToRead;
                            byte[] receiveBytes = new byte[byteCount];
                            serialPort.Read(receiveBytes, 0, byteCount);

                            serialPortScanGunText += Encoding.UTF8.GetString(receiveBytes);

                            if (serialPortScanGunText.EndsWith(Environment.NewLine))
                            {
                                ThreadPool.QueueUserWorkItem(obj =>
                                {
                                    // CurrentScanText = serialPortScanGunText.Trim();
                                    //...
                                }, serialPortScanGunText.Trim());

                                serialPortScanGunText = string.Empty;
                            }
                        }
                    }
                    else
                    {
                        serialPort.DiscardInBuffer();
                    }
                }
                catch
                {
                }
            };
因为收到的数据可能分包,谨慎起见,如果进行 Encoding.UTF8.GetString(receiveBytes) 并不能保证最后的字符是完整的正确字符,这就会出现跟发送数据不一致的问题。所以我认为应该缓存 List<byte> 而不是 string。然后在判断最后2个字节是 0x0d 0x0a 之后,才取出 List<byte> 内容转换为 string。[/quote] 分包和读取 Encoding.UTF8.GetString(receiveBytes) 没任何关系。,因为有lock,如果高速发送2个包过来,无非2种情况 1 2个datareceived事件各处理了一段数据 2 第一个datareceived事件读取缓冲区数据时,顺便获取到了后一次的数据,一并处理了,lock解锁,后一次datareceived事件读取缓冲区无数据, serialPortScanGunText += "", 空转
易2017 2017-09-14
  • 打赏
  • 举报
回复
引用 17 楼 ilikeff8 的回复:
给你贴的就是项目里实际用的代码,是进过反复测试和正在使用的,没出现过任何问题 你可以看到串口扫描枪扫一次,会发来若干次数据
测试当然是没问题,毕竟扫码枪或者其他的数据采集设备上传的数据都是很小的,只不过我想钻研一下这方面的问题,多假设几种情况
ilikeff8 2017-09-14
  • 打赏
  • 举报
回复
给你贴的就是项目里实际用的代码,是进过反复测试和正在使用的,没出现过任何问题
你可以看到串口扫描枪扫一次,会发来若干次数据



#region 事件定义
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (CurrentSortingStatus.ID == ESortingStatus.ScanStaffMode || CurrentSortingStatus.ID == ESortingStatus.ScanStaffID || CurrentSortingStatus.ID == ESortingStatus.ScanStaff2ID
|| CurrentSortingStatus.ID == ESortingStatus.ScanTaskID || CurrentSortingStatus.ID == ESortingStatus.ScanGoodsID || CurrentSortingStatus.ID == ESortingStatus.Start)
{
lock (lock_SerialPort_DataReceived)
{
int byteCount = serialPort.BytesToRead;
byte[] receiveBytes = new byte[byteCount];
serialPort.Read(receiveBytes, 0, byteCount);

serialPortScanGunText += Encoding.UTF8.GetString(receiveBytes);

if (!isFirstSerialPortScanGunScaning)
{
isFirstSerialPortScanGunScaning = true;
}

if (serialPortScanGunText.EndsWith(Environment.NewLine))
{
isFirstSerialPortScanGunScanDone = true;
CurrentScanText = serialPortScanGunText.Trim();
serialPortScanGunText = string.Empty;
}
}
}
else
{
serialPort.DiscardInBuffer();
}
}
catch
{
}
}

[code=csharp]
string currentScanText;
public string CurrentScanText
{
get
{ return currentScanText; }
set
{
// if (currentScanText != value) // 扫描相同号码也视为变动
{
currentScanText = value;
try
{
OnPropertyChanged(nameof(CurrentScanText));
}
finally
{
if (CurrentSortingStatus.ID != ESortingStatus.NoStart)
{
ProcessScan();
}
}
}
}
}
[/code]
  • 打赏
  • 举报
回复
好多年前,在一个微软的大项目的现场,我走到一个外包公司的人的工位上帮他解决一个问题,我写了几行代码。然后他就好像“很有感触地”说什么:微软公司的.......代码啊,这样我当时就楞了。我赶紧搞告诉他,不管我们挂了什么名儿,绝大多数人写的代码跟一般人没有什么两样儿,甚至就算是 msdn 上我们看到的代码也往往是一些实习学生写的,而我们的同事写的代码一样会有大量垃圾、需要反复修改。那个房间里的程序员没有什么背景公司之分,只有职能分工不同。 哎,只要理解代码所要表达的意思就好了,代码有 bug 这其实是经常地事情。毕竟这不是做反复测试的产品。这只是论坛啊。
易2017 2017-09-14
  • 打赏
  • 举报
回复
引用 9 楼 ilikeff8 的回复:
串口数据怎么可能会丢包,是写的有点问题 1 收到数据后,先lock掉,再进行操作 2 先用BytesToRead确定当前缓冲区里有多少数据可以读,如果发送比处理快,发送了2次,可能这时候就是10+6=26个字节 3 读取所有缓冲区数据,读取的数据会自动从缓冲区清除掉,不用DiscardInBuffer DiscardInBuffer不要滥用,你清空的可能不光光是你这次的数据,在你处理的时候如果刚好下一波串口数据过来了,你同时把刚收到的数据也清空了
怎么lock串口数据?你看的程序因为数据帧长度和命令帧长度不一,所以discard,这只是我精简后的,之前也跟你一样用BytesToRead读数据,像你说的第二条,如果两条数据同时被取出,如果不加处理,第二条数据被忽略,加处理就复杂了,相当于粘包了
  • 打赏
  • 举报
回复
引用 10 楼 qq_38588710 的回复:
[quote=引用 7 楼 sp1234 的回复:] 你的 ProcessCommand 不应该放到子线程中,应该在 serialPort1_DataReceived 中处理。因为不可能并发多线程去解析和移除 RevBuffer 的内容,所以这里用子线程(然后再lock)是多余的了。
那大神你当初为什么要这样写呢[/quote] 不记得啦。
  • 打赏
  • 举报
回复
无论如何都不会丢包,如果丢包那就是程序问题。
引用 3 楼 ilikeff8 的回复:
写的太复杂了, 例如接收串口扫描枪发过来的数据,以回车结束

            serialPort.DataReceived += (sender, e) =>
            {
                try
                {
                    if (isStartReceiving)
                    {
                        lock (lock_SerialPort_DataReceived)
                        {
                            int byteCount = serialPort.BytesToRead;
                            byte[] receiveBytes = new byte[byteCount];
                            serialPort.Read(receiveBytes, 0, byteCount);

                            serialPortScanGunText += Encoding.UTF8.GetString(receiveBytes);

                            if (serialPortScanGunText.EndsWith(Environment.NewLine))
                            {
                                ThreadPool.QueueUserWorkItem(obj =>
                                {
                                    // CurrentScanText = serialPortScanGunText.Trim();
                                    //...
                                }, serialPortScanGunText.Trim());

                                serialPortScanGunText = string.Empty;
                            }
                        }
                    }
                    else
                    {
                        serialPort.DiscardInBuffer();
                    }
                }
                catch
                {
                }
            };
因为收到的数据可能分包,谨慎起见,如果进行 Encoding.UTF8.GetString(receiveBytes) 并不能保证最后的字符是完整的正确字符,这就会出现跟发送数据不一致的问题。所以我认为应该缓存 List<byte> 而不是 string。然后在判断最后2个字节是 0x0d 0x0a 之后,才取出 List<byte> 内容转换为 string。
易2017 2017-09-14
  • 打赏
  • 举报
回复
引用 8 楼 sp1234 的回复:
业务处理超时这本身就是一个 bug,于是有各种各样的系统维护原则。例如有的处理死锁(比如说使用“弱引用对象”来跟踪和查看业务对象存在(IsAlive)时间,或者限流,等等。 这些还都是被动的错误。最关键地还是业务程序人员,有一个明确的设计原则,业务处理速度有一个硬指标上限。
经验get
易2017 2017-09-14
  • 打赏
  • 举报
回复
引用 7 楼 sp1234 的回复:
你的 ProcessCommand 不应该放到子线程中,应该在 serialPort1_DataReceived 中处理。因为不可能并发多线程去解析和移除 RevBuffer 的内容,所以这里用子线程(然后再lock)是多余的了。
那大神你当初为什么要这样写呢
ilikeff8 2017-09-14
  • 打赏
  • 举报
回复
串口数据怎么可能会丢包,是写的有点问题 1 收到数据后,先lock掉,再进行操作 2 先用BytesToRead确定当前缓冲区里有多少数据可以读,如果发送比处理快,发送了2次,可能这时候就是10+6=26个字节 3 读取所有缓冲区数据,读取的数据会自动从缓冲区清除掉,不用DiscardInBuffer DiscardInBuffer不要滥用,你清空的可能不光光是你这次的数据,在你处理的时候如果刚好下一波串口数据过来了,你同时把刚收到的数据也清空了
加载更多回复(9)
论文摘要 近年来,随着虚拟仪器技术、网络通讯技术的显著进步以及Intemet的迅速 普及,将网络技术应用到虚拟仪器,使信号采集、传输和处理分析一体化,已 成为一种趋势。这一方面可以使许多昂贵的硬件资源得以共享,另一方面还便 于系统的扩展和效率的提高。它通过应用程序与各功能化模块的有机结合,用 户利用友好的图形界面来控制计算机,完成对仪器控制、数据采集、分析、存 储及显示等功能。 本文针对数据采集与监控系统的开发需求,设计并实现了一种基于虚拟仪 器平台的数据采集与监控系统。系统采用的是一个虚拟仪器的构造形式,由数 据采集卡、工业控制计算机和信号调理电路构成硬件系统。系统软件开发平台 为LabWindow托VI,应用软件完成数据采集、处理、存储和显示等功能。 论文的主要研究工作如下: (1)根据数据采集与监控系统的功能需求,提出了系统软件的总体设计方 案,并对虚拟仪器的体系结构和软件开发两方面进行了深入的研究; (2)设计并实现了数据采集和处理模块。利用基于线程池的多线程技术和 基于线程安全队列的数据保护机制,改善数据吞吐量,提高程序响应速度和更 有效的后台数据处理; (3)设计并实现了通信模块。制定串口通信协议,确保数据传输的可靠性 和高速率,有效解决了数据传输与远程监控的问题; (4)设计并实现了数据库模块。实现了详细数据查询、报警信息查询、数 据报表管理、交接班管理、用户登录与权限管理等功能。

110,500

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧