由于工作需要,接触C#不久,做了一个串口通讯小程序。
串口通讯使用的是SerialPort,接收数据是使用SerialPort的数据接收事件。一直没什么问题,能够正常发送,接收数据。近几天发现一个比较奇怪的现象,如下:
正常通讯情况:
上位机向下位机发送数据,下位机应答返回带有8个字节信息的数据,通讯结束。
异常情况:
上位机向下位机发送数据,下位机应答返回带有8个字节信息的数据,数据接收完,之后当这8个字节的数据中只要存在 十六进制的1A,就又会进入到SerialPort的数据接收事件中,但没有任何数据,也就是说数据长度为0,之后结束通讯。
一开始,我以为下位机又发起了串口通讯,但是经过下位机开发人员说,下位机什么都没有发,问题还是出在上位机,我就有点整不明白了,是什么触发的SerialPort的数据接收事件?为什么除了1A之外都没有问题,难道1A在SerialPort中有什么说法?
|
|
0x1a 是文本文件结束符
是不是这个原因?要查一下
|
|
这个还真不清楚
我奇怪的是,异常情况下,数据接收也是完整正确的,但是只要数据中包含1A,就会又触发数据接收事件,让我不解。
初期我始终是怀疑下位机造成的,但是拿串口精灵监控,下位机确实没发数据。下位机开发也和我说,下位机本身很简单,做了就是做了,没做就是没做。
可上位机这,确实在收到数据后,又再次进入到了数据接收事件,虽然没有任何数据。这让我怀疑,是不是C#中的SerialPort在遇到1A之后,有什么特殊处理,又触发了数据接收事件。
这个异常虽然很好屏蔽掉,但是我只是想通过CSDN,是否能有更深一点的了解,以后也会注意一下。
|
5分 |
是什么触发的SerialPort的数据接收事件?
->
只要 “缓冲区” 有数据进来,就会触发事件。 这跟你的字节是什么 没有关系。
|
|
|
|
如果缓冲区里有数据,还说啥?主要是没有数据,所以我才晕菜了!
正常的一发一收,通讯结束,但是只有在数据中存在1A的情况下才之前的一收后,又再次触发了一次数据接收。
刚刚让下位机开发改了一下,让1A成为通讯协议中的一个命令字,结果就是所有数据都是两次触发数据接收,第一次正常接收,在正常接收之后,又再次触发了一个没有任何数据的 数据接收。估计真是SerialPort对1A数据的特殊处理啊!
|
|
不知道谁还更深入的了解过SerialPort,可能我上面是个例,毕竟我自己是没做人为触发 数据接收部分。
按我理解,可能是SerialPort对1A数据有什么说法。
还希望有懂其理的朋友,告之一二!
|
|
iSerialPort不会对1A这种数据做转门处理的,要么你的下位机弄的有问题 ,要么是你写的CODE有问题 。
|
|
这与接收的字符没啥关系,你要看通讯协议是啥。。
哥们,你这回答,让我怎么说?
还是请你,好好看看问题,谢谢!
|
25分 |
|
|
这与接收的字符没啥关系,你要看通讯协议是啥。。
哥们,你这回答,让我怎么说?
还是请你,好好看看问题,谢谢!
明白你说的了。MS写的代码里 把0x1A 当成的结束符了。。
this.dcb.XonChar = 0x11;
this.dcb.XoffChar = 0x13;
this.dcb.XonLim = this.dcb.XoffLim = (ushort) (this.commProp.dwCurrentRxQueue / 4);
this.dcb.EofChar = 0x1a;
this.dcb.EvtChar = 0x1a;
if (!Microsoft.Win32.UnsafeNativeMethods.SetCommState(this._handle, ref this.dcb))
{
InternalResources.WinIOError();
}
|
|
这与接收的字符没啥关系,你要看通讯协议是啥。。
哥们,你这回答,让我怎么说?
还是请你,好好看看问题,谢谢!
明白你说的了。MS写的代码里 把0x1A 当成的结束符了。。
哥们看来你还是没明白我这个帖子到底说的是啥事情?
你也别猜了,我直接说简单点,就是在串口通讯过程中,SerialPort类遇到0x1A,是否会出现 触发数据接收事件?
我目前的情况是,只要通讯中存在0x1A,测试过的是 传输数据,协议中的一个部分,都会在成功通讯后,紧接着触发数据接收事件。
所以我猜测SeriPort对0x1A数据,有特殊处理,所谓特殊处理,也就是会导致它的异常触发数据接收事件,可能是0x1A对它有不可规避的某些东西,也可以说是它的Bug(个人认为,我希望不是),需要人为在外部解决。
由于我不太了解SerialPort的底层,所以上来问问了解的朋友,由于我自己没有写触发数据接收事件的代码,所以我可以说 数据接收事件的触发,一个是串口有数据,一个就是SerialPort的原因,也是我发此贴的意思。
|
|
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发?
也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
|
|
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发?
也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
明白你的意思了,
不过有个疑问
如果你收到的像 0x11,0x11,0x12,0x1A,0x13,0x14,0x15
这样的0x1A 按你所说的接收事件,收到0x11,0x11,0x12,0x1A 后 接收收到一个0长度的字节?后面的,0x13,0x14,0x15 还会不会继续收?
|
|
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发?
也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
明白你的意思了,
不过有个疑问
如果你收到的像 0x11,0x11,0x12,0x1A,0x13,0x14,0x15
这样的0x1A 按你所说的接收事件,收到0x11,0x11,0x12,0x1A 后 接收收到一个0长度的字节?后面的,0x13,0x14,0x15 还会不会继续收?
我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。
|
15分 |
看了里面的原码
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发?
也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
明白你的意思了,
不过有个疑问
如果你收到的像 0x11,0x11,0x12,0x1A,0x13,0x14,0x15
这样的0x1A 按你所说的接收事件,收到0x11,0x11,0x12,0x1A 后 接收收到一个0长度的字节?后面的,0x13,0x14,0x15 还会不会继续收?
我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。
细看了他的原码 0x1A按你上面说的他是做为一个结束符来用, 当收到结束符后他会触发一次DataRecived事件,但里面的事件参数类型变成成 e.EventType= SerialData.Eof ,正常情况下是 SerialData.Chars。所以你应可以根据这个参数来识别是否为正常接收数据吧。
|
20分 |
|
|
我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。
你原本在设计信令格式时应该把 1A 作为消息的结束 。或者如果你的数据中不可能包括 1A,那么你设计其它结束方式也是很普通的。
现在你把 1A 弄到数据当中了。
|
25分 |
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发?
也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
只要是曾经接收过 1A,一定会在windows消息泵中排队插入一个“接收消息”。当主线程空闲时,也就是可能恰好你已经取走了缓冲区中的数据之后,这个事件才触发。
基本上按照比较“保险、正规”的方式来编程,就不会有问题。当这个事件触发时,缓冲区里可以有0个或者多个字节,可能是 EOF 结尾也可能不是以它结尾的(在EOF之后立刻收到更多字节到缓冲区里),都应该用同样的流程来处理。
|
|
你用个串口调试工具调试一下不就知道是不是你写的代码的问题了吗?说这么多。。。。
|
|
你用个串口调试工具调试一下不就知道是不是你写的代码的问题了吗?说这么多。。。。
我不多说点,能说明白问题?
我即使说了这么多 ,你不是也没明白我说的是啥?
还串口调试工具?我上面不是没说,我也试过了,你什么眼神啊?
|
|
看了里面的原码
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发?
也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
明白你的意思了,
不过有个疑问
如果你收到的像 0x11,0x11,0x12,0x1A,0x13,0x14,0x15
这样的0x1A 按你所说的接收事件,收到0x11,0x11,0x12,0x1A 后 接收收到一个0长度的字节?后面的,0x13,0x14,0x15 还会不会继续收?
我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。
细看了他的原码 0x1A按你上面说的他是做为一个结束符来用, 当收到结束符后他会触发一次DataRecived事件,但里面的事件参数类型变成成 e.EventType= SerialData.Eof ,正常情况下是 SerialData.Chars。所以你应可以根据这个参数来识别是否为正常接收数据吧。
嗯,我应该知道你的意思了。
其实这个异常在我这不算是正常数据,我判断一下字节长度就可以屏蔽了。
谢谢了!
|
|
每当信息中有EOF就会立刻(或者说“额外”)触发事件,它原本就是这样设计的。
https://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport.receivedbytesthreshold(v=vs.100).aspx
msdn上已经写明了,此事件触发“与内部输入缓冲区中的字节数无关”。
我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。
你原本在设计信令格式时应该把 1A 作为消息的结束 。或者如果你的数据中不可能包括 1A,那么你设计其它结束方式也是很普通的。
现在你把 1A 弄到数据当中了。
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发?
也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
只要是曾经接收过 1A,一定会在windows消息泵中排队插入一个“接收消息”。当主线程空闲时,也就是可能恰好你已经取走了缓冲区中的数据之后,这个事件才触发。
基本上按照比较“保险、正规”的方式来编程,就不会有问题。当这个事件触发时,缓冲区里可以有0个或者多个字节,可能是 EOF 结尾也可能不是以它结尾的(在EOF之后立刻收到更多字节到缓冲区里),都应该用同样的流程来处理。
谢谢大牛同志,你解释了我的疑问。
相关知识也学习了,受教匪浅!
在我的程序中,无法避免的会存在0x1A的数据,不过应该不算什么问题,我可以解决。
同样谢谢各位朋友的帮忙,还不遗余力的给我相应的链接,谢谢!
|
|
工业串口和网络软件通讯平台(下载)
http://www.bmpj.net/index.php?m=product&f=browse&categoryID=1
看看你需要不
|