串口通讯SerialPort 疑问!

雪狼孤竹 2015-04-20 01:51:50
由于工作需要,接触C#不久,做了一个串口通讯小程序。

串口通讯使用的是SerialPort,接收数据是使用SerialPort的数据接收事件。一直没什么问题,能够正常发送,接收数据。近几天发现一个比较奇怪的现象,如下:

正常通讯情况:
上位机向下位机发送数据,下位机应答返回带有8个字节信息的数据,通讯结束。

异常情况:
上位机向下位机发送数据,下位机应答返回带有8个字节信息的数据,数据接收完,之后当这8个字节的数据中只要存在 十六进制的1A,就又会进入到SerialPort的数据接收事件中,但没有任何数据,也就是说数据长度为0,之后结束通讯。

一开始,我以为下位机又发起了串口通讯,但是经过下位机开发人员说,下位机什么都没有发,问题还是出在上位机,我就有点整不明白了,是什么触发的SerialPort的数据接收事件?为什么除了1A之外都没有问题,难道1A在SerialPort中有什么说法?

...全文
291 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
雪狼孤竹 2015-04-21
  • 打赏
  • 举报
回复
引用 16 楼 sp1234 的回复:
每当信息中有EOF就会立刻(或者说“额外”)触发事件,它原本就是这样设计的。 https://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport.receivedbytesthreshold(v=vs.100).aspx msdn上已经写明了,此事件触发“与内部输入缓冲区中的字节数无关”。
引用 17 楼 sp1234 的回复:
[quote=引用 14 楼 Snowwolf_119 的回复:] 我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。
你原本在设计信令格式时应该把 1A 作为消息的结束 。或者如果你的数据中不可能包括 1A,那么你设计其它结束方式也是很普通的。 现在你把 1A 弄到数据当中了。[/quote]
引用 18 楼 sp1234 的回复:
[quote=引用 12 楼 Snowwolf_119 的回复:] 再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发? 也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
只要是曾经接收过 1A,一定会在windows消息泵中排队插入一个“接收消息”。当主线程空闲时,也就是可能恰好你已经取走了缓冲区中的数据之后,这个事件才触发。 基本上按照比较“保险、正规”的方式来编程,就不会有问题。当这个事件触发时,缓冲区里可以有0个或者多个字节,可能是 EOF 结尾也可能不是以它结尾的(在EOF之后立刻收到更多字节到缓冲区里),都应该用同样的流程来处理。[/quote] 谢谢大牛同志,你解释了我的疑问。 相关知识也学习了,受教匪浅! 在我的程序中,无法避免的会存在0x1A的数据,不过应该不算什么问题,我可以解决。 同样谢谢各位朋友的帮忙,还不遗余力的给我相应的链接,谢谢!
雪狼孤竹 2015-04-21
  • 打赏
  • 举报
回复
引用 15 楼 wyd1520 的回复:
看了里面的原码 [quote=引用 14 楼 Snowwolf_119 的回复:] [quote=引用 13 楼 wyd1520 的回复:] [quote=引用 12 楼 Snowwolf_119 的回复:] 再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发? 也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
明白你的意思了, 不过有个疑问 如果你收到的像 0x11,0x11,0x12,0x1A,0x13,0x14,0x15 这样的0x1A 按你所说的接收事件,收到0x11,0x11,0x12,0x1A 后 接收收到一个0长度的字节?后面的,0x13,0x14,0x15 还会不会继续收?[/quote] 我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。 [/quote] 细看了他的原码 0x1A按你上面说的他是做为一个结束符来用, 当收到结束符后他会触发一次DataRecived事件,但里面的事件参数类型变成成 e.EventType= SerialData.Eof ,正常情况下是 SerialData.Chars。所以你应可以根据这个参数来识别是否为正常接收数据吧。[/quote] 嗯,我应该知道你的意思了。 其实这个异常在我这不算是正常数据,我判断一下字节长度就可以屏蔽了。 谢谢了!
雪狼孤竹 2015-04-21
  • 打赏
  • 举报
回复
引用 19 楼 zhoumeiwen 的回复:
你用个串口调试工具调试一下不就知道是不是你写的代码的问题了吗?说这么多。。。。
我不多说点,能说明白问题? 我即使说了这么多 ,你不是也没明白我说的是啥? 还串口调试工具?我上面不是没说,我也试过了,你什么眼神啊?
  • 打赏
  • 举报
回复
工业串口和网络软件通讯平台(下载) http://www.bmpj.net/index.php?m=product&f=browse&categoryID=1 看看你需要不
周美文 2015-04-20
  • 打赏
  • 举报
回复
你用个串口调试工具调试一下不就知道是不是你写的代码的问题了吗?说这么多。。。。
  • 打赏
  • 举报
回复
引用 12 楼 Snowwolf_119 的回复:
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发? 也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
只要是曾经接收过 1A,一定会在windows消息泵中排队插入一个“接收消息”。当主线程空闲时,也就是可能恰好你已经取走了缓冲区中的数据之后,这个事件才触发。 基本上按照比较“保险、正规”的方式来编程,就不会有问题。当这个事件触发时,缓冲区里可以有0个或者多个字节,可能是 EOF 结尾也可能不是以它结尾的(在EOF之后立刻收到更多字节到缓冲区里),都应该用同样的流程来处理。
  • 打赏
  • 举报
回复
引用 14 楼 Snowwolf_119 的回复:
我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。
你原本在设计信令格式时应该把 1A 作为消息的结束 。或者如果你的数据中不可能包括 1A,那么你设计其它结束方式也是很普通的。 现在你把 1A 弄到数据当中了。
  • 打赏
  • 举报
回复
每当信息中有EOF就会立刻(或者说“额外”)触发事件,它原本就是这样设计的。 https://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport.receivedbytesthreshold(v=vs.100).aspx msdn上已经写明了,此事件触发“与内部输入缓冲区中的字节数无关”。
本拉灯 2015-04-20
  • 打赏
  • 举报
回复
看了里面的原码
引用 14 楼 Snowwolf_119 的回复:
[quote=引用 13 楼 wyd1520 的回复:] [quote=引用 12 楼 Snowwolf_119 的回复:] 再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发? 也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
明白你的意思了, 不过有个疑问 如果你收到的像 0x11,0x11,0x12,0x1A,0x13,0x14,0x15 这样的0x1A 按你所说的接收事件,收到0x11,0x11,0x12,0x1A 后 接收收到一个0长度的字节?后面的,0x13,0x14,0x15 还会不会继续收?[/quote] 我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。 [/quote] 细看了他的原码 0x1A按你上面说的他是做为一个结束符来用, 当收到结束符后他会触发一次DataRecived事件,但里面的事件参数类型变成成 e.EventType= SerialData.Eof ,正常情况下是 SerialData.Chars。所以你应可以根据这个参数来识别是否为正常接收数据吧。
雪狼孤竹 2015-04-20
  • 打赏
  • 举报
回复
引用 13 楼 wyd1520 的回复:
[quote=引用 12 楼 Snowwolf_119 的回复:] 再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发? 也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
明白你的意思了, 不过有个疑问 如果你收到的像 0x11,0x11,0x12,0x1A,0x13,0x14,0x15 这样的0x1A 按你所说的接收事件,收到0x11,0x11,0x12,0x1A 后 接收收到一个0长度的字节?后面的,0x13,0x14,0x15 还会不会继续收?[/quote] 我目前状况是,你发送的0x11到0x15我都收了,这个作为正常的下位机回应。按理说,正常通讯就此结束。意外的是数据中存在0x1A时,上位机发送,下位机正常回应(0x11到0x15),我也都收了,处理了。之后莫名的就又触发了一次 数据接收事件,这次事件的触发,没有任何数据,缓冲区数据长度为0。
本拉灯 2015-04-20
  • 打赏
  • 举报
回复
引用 12 楼 Snowwolf_119 的回复:
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发? 也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
明白你的意思了, 不过有个疑问 如果你收到的像 0x11,0x11,0x12,0x1A,0x13,0x14,0x15 这样的0x1A 按你所说的接收事件,收到0x11,0x11,0x12,0x1A 后 接收收到一个0长度的字节?后面的,0x13,0x14,0x15 还会不会继续收?
雪狼孤竹 2015-04-20
  • 打赏
  • 举报
回复
再有,SerialPort中的 数据接收事件,是否能够没有数据的被触发? 也就是说,字节个数为0,的情况下,能否被触发,被谁触发?
雪狼孤竹 2015-04-20
  • 打赏
  • 举报
回复
引用 10 楼 wyd1520 的回复:
[quote=引用 8 楼 Snowwolf_119 的回复:] [quote=引用 4 楼 wyd1520 的回复:] 这与接收的字符没啥关系,你要看通讯协议是啥。。
哥们,你这回答,让我怎么说? 还是请你,好好看看问题,谢谢!![/quote] 明白你说的了。MS写的代码里 把0x1A 当成的结束符了。。 [/quote] 哥们看来你还是没明白我这个帖子到底说的是啥事情? 你也别猜了,我直接说简单点,就是在串口通讯过程中,SerialPort类遇到0x1A,是否会出现 触发数据接收事件? 我目前的情况是,只要通讯中存在0x1A,测试过的是 传输数据,协议中的一个部分,都会在成功通讯后,紧接着触发数据接收事件。 所以我猜测SeriPort对0x1A数据,有特殊处理,所谓特殊处理,也就是会导致它的异常触发数据接收事件,可能是0x1A对它有不可规避的某些东西,也可以说是它的Bug(个人认为,我希望不是),需要人为在外部解决。 由于我不太了解SerialPort的底层,所以上来问问了解的朋友,由于我自己没有写触发数据接收事件的代码,所以我可以说 数据接收事件的触发,一个是串口有数据,一个就是SerialPort的原因,也是我发此贴的意思。
本拉灯 2015-04-20
  • 打赏
  • 举报
回复
引用 8 楼 Snowwolf_119 的回复:
[quote=引用 4 楼 wyd1520 的回复:] 这与接收的字符没啥关系,你要看通讯协议是啥。。
哥们,你这回答,让我怎么说? 还是请你,好好看看问题,谢谢!![/quote] 明白你说的了。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();
            }
雪狼孤竹 2015-04-20
  • 打赏
  • 举报
回复
引用 4 楼 wyd1520 的回复:
这与接收的字符没啥关系,你要看通讯协议是啥。。
哥们,你这回答,让我怎么说? 还是请你,好好看看问题,谢谢!!
本拉灯 2015-04-20
  • 打赏
  • 举报
回复
引用 5 楼 Snowwolf_119 的回复:
[quote=引用 3 楼 duanzi_peng 的回复:] 是什么触发的SerialPort的数据接收事件? -> 只要 “缓冲区” 有数据进来,就会触发事件。 这跟你的字节是什么 没有关系。
如果缓冲区里有数据,还说啥?主要是没有数据,所以我才晕菜了!! 正常的一发一收,通讯结束,但是只有在数据中存在1A的情况下才之前的一收后,又再次触发了一次数据接收。 刚刚让下位机开发改了一下,让1A成为通讯协议中的一个命令字,结果就是所有数据都是两次触发数据接收,第一次正常接收,在正常接收之后,又再次触发了一个没有任何数据的 数据接收。估计真是SerialPort对1A数据的特殊处理啊!! [/quote] iSerialPort不会对1A这种数据做转门处理的,要么你的下位机弄的有问题 ,要么是你写的CODE有问题 。
雪狼孤竹 2015-04-20
  • 打赏
  • 举报
回复
不知道谁还更深入的了解过SerialPort,可能我上面是个例,毕竟我自己是没做人为触发 数据接收部分。 按我理解,可能是SerialPort对1A数据有什么说法。 还希望有懂其理的朋友,告之一二!
雪狼孤竹 2015-04-20
  • 打赏
  • 举报
回复
引用 3 楼 duanzi_peng 的回复:
是什么触发的SerialPort的数据接收事件? -> 只要 “缓冲区” 有数据进来,就会触发事件。 这跟你的字节是什么 没有关系。
如果缓冲区里有数据,还说啥?主要是没有数据,所以我才晕菜了!! 正常的一发一收,通讯结束,但是只有在数据中存在1A的情况下才之前的一收后,又再次触发了一次数据接收。 刚刚让下位机开发改了一下,让1A成为通讯协议中的一个命令字,结果就是所有数据都是两次触发数据接收,第一次正常接收,在正常接收之后,又再次触发了一个没有任何数据的 数据接收。估计真是SerialPort对1A数据的特殊处理啊!!
本拉灯 2015-04-20
  • 打赏
  • 举报
回复
这与接收的字符没啥关系,你要看通讯协议是啥。。
加载更多回复(3)

110,533

社区成员

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

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

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