在做一个报警盒测试软件中,遇到这样的问题:
报警盒采用被动方式与计算机沟通,计算机发送一次查询,报警盒返回当前状态.为了实现自动化,采用了Timer,但是在用到多个Timer时,出现了问题:进入某一Timer时,系统要处理此过程直到该Timer停止,即某一时间内只能运行一个Timer,因而使用Doevents来转移控制权,使得多个Timer能互不干扰.代码如下:Private Sub Timer1_timer()
   函数A     '报警状态查询并返回值
    ....     '根据返回值进行相应的处理并在程序界面给出显示      函数B     '开关状态查询并返回值
    ....     '同上
End SubPrivate Sub Timer2_timer()
   OverTime = true
End SubPrivate Sub Timer3_timer()
   函数C     '由一个按钮控制其Enable.需要在Timer1进行的同时进行此操作
End SubPrivate Function 函数A(ByRef 返回值)
   发送报警查询命令
 
   FlagIn = False
    Timer2.Interval = 150    Do
      If OverTime Then
          Exit Do
      End If
      DoEvents
   Loop Until FlagIn   Timer2.Interval = 0   If FlagIn = True Then
       'Oncomm事件被激活,对接受到的数据进行处理
   End IfEnd FunctionPrivate Function 函数B(ByRef 返回值)
   发送开关查询命令    FlagIn = False
    Timer2.Interval = 150    Do
      If OverTime Then
          Exit Do
      End If
      DoEvents
   Loop Until FlagIn   Timer2.Interval = 0   If FlagIn = True Then
       'Oncomm事件被激活,对接受到的数据进行处理
   End If
End FunctionPrivate Sub MSComm1_OnComm()
       '发生Oncomm事件
       FlagIn = True
End Sub
现在这样写,程序能运行,并基本上满足需求,各个Timer互不干扰,并能对硬件状态做出同步反应,但是当硬件发生中断时,就出现了问题:       按设计思路,因Doevents的关系,硬件中断后,再次恢复与计算机通讯后,在Oncomm事件过程中,FlagIn状态被改写,为True,此时的True值应该传入函数A或B中,结束函数中的DO循环,并进行处理,但是并未按想法运行,而是进入函数A或B后,FlagIn又被改写成False.在循环一个不确定的时间后,才跳出DO循环.(因为要兼容多种设备,故有多种协议,在A协议中,中断再恢复,不会出现这个问题,但是在B协议中,中断再恢复就有问题,这也是奇怪的地方,如果是程序的问题,应该两者都出错,但是只一种协议有问题,两种协议的处理方式都是一样的)       我分析问题可能出现在Doevents上面,因为MSDN上面关于它的详细解释也是很模糊,很多不可预料的结果.但是要实现自动化,一般都是用Timer,或者创建多线程,多线程我没试过,不知道会不会也出现这种情况.       或者改进我现在处理方式,避免使用Doevents.       我表达的不是很清楚,因为这个问题实在很奇怪,我尽量把我的意思说明白,请大家伸出援助之手~~~

解决方案 »

  1.   

    Dim OverTime as Boolean, FlagIn as boolean你这个在那边宣告了 ?
      

  2.   

    这两个是全局变量.
    声明在窗体顶部.
    呵呵,cbm666,你好啊
      

  3.   

    呵呵 你好, 不完全明白你的思路, 但大概可以看得出来.我觉得你应该要使用一个Function就好了,在里面再定义A与B各别的判断,FlagIn1与FlagIn2两个变量来搞MSComm1_OnComm() 接收到的信息如能识别为A(FlagIn1)或B(FlagIn2)那就更好搞了.
      

  4.   

    Doevents会造成过程重入,有些情况下会有非常严重的情况发生...能不用就尽量不用.建议从流程上优化.MSCOMM控件内部有单独的线程来进行串口收发,并且已经在VB这边做成了事件驱动,看看有没有办法优化你的流程,从而实现不使用Doevents.以上是我以前做工控通讯的一种思路吧~~至于你的这个代码,看起来可以如3楼所说,在OnComm事件里面进行处理.不过如果你的处理代码比较消耗时间,那还要做一下排队处理,也就是OnComm事件里面把数据都收起来,等上一个处理过程空闲了再让其处理.以前就遇到过一个做得比较差的采集卡,它里面没缓存,数据是实时到达串口,事先也不通知的,直接扔过来.如果不收起来下次就没了.那哪是采集卡,根本就是一个A/D转换器,靠.说起来就想骂了.后来就使用了排队处理,就OK了.
      

  5.   

    呵呵,感谢cbm666,myjian两位来帮我,因昨天休息,没来看帖:)见谅见谅!
        处理过程是这样的:        发送查询码----报警盒回送识别码---接受并处理
             
    报警盒的发码间隔需要在150ms以上,这样在处理时,为了实现实时报警,必须不间断发查询码(Timer1),但是如果不使用Doevents,则无法激活Oncomm事件(Timer1不能停止).
    所以就加了Timer2,来处理Oncomm.cbm666说在一个函数里处理报警和开关两种情况,但是因为我现在要兼容多种设备,各个设备的通讯协议又各不相同(有的甚至同一协议里报警码,开关码,回送码的位数都不一样),写到一起程序可能太长,所以先分开写.老马说的MSCOMM控件内部有单独的线程来进行串口收发,并且已经在VB这边做成了事件驱动,这个事件驱动是什么?我现在是处理的CommEvent(comEvReceive).现在没有在Oncomm里处理数据,是将收到的数据传入函数A or B处理,因回送码一般为一个字节(8位),所以处理起来不会太久,可能问题就出在发码到串口,串口回码的通讯时间上面,因为这时间不能确定.
      

  6.   

    呵呵,问题解决了,如老马所说,Doevents造成了代码重入,计时器周期过短,造成A、B的代码只执行一半就进入下一次循环了,感谢老马和cbm666,结帖!
      

  7.   

    咦,怎么又看不到回复了CSDN在搞什么呀.一回复肯定又能看见了.哎.