C# SerialPort的 DataReceived事件,可能是存在问题,使用时,数据丢失,造成数据不完整。
解决方法思路:
使用独立线程读取数据,把串口缓冲区的数据,读取到程序中。抛开DataReceived事件。
使用其它线程获取“串口中读取的数据”再进行解析。
客户程序由被动触发,改为主动获取。
相关变量、对象
C# Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
///
/// 保持读取开关
///
bool _keepReading;
///
/// 检测频率【检测等待时间,毫秒】【按行读取,可以不用】
///
int _jcpl = 1 ;
///
/// 串口
///
SerialPort _sp = new SerialPort();
///
/// 字符串队列【.NET Framework 4.0以上】
///
ConcurrentQueue< string > _cq = new ConcurrentQueue< string >();
///
/// 字节数据队列
///
ConcurrentQueue< byte []> _cqBZ = new ConcurrentQueue< byte []>();
串口读取方法【ViewCommStatus,自定义方法,串口读取状态输出】
C# Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
///
/// 串口读取方法
///
void SerialPortRead()
{
while (_keepReading)
{
if (_jcpl > 0 ) //按行读取可以省略
{
Thread.Sleep(_jcpl);
} if (_sp == null )
{
ViewCommStatus( false , "串口对象未实例化!" );
Thread.Sleep( 3000 ); //3秒后重新检测
continue ;
}
if (!_sp.IsOpen)
{
ViewCommStatus( false , "串口未打开" );
Thread.Sleep( 3000 );
continue ;
}
try { #region 按行读取
string buffer = _sp.ReadLine();
if (! string .IsNullOrEmpty(buffer)) //可以不加判断,允许添加null值,数据解析时,再做判断。
{
_cq.Enqueue(buffer);
} #endregion //#region 字节读取
//byte[] readBuffer = new byte[_sp.ReadBufferSize + 1];
//int count = _sp.Read(readBuffer, 0, _sp.ReadBufferSize);
//if (count != 0)
//{
// _cqBZ.Enqueue(readBuffer);
//}
//#endregion
ViewCommStatus( true , "串口通信正常" );
}
catch (TimeoutException) //注意超时时间的定义
{
ViewCommStatus( false , "串口读取超时!" );
}
catch (Exception ex) //排除隐患后可以去掉。
{
ViewCommStatus( false , "串口读取异常:" + ex.Message);
}
}
}
数据解析方法
C# Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
///
/// 数据解析
///
void DataAnalysis()
{
while ( true )
{
Thread.Sleep( 10 );
if (_cq.IsEmpty)
{
continue ;
}
#region 按行读取
for ( int i = 0 ; i < _cq.Count; i++)
{
string strTmp = "" ;
_cq.TryDequeue( out strTmp);
//解析strTmp
//解析strTmp
//解析strTmp
} #endregion #region 按字节读取
//StringBuilder sb = new StringBuilder();
//for (int i = 0; i < _cq.Count; i++)
//{
// byte[] bt = null;
// _cqBZ.TryDequeue(out bt);
// string strTmp = System.Text.Encoding.ASCII.GetString(bt);
// sb.Append(strTmp);
//}
////解析sb
////解析sb
////解析sb
#endregion }
}
调用示例
C# Code
1
2
3
4
5
6
7
8
9
10
11
void StartRead()
{
_keepReading = true ;
Thread trdRead = new Thread(SerialPortRead);
trdRead.Start();
Thread trdDataAnalysis = new Thread(DataAnalysis);
trdDataAnalysis.Start();
}
SerialPort的参数配置和资源释放,就先不写了。这个一般情况下都会。