[replyview]
[upload=rar]viewFile.asp?ID=10[/upload]
[/replyview]
关于本软件 1.PLC串行通讯简易调试软件目前仅对三菱FX系列有效 2.PLC串行通讯简易调试软件已经将收发功能打包成CLS类的方法onCommRevPLC,onCommSendPLC等使用时直接调用 3.由于VB本身执行效率的问题,连续发送或接受要有延时,否则会丢失或发送信息 4.你可在 PLC论坛(http://www.plcjs.com/bbs/index.asp?boardid=36)更经典的讨论
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
信号丢失解决方法:
以前做的485总是纯粹的8位方式,因为很多前辈都栽倒在PC端上了,所以我就不尝试9位的方式了,失去了DOS这个乐园,windows的9位多机通信真是让人失色,但是8bit方式的缺点非常明显:每次主机发送指令后,所有终端都收到了,之后才判断是不是喊自己,被叫的从机发送执行数据也要带上机号,而且发送的时候,所有从机又收一遍,收完之后又废除。。。。。
我依然决定尝试9bit的方式,起码这样做从机有权听不到和自己不相干的信息,这倒不是因为从机很忙,而是因为这年头,事不关己高高挂,主管又没找我,我何必竖起耳朵装孙子。
我选择了VB6+MsComm,使用RTS作为收发切换,我一上来就发现只要在发送之后修改了RTS线的状态,通信肯定出问题,百思不得其解,因为我在Handshaking属性中设置成了comNone,纯正的三线制,根本不需要RTS来左右数据流握手呀,RTS在发送前设置为True,发送后延时转为接收设置成false,但是就是这样的变化就引起数据丢失,去掉多RTS的控制就正常,想不通就干脆不想了,我干脆将控制线换成了DTR,嘿嘿,这下子没事了,看来mscomm对RTS有一定的敏感性。只是不知道那么多大侠都使用的VB6+MsComm,为什么都声称自己使用RTS控制自如呢?而我却不得要领。
接下来,因为发送完机号之后应该发送数据,他们之间的差别在于多级通信位的不同(第九位),那么既然修改了MsComm的设置,就应该等机号数据完全发送结束之后再修改设置发送剩余的数据。于是我装模作样的这样写: While (MSComm1.OutBufferCount <> 0) '等待发送数据流发送完成 DoEvents Wend 结果我发现根本不起作用,因为即使一次发送几百字节,OutBufferCount的查询结果都是0,于是我改成: Public Transmit_OK As Boolean ' 串行缓冲区数据发送完成标志
在 MSComm1_OnComm()中加入: Select Case MSComm1.CommEvent Case comEvSend Transmit_OK = True End Select
Transmit_OK = False MSComm1.SThreshold= 1 '发送缓冲区空的时候激发OnComm事件 MSComm1.Output = Recs While (Transmit_OK = False) '等待机号字节发送完成 DoEvents Wend
这样总算差不多了,起码会等到缓冲区为空的时候通知发送结束。我在115200bps下按照每包32字节,共计发送了8192包数据给从机,都没出错,我以为没事了,可是,当我将波特率改为9600bps的时候,发现从机接收数据包的通过率跌落到了小于5%的地步!有这样的可能吗?高波特率正常但是低波特率却不能工作,我仔细检查后认为波特率设置没有错,问题被定位在了发送机号结束后,虽然得到了MsComm的通知事件,但最后一个字节毕竟没有在总线上发送完,所以接下来修改第九位多机通信位再发送命令数据就会出错,于是我将波特率压低到1200bps再试验,这下子热闹了,没有一个数据包被正常接收!据此判断,115200bps之所以好用,是因为检测到缓冲区空到数据完全在总线上发送结束之间的时间非常短,可以忽略不计,所以不会出错,而9600bps~1200bps就不同了,于是我就在检测到发送缓冲区为空之后,加入延时10ms,开始使用Timer来实现(PII之后的定时器精度为10ms,不再是55ms),再试验9600bps,基本成功,我继而测试2400bps,偶尔有不成功,加大延时为20ms在1200bps下仍然有不成功,不能再加大了,因为终端的超时时间设定是50ms,因为我在VB延时循环过程中使用了doevents,所以实际时延变得不确定,而且如果不加doevents,有时候程序会有不响应外部事件的问题,非常挠头,windows难道没有一个精确延时器吗?上网翻了一通,搞来了一各延时函数,总算基本满足我的要求了:
Public Declare Function GetTickCount Lib "kernel32" () As Long '它传回Windows启动後到目前为止所经过的时间,传回值以微秒为单位? 'delay (BUS_Comm_Byte_interval是延时时间,ms) Dim Begin_time As Long, End_time As Long Begin_time = GetTickCount() Do End_time = GetTickCount() Loop Until (End_time - Begin_time) >= BUS_Comm_Byte_interval
GetTickCount()函数被下载网站的版主描述成是返回us精度的,但是我测试是以ms为单位的,精度嘛就更不好说了,看来做纯PC开发的人不会象我们做单片机的这样会对时间精度负责的,不过这个函数肯定优于Timer控件,我体会还可以对付。这下子在延时20ms的时候,下位机没发生超时错误,而用Timer的时候就不确定。不过找个问题也让我猜测MsComm的发送机理,OnComm事件发生的时候,虽然表示缓冲区空了,似乎只有一个字节等待发送,但MsComm提供的串行缓冲区并非硬件的最终发送缓冲区,也就是说串口适配器16C550里面还有若干字节的FIFO,我们没法控制它不用FIFO,那么mscomm发送结束仅仅是将待发数据都转移到了16550的FIFO,这时候总线上还要持续发送多久我们是很难把握的,此时我们改变发送设置或者切换总线方向都是不可预知的。我眼下是蒙混过关了,但肯定尚有很多隐患,不知各位是如何考虑这个问题的。
MsComm中定义第九位多机通信位的方法如下,其中BUS_Comm_Baud是波特率: MSComm1.Settings = Format(BUS_Comm_Baud) & ",M,8,1" '第九位置1 MSComm1.Settings = Format(BUS_Comm_Baud) & ",S,8,1" '第九位置0
总之,我感觉用VB+MSComm做多机通信似乎有很多不可预知的东西,特别是收发切换的时间控制问题,这个时间快了怕尚未发完就转入接收,慢了又影响网络效率,唉,一言难尽。
[此贴子已经被作者于2006-6-13 21:25:32编辑过] |