项目要求:1.有六个串口设备,并有六个测试通道
2.六个通道可对六个设备选择,可能一个通道一台,也可能一个通道六台
3.这六个通关对仪器有不同的控制要求,并要读回数据作处理,要可以同时运行六个通道(六通道动作不同)
开发语言:VB6
OS:WINXP
我的作法:用六个TIMER控件写六个通道下的各种行为,点击指定按键,运行某个TIMER事件,当运行多个TIMER后,发现当后运行的TIMER动作时,先运行的TIMER暂停了
我查了相关资料说是在同一个窗体中同时这样运行六个TIMER是会出现我这样的情况,请问有何解决方法?我目前了解和确认用MDI窗体作六个子窗体是可以实现要求,但有无方法在一个窗体中实现这样的行为?
2.六个通道可对六个设备选择,可能一个通道一台,也可能一个通道六台
3.这六个通关对仪器有不同的控制要求,并要读回数据作处理,要可以同时运行六个通道(六通道动作不同)
开发语言:VB6
OS:WINXP
我的作法:用六个TIMER控件写六个通道下的各种行为,点击指定按键,运行某个TIMER事件,当运行多个TIMER后,发现当后运行的TIMER动作时,先运行的TIMER暂停了
我查了相关资料说是在同一个窗体中同时这样运行六个TIMER是会出现我这样的情况,请问有何解决方法?我目前了解和确认用MDI窗体作六个子窗体是可以实现要求,但有无方法在一个窗体中实现这样的行为?
串口是一对一的,所以六台设备各有一个串口,各串口参数一致.我再补充一下我的项目要求:
这是一个生产线产品测试程序,有六个测试通道,可能会同时或不同时测试不同的产品,而且各产品的测试步骤也是不同的,个别通道下可能会要求并联两台以上设备,(当然这样一来其它通道就不会进行测试)我现在遇到的问题是:当两个或者以上通道同时进行测试时,先运行的通道会停止在读数据的子函数中(有时是读电流,有时读电压,有时是读功率,这是查询Stack发现的),当把后运行的通道停止掉后,先运行的通道才会再继续下去
之前因为怀疑通道会共用某一个SUB或者函数,所以把所有通道用的SUB,函数全部独立了出来有四五年没写VB了,现在一上手就遇到这么个问题,难道真的太老了...哎求助!
On Error GoTo eHcomInitLd1
With mscomLoad1
If .PortOpen Then .PortOpen = False
.CommPort = portCom(idLoad)
.Settings = "115200,n,8,1"
End With
Exit Sub
eHcomInitLd1:
MsgBox Err.Description, vbOKOnly, "9841"
End SubPrivate Function loadRdLd1(strRd As String) As String
On Error GoTo EhClassRdLd1
Dim tTime As Long, DataReceive As String, timP As Long
With mscomLoad1
If Not .PortOpen Then .PortOpen = True
tTime = GetTickCount
.InBufferCount = 0
DataReceive = ""
.Output = strRd & Chr(10)
Do
DataReceive = DataReceive & .Input
DoEvents
If Right(DataReceive, 1) = Chr(10) Then
timP = GetTickCount - tTime
Debug.Print "LOAD Time Read : " & timP
loadRdLd1 = Left(DataReceive, Len(DataReceive) - 1)
Exit Do
End If
Loop Until (Right(DataReceive, 1) = Chr(10)) Or (GetTickCount > tTime + timeoutRd)
' Do While GetTickCount < tTime + timeoutRd
' DataReceive = DataReceive & .Input
'
' If Right(DataReceive, 1) = Chr(10) Then '.InBufferCount <> 0 Then 'And Right(.Input, 1) = Chr(10) Then
'' Debug.Print "Length = " & Len(DataReceive)
' loadRdLd1 = Left(DataReceive, Len(DataReceive) - 1)
' Exit Do
' Else
' DoEvents
' End If
' Loop
End With Exit Function
EhClassRdLd1:
MsgBox "9841 Communication Error : " & Err.Number & " : " & Err.Description, vbOKOnly, "9841"
End Function
这是其中一个通道的读回函数,程序经常性的暂停于此或者其它的设备的读回函数中
昨天试的方法不可行;
印象中这个问题N年前遇到过,似乎是个小地方,VB6有BUG?我在程序中用到了结构数组,所以主程序中有大量WITH存在,不知道有没有影响
TO:贝隆
1.你几年前上传的那个串口API的程序我试用了,发现不能连接我的设备,指令发送过去无效,因为没有时间就没有深究了,有空再研究.里面的API用法对我突破16个口限制有帮忙,这里先谢过;
2.你说在单窗体中用一个TIMER怎么实现,求教,因为在我的设计中,六通道以应六个TIMER,这六个TIMER通常只会运行一次,也即点击对应TAB页面上的测试键开始运行;六通道的测试项目也是不同的,运行的时间也相应的会是不同的.
3.呵呵,自从看了你的一些回复,一直想联系你,但不知道如何能找到你.
TO:贝隆
1.你几年前上传的那个串口API的程序我试用了,发现不能连接我的设备,指令发送过去无效,因为没有时间就没有深究了,有空再研究.里面的API用法对我突破16个口限制有帮忙,这里先谢过;
2.你说在单窗体中用一个TIMER怎么实现,求教,因为在我的设计中,六通道以应六个TIMER,这六个TIMER通常只会运行一次,也即点击对应TAB页面上的测试键开始运行;六通道的测试项目也是不同的,运行的时间也相应的会是不同的.
3.呵呵,自从看了你的一些回复,一直想联系你,但不知道如何能找到你.对于多串口通信,我通常的做法就是采用轮询,也就是在一个Timer中轮流读取各个下位机的数据,具体怎么区分?也很简单,就用Select语句来分别就是,实际上其效果和多线程并无区别。
TO:贝隆
1.你几年前上传的那个串口API的程序我试用了,发现不能连接我的设备,指令发送过去无效,因为没有时间就没有深究了,有空再研究.里面的API用法对我突破16个口限制有帮忙,这里先谢过;
2.你说在单窗体中用一个TIMER怎么实现,求教,因为在我的设计中,六通道以应六个TIMER,这六个TIMER通常只会运行一次,也即点击对应TAB页面上的测试键开始运行;六通道的测试项目也是不同的,运行的时间也相应的会是不同的.
3.呵呵,自从看了你的一些回复,一直想联系你,但不知道如何能找到你.对于多串口通信,我通常的做法就是采用轮询,也就是在一个Timer中轮流读取各个下位机的数据,具体怎么区分?也很简单,就用Select语句来分别就是,实际上其效果和多线程并无区别。
我的程序单个通道运行起来是没有问题的,但当开始了另一个通道的测试后,先运行的通道就没有问题,所以我想我的顺序读数据这一块出问题可能性不大;
之前一直怀疑是两个通道使用了公用变量造成了问题,但现在我已经把人用变量私化了,我反复检查过,也不太可能在这出问题;
所以想请你帮我想想什么情况下会出现这样的情况?也即暂停的通道总是停在DOEVENTS上,DOEVENTS的位置是在读BUFFER时才会有
耗时的代码最好分过程
...
Select Case Index
Case 0
' timCh1.Enabled = True
Call testCh1
Case 1
Call testCh2
....
end select
end subPrivate Sub testCh1()
Dim i As Integer, j As Integer, k As Integer, h As Integer, m As Integer
Dim flagFor1 As Integer, flagFor2 As Integer
totalStep(currentChanT(0)) = 0
flagFor1 = 0
flagFor2 = 0
' With itemStep(currentChan, i)
'查找For1,Loop1,For2,Loop2位置
For i = 1 To nStep
If flagStop(0) Then
Call doneStop(currentChanT(0) = 0)
Exit Sub
End If
With itemStep(currentChanT(0), i)
If .kindStep <> 100 Then
'状态显示表格赋值
valShow(currentChanT(0), 0) = getItemName(.kindStep)
'
If .kindStep = 5 Then '当为FOR1时在余下步骤中找出第一个LOOP1
stepFor1(currentChanT(0)) = i
For j = i + 1 To nStep '查找loop1位置
If itemStep(currentChanT(0), j).kindStep = 6 Then
stepLoop1(currentChanT(0)) = j
flagFor1 = 1
i = j '将当前测试步骤指向循环尾
Exit For
End If
Next j
'判断在FOR1中有无For2
For k = stepFor1(currentChanT(0)) + 1 To stepLoop1(currentChanT(0)) - 1
If itemStep(currentChanT(0), k).kindStep = 7 Then
stepFor2(currentChanT(0)) = k
flagFor2 = 1
Exit For
End If
Next k
'查找LOOP2
For k = stepFor2(currentChanT(0)) + 1 To stepLoop1(currentChanT(0)) - 1
If itemStep(currentChanT(0), k).kindStep = 8 Then
stepLoop2(currentChanT(0)) = k
End If
Next k
'状态显示表格赋值,记录FOR1循环次数
valShow(currentChanT(0), 1) = itemStep(currentChanT(0), stepFor1(currentChanT(0))).itemDes(1)
'按循环次执行FOR2测试,DO WHILE循环次数,FOR作循环步骤,步骤为stepFor2+1->stepLoop2-1
For k = 1 To itemStep(currentChanT(0), stepFor1(currentChanT(0))).itemDes(1)
'状态显示表格赋值
valShow(currentChanT(0), 1) = valShow(currentChanT(0), 1) - 1
valShow(currentChanT(0), 0) = getItemName(.kindStep)
For h = stepFor1(currentChanT(0)) + 1 To stepLoop1(currentChanT(0)) - 1
If itemStep(currentChanT(0), h).kindStep = 7 Then
'状态显示表格赋值,记录FOR2循环次数
valShow(currentChanT(0), 2) = itemStep(currentChanT(0), stepFor2(currentChanT(0))).itemDes(1)
For m = 1 To CInt(itemStep(currentChanT(0), stepFor2(currentChanT(0))).itemDes(1))
valShow(currentChanT(0), 2) = valShow(currentChanT(0), 2) - 1
For j = stepFor2(currentChanT(0)) + 1 To stepLoop2(currentChanT(0)) - 1
' DoEvents
'执行五测试
Call itemTestCh1(currentChanT(0), j)
'按下停止键,停止测试
If flagStop(currentChanT(0)) = True Then
Call doneStop(currentChanT(0))
Exit Sub
End If
'判断是否按下暂停键
Do While flagPause(currentChanT(0)) = True
DoEvents
Loop
'关闭数据读取
' Call swTimer(currentchant(0), False, 1000)
Next j
Next m
Else
'执行五测试
Call itemTestCh1(currentChanT(0), h)
'按下停止键,停止测试
If flagStop(currentChanT(0)) = True Then
Call doneStop(currentChanT(0))
Exit Sub
End If
'判断是否按下暂停键
Do While flagPause(currentChanT(0)) = True
DoEvents
Loop
'关闭数据读取
' Call swTimer(currentchant(0), False, 1000)
End If
Next h
Next k
Else
'判断项目类别执行五种测试项之一
Call itemTestCh1(currentChanT(0), i)
'按下停止键,停止测试
If flagStop(currentChanT(0)) = True Then
Call doneStop(currentChanT(0))
Exit Sub
End If
'判断是否按下暂停键
Do While flagPause(currentChanT(0)) = True
DoEvents
Loop
'关闭数据读取
' Call swTimer(currentchant(0), False, 1000)
End If
End If
End With
Next i
'测试完成,停止测试
Call doneStop(currentChanT(0))
flagStop(0) = True
End Sub
Private Sub itemTestCh1(tmpChan As Integer, tmpStep As Integer)
...
Select Case .kindStep
Case 0 'DisCharge
...
Call statusReadCh1(tmpChan)
case 1
...
end select
end sub Private Sub statusReadCh1(tmpChan As Integer)
...
valShow(tmpChan, 3) = Format(cmdRdPloadVCh1(tmpChan), "#0.000") '电压
valShow(tmpChan, 4) = Format(cmdRdPloadICh1(tmpChan), "#0.000") '电流'
valShow(tmpChan, 5) = Format(cmdRdPloadPCh1(tmpChan), "#0.000") '功率'
...
end subPrivate Function cmdRdPloadVCh1(tmpChan As Integer) As Double
...
loadRdLd1("meas:volt?")
...
end sub
Private Function loadRdLd1(strRd As String) As String
On Error GoTo EhClassRdLd1
Dim tTime As Long, DataReceive As String, timP As Long
With mscomLoad1
If Not .PortOpen Then .PortOpen = True
tTime = GetTickCount
DataReceive = ""
.Output = strRd & Chr(10)
Do
DataReceive = DataReceive & .Input
DoEvents
If Right(DataReceive, 1) = Chr(10) Then
timP = GetTickCount - tTime
Debug.Print "LOAD Time Read : " & timP
loadRdLd1 = Left(DataReceive, Len(DataReceive) - 1)
Exit Do
End If
Loop Until (Right(DataReceive, 1) = Chr(10)) Or (GetTickCount > tTime + timeoutRd)
' Do While GetTickCount < tTime + timeoutRd
' DataReceive = DataReceive & .Input
'
' If Right(DataReceive, 1) = Chr(10) Then '.InBufferCount <> 0 Then 'And Right(.Input, 1) = Chr(10) Then
'' Debug.Print "Length = " & Len(DataReceive)
' loadRdLd1 = Left(DataReceive, Len(DataReceive) - 1)
' Exit Do
' Else
' DoEvents
' End If
' Loop
End With Exit Function
EhClassRdLd1:
...
End Function以上是其中一个通道的代码,原来两个通道是在一个SUB中,但担心出问题,所以分离了开来,本来代码没这么复杂,后面基于同样的原因采取了分离,所以两个通道的代码基本是一致的而双通道运行时,程序总是会停在读串口数据的DOEVENTS那,这是查看call stack发现的,而且我用断点证明过确实是停在那里
目前程序中就只有在读回上有DOEVENTS存在请大家帮忙看看,我这边也在同步在调试
看起来跟发电机复示器比较像,
如果是那种程序的话,先把采集和显示分离开来,
比如你可以用一组mscomm和timer数组,功能就是定时采集数据,然后存到一组变量里边,这样采集程序就完成他的功能了。
然后按钮部分,按钮不管是外部的还是内部的,只对他的触发做处理,就是按下或者放开,按下时标记一个按下的值,放开时标记一个放开的值,不要去紧盯着按钮状态,很消耗资源有按下标记了就认为他按下。
然后是数据加工处理部分,那就要看你需要了,是根据按钮动作来的,还是需要实时处理的,反正处理完的数据就交给显示程序去显示。
产生的问题也有可能和时间有关
在我原来的程序中,数据采集和发送处于同一个SUB中,那么当扔出DOEVENTS时,权限就会跑到另一个通道,直到另一个通道的进程终止;
我想我的改法是:1.设立六个TIMER对应六台设备,TIMER设为10ms运行一次,读回VIP(三次读回最大耗时180ms)
2.通道程序中只提供设备的设定指令,设定完成后即等待一个设定的延时后再去取回TIMER中采集的VIP
而恰巧客户对于显示的要求是1S一次,而我的机器读回一个参数最大耗时是60ms,写入约10ms的延时
3.其中有一项测试步骤比较麻烦一点,要实时采回一组连在一起的字符串,不过原因找到了我想就能想办法规避掉再次感谢你的回复,我先要改程序了,时间隔太久了,这问题以前肯定遇到过并解决过.我有五年没写VB程序,8年没写VB的串口程序了,老了老了,真怀疑我的工作寿命还有多久
我一般在timer头上把timer.enable=false,在结束的地方timer.enable=true
1.将主函数也即测试步骤进行的函数分割,通过判断标志压缩运行时间;
2.将分割后的函数再细分,长时间运行的函数再细分,将其运行时间压缩,这样用了DOEVENTS后控制权也能快速放出
就现在的情况来说,不这样分就用不了DOEVENTS,因为不用DOEVNETS的话程序就象死机一样,虽然仪器还在动,呵呵谢谢你的回复,但这种程序还是需要用DOEVENTS的谢谢你的回复,100ms以内的误差都可以接受
请教:多个TIMER同时运行时即其ENABLE都为TURE时执行顺序有无规则?
最近几年没有写过VB,一直在作LABVIEW,真的忘记太多
思索作为程序员的未来的路.希望有朋友们顺便加入来讨论这个问题
我这个真的有点头痛,
我在想这样一个作法:把六个通道分到六个MDI子窗体中,程序运行放在各窗体的按键事件中循环,当然循环会很短的耗时,再加上DOEVENTS画面就不显得死机,同时用一个TIMER来捕捉7台设备的数据提供给六个通道调用,感觉不一定行,但要试,现在在家没法试了
不知道如何实现六进程呀,之所以用六个MDI子窗体是因为我见过一个几乎相同的程序以MDI子窗体为对象,创建了八个通道来作
顺便请教如何实现六进程
timer时间太短的话doevents很容易触发别的timer,或者你在doevents之前把别的timer关掉,结束之后再开,不知道会不会好些,不过担心有些timer可能会因此不能工作,试过才知道。看来只用一个timer处理起来比较好些
一进timer之后就把这个timer 关掉
然后就可以放心用doevents了
结束timer之前再把timer打开,像这样子。
Sub Timer1_Timer()
Timer1.Enable=False
...
...
Doevents
...
...
Timer1.Enable=True
End Sub
六个通道下还有不同的步骤,当然也有可能是相同的步骤,对于时间的要求自由性很大,有可能是1S采集记录一次,也可以是多秒,这个时间也是由客户定义,并且在通道的步骤中有一个步骤还需要不断的侦测设备的返回值,而这个步骤也是由用户自由设定的可以出现在任何一个通道中
如你所说,我想我的作法将要改为如此:
1、用两个TIMER,一个采集数据,一个运行六通道的程序,同一时间保证只运行一个TIMER;
2、对时间的要求比较高,而且也相对较难处理;对六通道的当前步骤的采集时间进行排序,建立一个序列,顺序采集并保存显示;这一块有一定难度,到时要想想
3、运行六通道的程序作为主程序,用FOR循环顺序判断六个通道是否执行,如果步骤为初期设定,则设定完后跳出到下一个通道,并且设置采集TIMER为TRUE;如果是采集,则收回采集TIMER中采集到的数据,
4、采集TIMER每运行一次在尾部FALSE;
5、假设六个通道都在运行,采集间隔要求为1S,3S,2S,5,6S,那么就需要定义两个变量数组,分别对应当前步骤的起始测试时间,和采集间隔时间,在每一次主程序循环时都判断这个起始时间+间隔时间到了没有如果到了就采集,并对最短的时间量进行延时补偿
今天要在家陪女儿,明天去公司试,笨狗兄再帮我补充补充
另外请问一下:我打算每个通道满5K条记录就存贮为一个文件,我现在的这个存贮部分是放在单个通道的显示SUB中,不知道对于量测时间上会否产生干扰?或者说这部分可能需要多久时间完成?