串口通信类库 通讯范例大家帮忙看看这样写好不好?http://blog.csdn.net/yeqi3000/article/details/8236555
串口通信类库 通讯范例 大家帮忙看看这样写好不好?
http://blog.csdn.net/yeqi3000/article/details/8236555
串口通信类库 通讯范例 大家帮忙看看这样写好不好?各位牛人们,你们通信的类库都是怎么做的?
[解决办法]
我是根据需求 定义出符合自己的类库,然后打包封装成DLL,
[解决办法]
我这个是基础通信类,然后其他通信设备继承这个类再拓展功能,但收发数据都是用这个基类里的方法。
[解决办法]就没有大牛来给点意见么。求提高!
[解决办法]最后一次人工置顶,求意见。
[解决办法]存在很大的误导。。
你认为一次通讯肯定就能接收完数据
if (DataCount >= _FullCmdCount)//接收到数据位数量正确
如果一条完整的数据被分成多次收到的话,你永远不能得到一个正确的结果。因为你丢弃了原本一条完整报文的另一部分。
还是赶紧先从blog中拿下来吧。以免误导别人。
[解决办法]请看清楚好吗?这个是一个异步数据接收。在发送数据的方法里有时间超时判断。
接收数据里面不是一次性接收完的。触发了RSSerialPort_DataReceived之后,是要做一些判断。一个是不是SendBytes中已经认为超时不再需要你接收数据了,一个是判断接收的数据位数是否达到的预定的正确数据位数。若数据位数还没达到,那么下一次触发RSSerialPort_DataReceived时将再次判断数据位数是否达到预定数据位数。如果在一段时间内都未能达到。这个时候SendBytes就认为接收超时返回false了。
不过还是很感谢你进来回帖。
[解决办法]当_IsAllowReceiveData 为true时根本不会丢弃任何数据。
[解决办法]还有一点,我想你并不清楚,不执行
this.Read(ReCMD, 0, _FullCmdCount);//读取数据
这一句的话,数据是还在缓存里的。所以根本不存在多次接收一条完整报文就会丢弃其中一部分的情况。
[解决办法]为了谨慎,我又仔细看了一下你的代码。
首先一个问题是:在很多项目中,你不能预计串口可以返回多少字节的固定长度的数据。就是说一条完整的报文的长度是未知的。
下面讨论先前的问题:
设你发送0x01 0x02到串口,你期望串口可以返回 0x01 0x02 0x03......0x10
共10个字节。
理论上,你往串口写入数据后,就有可能马上接收到数据。
假设你第一次这样:
int DataCount = this.BytesToRead
接收到1个长度的字节,即0x01
显然DataCount小于_FullCmdCount(期望的10个字节的长度)
接着该事件再次引发,假设这次接收到0x02 0x03共二个长度的字节
显然,DataCount小于 _FullCmdCount (期望的10个字节的长度)
接着继续上面的事件引发。
10个长度的字节返回被分成N次接收到。
而你的代码总是没有办法去处理这一个完整的报文 。
假设一共分成了5次接收完,花费2秒。而你的超时设置为1秒,因为超时的原因,你的代码也不会有正确的结果。
[解决办法]请弄清楚 this.BytesToRead 和this.Read(ReCMD, 0, _FullCmdCount);的区别再行讨论
[解决办法]显然你也并没有仔细看我上面给您的回复。跟您解释了为什么多次接收数据不会出现丢失数据的原理。
[解决办法]关于你说的超时设置的1秒的问题。这个是弹性的。如果下位机完成一次通讯确实需要2秒。完成可以延长这个超时时间设定。
[解决办法]算了,就当我没有说吧。。。。
[解决办法]说了就是说了嘛。大家讨论下嘛。
[解决办法]有个疑问,如果串口接收到的数据长短不一,长点的一帧数据可能有好几十个字节,短点的可能就几个字节,这样的话,数据帧比较长的会分几次触发RSSerialPort_DataReceived事件吧。
this.Read(ReCMD, 0, _FullCmdCount);//读取接收缓冲区中的数据
_ReceivedData = ReCMD;
这样后面接收到的数据会覆盖之前接收到的
[解决办法]比如一个完整的返回数据: 01 02 03 04 05 06 07 08 09 10;
第一次触发RSSerialPort_DataReceived接收到了01 02
这个时候 if (DataCount >= _FullCmdCount) 肯定为false(因为_FullCmdCount为10时才是正确的,当前缓冲区只有2个字节)。那么本次触发的处理就到此结束了。
第二次触发RSSerialPort_DataReceived 接收到了 03 04 05
这个时候 if (DataCount >= _FullCmdCount) 肯定为false(因为_FullCmdCount为10时才是正确的,当前缓冲区只有5个字节(因为上次并没有把缓冲区的数据读取掉))。那么本次触发的处理就到此结束了。
依次类推如果在SendBytes函数中的while中限定的时间内还没有完成完整数据的接收。SendBytes将认为接收超时。
[解决办法]那再举个例子加以说明好了,串口接收到1,2,3,4,...,19,20(每个数字为1个字节)
一触发事件就开始读取串口,假设BytesToRead=8(主要是因为我在通信过程中往往是8,此处就假设为8,应该跟波特率有关),那么1~8,9~16,17~20分别触发了DataReceived事件,最后,this.Read(ReCMD, 0, _FullCmdCount),ReCMD里的数据将会是17,18,19,20;
寻求除了加延迟外的其它方法
[解决办法]你理解错我的意思了
比如一帧数据有20个字节,但是也许8个字节(在我的程序中,设置的是1个字节就触发接收事件,但BytesToRead往往为8,波特率为9600),这样一次接收的就是8个字节,剩下还有12个字节会再触发两次接收事件,于是,20个字节触发了三次DataReceived事件,最后this.Read(ReCMD, 0, _FullCmdCount)读到的将是最后4个字节,之前的都被覆盖掉了。
不知对这个问题,LZ有何高见,我只能想到在读取串口之前加入延迟以确保所有数据都已经到缓冲区继而一次性接收数据,求其他更好的方法。
[解决办法]我求证一点。如果触发了DataReceived事件,即使不去读取缓冲区的数据(即不执行this.Read(ReCMD, 0, _FullCmdCount)),缓冲区数据也会被清空吗?
[解决办法]你说触发几次就触发几次啊
你可以自己仔细跟踪下,触发次数跟你设置的那个多少字节引起事件是有关系的
串口接收最好是每次接收后放到队列
然后分析队列数据
楼主确实存在一部分误导的嫌疑啊
------解决方案--------------------
我明白了。你所说的设置字节是指的:ReceivedBytesThreshold属性吧。默认就是1。应该每一个字节都会触发。
[解决办法]“设置的那个多少字节”是指?
[解决办法]不要应该了。。。。你找两台电脑去通信下,或者用电脑跟单片机通信下,理论上是1个字节触发一次,但实际上不是那么一回事。
不读缓冲区的数据不会清空缓冲区内容,但问题是,应该在何时读取,总不能一直不读呀。
[解决办法]首先向楼主说sorry.我有一部分没有看清楚,就是在未读取数据时,数据将一直保存在操作系统的缓冲区中。
但是这里存在这样一个问题,如果说类库使用者将FullCmdCount 属性的值设置的比较大。大到超出SerialPort.ReadBufferSize的默认值4096,那么在多次事件触发中都不会从缓冲区读数据,这样可能就会造成缓冲区已满的问题!楼主想想会不会这样?
第二这个库可能不太适合处理那些从串口返回的数据不定长的情况。
[解决办法]那你可有仔细看过我里面丢弃数据的部分呢?你没看到每一次发送新的数据命令前,都清空了缓冲区吗?
[解决办法]求指导啊,队列怎么用啊~~~~~~~~~用数组?
触发次数不止跟ReceivedBytesThreshold有关,明明我设置的1,但是并不是每个字节都触发事件。
[解决办法]你可以用泛型: List<byte> 来存储。
这个触发我是知道的,微软官方也说明了DataReceived是不保证每次都触发的。
[解决办法]是的,我现在主要做通讯,每次数据返回量都不太大。所以肯定不会超出缓冲区。如果有必要肯定是自定义缓冲区来处理接收数据的。
现在你们看到的版本其实是最简单的基本版本,为了提高通讯的速度,我做了一些简化。
至于你说的不定长的情况。现在的类库肯定是不行的。关于不定长的情况,FullCmdCount 这样的定义肯定不需要了。而是根据校验值计算了。每次接收完数据都做一次校验,如果校验正确则认为接收成功完成。
[解决办法]清空缓冲区有用吗,清空只会丢失数据呀,貌似我跟你说的不是一码事,我说的是数据分几次触发接受事件怎么办,我希望只触发接收事件一次,这样可以一次性完整的读取串口。我只是在请教怎么完整的接收数据比较好,跟清空没有关系。我没用过List<byte>,这个我倒是可以好好学习下的。有空我私信你请教下