各位老鸟,我用的MSCOMM控件做的一台设备的接受,现在能够从那台设备接收到一串数据,源代码如下:
Private Sub Timer1_Timer()
If MSComm1.InBufferCount > 0 Then
MSComm1.Output = Chr(6)
Text1.Text = Text1.Text + Trim(MSComm1.Input)
End If
End Sub接受到的数据显示在文本框中,如下:
  1H|\^&|||99^2.00|||||||P|1.00|20030926090537  格式 yyyymmddhhmmss
 22
 2P|1|||^^^
 CD
 3O|1|03092525|||R                         样本号25
 1B
 4R|1|^^^1|13.3|sec.||||F||||                    第一个结果13.3sec
 56
 5M|1|A|@
 B8
 6R|2|^^^2|1.09|INR||||F||||                    第二个结果1.09INR
 DD
 7M|2|A|@
 BB
 0R|3|^^^3|1.07|Ratio||||F||||                   第三个结果1.07Ratio
 ED
 1M|3|A|@
 B6
 2R|4|^^^4|12.4|Ref.T||||F||||                   第四个结果12.4Ref.T
 90
 3M|4|A|@
 B9
 4L|1|N
 07
注明的是sec INR Ratio Ref.T都是我们的医用单位,
?chr(3)   'ETX
 
?CHR(2)   'STA
 
我现在的问题是如何实现以下功能(我前面已经做好了数据库和输入界面):
1. 如何接受数据后自动判断目前的日期和样本号,关键是后者,判断后自动存储进入相对应的样本号的表中。我已经建立好的输入界面和数据库,比如在电脑上按照样本号输入某个病人的基本数据后先存贮,随后设备开始工作后结果出来数据按对应的样本号传输过来了。
2. 结果数据按样本号传输过来后,分别按对应的结果(或者称为通道)第一个结果(通道),对应通道号传输到相对应的位置上?这个如何完成,用程序?
其中我的数据库已经做好,用的access,包括sec INR Ratio Ref.T四个结果,如何实现用个模块实现接收后获得有效数据,然后分别存储入对应的数据库中?不知道我的问题和我的想法说清楚没有?能否给我讲一下思路或者如何实现目标的其它方法?谢谢。如果有参考的源代码更好。高分相送!

解决方案 »

  1.   

    按照你所提供的数据来讲,你的通信方式属于一种不可靠的通信协议,主机发出一个请求,客户机不管3721就返回一堆数。
    建议首先修改通信协议,比如加上包头、长度、校验码、包尾等信息。有了这些信息,以2进制的形式接受和发送数据,你很简单的就可以确定真正的数据是哪些,而这些数据的分隔符等都是确定的,所以你很容易就知道你想要的东西。
    按照你现在的协议方式,只能在接受到数据之后,想全部放到一个缓冲当中,在缓冲里不管3721的将所有数据拼接成一个大字符串,然后查找“1P”的位置作为数据开始位置,依次类推去分析所有数据。
    但你提供的程序中有很大的问题,就是串口通信是需要时间的(实际所有的数据通信都一样),也就是说,如果Chr(6)是要求客户机返回数据的命令的话,那么在你发出了命令之后,应该会等一会才接收到新的数据,所有数据显示的部分不应该在Timer事件中,而应该在MSComm控件的OnCom(好像是这么写吧,记不清了)事件里。关于MsCom控件如何激发OnCom事件,你可以查一下MSDN,里面有详细的解释。
      

  2.   

    楼上的各位老鸟,谢谢大家,特别是 AresChen,因为我被临时通知待命SARS应急小组演习去了。回来后没有多久。本人是从医的编VB的菜鸟,菜得很,很多的源代码都是看着书做的。
     如AresChen所说,设备其实与PC之间有通讯协议的,我从word上面复制到论坛上出了点问题,设备发送<ENQ>,PC发送<ACK>,随后就是<STX>1H|\^&|||99^2.00|||||||P|1.00|<CR><ETX>2A<CR><LF>,也就是上面的  1H|\^&|||99^2.00|||||||P|1.00|20030926090537  
     22
    其中有些不可见字符。随后PC发送<ACK>,然后设备再发送以<STX>开头的如上的字符。我本来不想把所有的字符都放到缓冲里面的,但是模仿的源代码如此,幻想的是一条一条处理的,结果水平有限。各位老鸟能否帮忙给个类似的源代码参考一下,我的参考书实在没有类似的啊!谢谢各位了先!
      

  3.   

    不用谢。
    既然你提到有显示不出来的字符,那么建议你使用2进制的方式接受,而不要使用文本方式,详细的设置方式可以查MSDN中关于MsComm控件的帮助。
    提供给你一段代码,这是我以前写的一个类,主要是接受数据,然后获得真正的数据内容用的。这个类当时是用在Winsock通信上,这么长的代码是因为要考虑传输过程丢包等因素,对于你的需求应该没有这么复杂,但看一看没有坏处。
    主要的函数是addData函数,通信端口每次获得到数据都调用这个函数,由这个函数去判断一次通信是什么时候开始、什么时候结束。其中,有些约定是,除了通信协议以外,我在处理的时候,如果一次接受了两个完整的包,我会把第一包当作是上次滞后数据丢掉。
    没有更合适的串口通信程序了,不过我认为通信过程,因为MSComm、Winsock等控件都封装好了,所以没什么可想的,倒是如何保证传输的数据是正确的,相对之下比较重要。程序里有些注解,但因为是我自己看着用的,而且我英文并不好,所以你就自己慢慢琢磨吧。补充一句,Copy到VB中看起来容易些。
    Shit~~~
    太长了。
      

  4.   

    Option ExplicitPrivate Const USER_END_NOT_FOUND = -1
    Private Const USER_END_OUT_OF_RANGE = -2Private Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)Dim bBuffer() As ByteDim mvarDataCount As Long
      

  5.   

    Public Property Get DataCount() As Long
        DataCount = mvarDataCount
    End PropertyPublic Function AddData(bData() As Byte, bResult() As Byte) As Byte
        On Error Resume Next
        
        Dim intDataLength As Long, intLength As Long
        Dim intPackDataLength As Long
        Dim bTemp() As Byte, bTemp2() As Byte
        Dim blnPackHeaderFound As Boolean
        Dim blnContinue As Boolean
        Dim bCmd As Byte
        
        'Clear result first
        bCmd = 0
        Erase bResult
        
        'Begin process
        Do
            blnContinue = False
            
            'Get length of new data
            intDataLength = -1
            intDataLength = UBound(bData)
            
            'No new data then quit process, and function
            'will return the result by last process if there it is.
            If intDataLength <= 0 Then
                AddData = bCmd
                Exit Function
            End If
            
            'Is there any data in buffer before?
            If mvarDataCount = -1 Then
                'No data in buffer
                If intDataLength <= 10 Then
                    'Just append new data to end of buffer when
                    'new data not enough, and then quit process
                    AddData = bCmd
                    ReDim bBuffer(intDataLength)
                    CopyMem bBuffer(0), bData(0), intDataLength + 1
                    Exit Function
                Else
                    'When data's length is enough, copy them to
                    'Tempory variable bTemp2, get ready for next step.
                    ReDim bTemp2(intDataLength)
                    CopyMem bTemp2(0), bData(0), intDataLength + 1
                End If
            Else
                'When there has data in buffer before, append new data
                'to buffer, and then copy buffer to tempory variable bTemp2
                'and clear the buffer, we don't need buffer now, all operate will
                'process with bTemp2 from now.
                ReDim Preserve bTemp2(mvarDataCount + intDataLength + 1)
                CopyMem bTemp2(0), bBuffer(0), mvarDataCount + 1
                CopyMem bTemp2(mvarDataCount + 1), bData(0), intDataLength + 1
                ClearBuffer
            End If
            
            'Get the package from header if there it is, and put it to
            'tempory variable bTemp
            intLength = getFromPackHeader(bTemp2, bTemp)
            
            blnPackHeaderFound = False
            If intLength >= 0 Then
                blnPackHeaderFound = True
            Else
                'No PHS found,let's see whether there is
                'the first byte of PHS in Data
                intLength = Abs(intLength) - 1
                
                'Clear buffer at first.
                ClearBuffer
                
                If intLength <> 0 Then
                    'if the first byte of PHS found,put the remnants
                    'of data into buffer
                    ReDim bBuffer(intLength)
                    CopyMem bBuffer(0), bTemp(0), intLength + 1
                End If
            End If
            
            If blnPackHeaderFound Then
                'Identify the PES and get the content of package
                'if PES has found.
                intPackDataLength = identifyPackEnd(bTemp)
                
                Select Case intPackDataLength
                Case USER_END_NOT_FOUND:
                    'PHS has found,but PES(Package Ended Signal) not found,
                    'for this case, it means that maybe data was destroyed
                    'by accient, so we remove the first byte from DATA, and
                    'try again(maybe another PHS will found in Data).
                    
                    ReDim bData(intLength - 1)
                    CopyMem bData(0), bTemp(1), intLength
                    blnContinue = True
                Case USER_END_OUT_OF_RANGE:
                    'PHS has found,but PES was not recieved yet, we should
                    'put DATA into buffer, and wait for next data.
                    
                    'Clear buffer at first
                    ClearBuffer
                    'Resize buffer and copy data to buffer
                    ReDim bBuffer(intLength)
                    CopyMem bBuffer(0), bTemp(0), intLength + 1
                    'Set the length of buffer, next time , we must append
                    'data to the buffer.
                    mvarDataCount = intLength
                    'Disable the contiueable signal, we needn't go on
                    'process at this time,wait for data and go on.
                    blnContinue = False
                Case Else:
                    'Every thing has done correctlly, set the content of package
                    'to the RESULT array.
                    'But, we can't stop process yet,cause we don't know whether
                    'there has useful data in buffer yet, so we must set correct
                    'command and result first, and then try to get next result
                    'again, if there is not another result, function will return
                    'this result, and if not, try to get next result.
                    
                    'get the command of this package
                    bCmd = bTemp(6)
                    
                    'get package content
                    ReDim bResult(intPackDataLength - 1)
                    CopyMem bResult(0), bTemp(11), intPackDataLength
                    
                    If intPackDataLength + 15 > intLength + 1 Then
                        'if there is still some data in buffer, try to
                        'process it again.
                        ReDim bData(intLength - intPackDataLength - 15)
                        CopyMem bData(0), bTemp(intPackDataLength + 14), intPackDataLength + 15
                        blnContinue = True
                    Else
                        'No more data, clear buffer and return the result.
                        ClearBuffer
                    End If
                End Select
            End If
        Loop While blnContinue
        
        AddData = bCmd
    End FunctionPrivate Function identifyPackEnd(bSou() As Byte) As Long
        Dim intPackLength As Long
        Dim intDataLength As Long
        
        intDataLength = UBound(bSou)
        intPackLength = getPackLength(bSou)
        
        If intPackLength + 15 <= intDataLength + 1 Then
            If bSou(11 + intPackLength) = &H49 And bSou(11 + intPackLength + 1) = &H55 And bSou(11 + intPackLength + 2) = &HAA And bSou(11 + intPackLength + 3) = &HDB Then
                identifyPackEnd = intPackLength
            Else
                identifyPackEnd = USER_END_NOT_FOUND
            End If
        Else
            identifyPackEnd = USER_END_OUT_OF_RANGE
        End If
    End FunctionPrivate Function getPackLength(bSou() As Byte) As Long
        getPackLength = CLng(bSou(10)) + CLng(bSou(9)) * &H100& + CLng(bSou(8)) * &H10000 + CLng(bSou(7)) * &H1000000
        Debug.Print getPackLength
    End Function
      

  6.   

    感动啊感动!一定给分!
    只是我愚笨无比,看不懂。先学习一下先。我还有的一个问题就是获得后如何存储到access 的数据库中呢?
      

  7.   

    还差一小段程序,给你的留言里我写函数的定义,没有具体的内容,shit CSDN!不允许连续3次回帖,实际上在判断数据包头的地方有一点小技巧,在数据量大的时候对效率的影响很大,不过对于你需求倒是用处不大,简单说明一下,比如我们定义每包数据的开始是AA、BB、CC、DD四个16进制数,那么我们判断的时候,一般写法是:
    for....
     if b(i)=AA and b(i+1)=BB and b(i+2)=CC and b(i+3)=DD then Found!
    next
    但是在数据量大的时候,这种判断非常耗时,所以,当时我采取将这个条件语句分开的写法:
    for ...
     if b(i)=AA then
      if b(i+1)=BB then
       if b(i+3)=CC then
        if b(i+4)=DD then
         Found!
        endif
       end if
      endif
     endif
    next
    实测表名,第二种写法,效率提升很多。有没有别的更好的办法?我当时时间紧,没有时间去查API,不知道有没有API能够直接从一段内存区域中查找一些值的办法,估计应该会有的,大家可以帮忙顶。
      

  8.   

    至于你所说的转存为Access,自己查一下MSDN中关于ADO、DAO方面的帮助,非常简单的,比如ADO基本的操作顺序是:
    1.工程的应用中加入ADO库(废话)
    2.创建Connection
    3.创建Recordset,并打开相应的表
    4.调用Recordset的AddNew方法
    5.给Recordset的Field(n)赋值
    6.调Recordset的Update或者UpdateBatch方法
    自己去多查查吧,真的很容易懂的。
      

  9.   

    平日工作很忙,回到家里面有精力的话就做一段。买了些书,不断地摸索和上机,代码也是从几本书上来摘录的,说来很惭愧啊!总觉得自己什么地方学得不好,但是总是说不上来,只有多努力看书了。呵呵。谢谢你,AresChen。