给我点MSCOMM控件使用后的数据处理后的解决思路,高分!

Jackahuang 2003-10-19 11:50:26
各位老鸟,我用的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四个结果,如何实现用个模块实现接收后获得有效数据,然后分别存储入对应的数据库中?

不知道我的问题和我的想法说清楚没有?能否给我讲一下思路或者如何实现目标的其它方法?谢谢。如果有参考的源代码更好。高分相送!

...全文
48 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
AresChen 2003-10-22
  • 打赏
  • 举报
回复
我邮件是Ares.China@263.net,QQ:395356,有机会大家多交流吧。
Jackahuang 2003-10-21
  • 打赏
  • 举报
回复
平日工作很忙,回到家里面有精力的话就做一段。买了些书,不断地摸索和上机,代码也是从几本书上来摘录的,说来很惭愧啊!总觉得自己什么地方学得不好,但是总是说不上来,只有多努力看书了。呵呵。谢谢你,AresChen。
Jackahuang 2003-10-21
  • 打赏
  • 举报
回复
老大,交个朋友吧!我是学医的,本行还将就。我的邮箱是hth18@sina.com,给我封邮件,好吗?
谢谢你写了这么多!
AresChen 2003-10-21
  • 打赏
  • 举报
回复
至于你所说的转存为Access,自己查一下MSDN中关于ADO、DAO方面的帮助,非常简单的,比如ADO基本的操作顺序是:
1.工程的应用中加入ADO库(废话)
2.创建Connection
3.创建Recordset,并打开相应的表
4.调用Recordset的AddNew方法
5.给Recordset的Field(n)赋值
6.调Recordset的Update或者UpdateBatch方法
自己去多查查吧,真的很容易懂的。
AresChen 2003-10-21
  • 打赏
  • 举报
回复
还差一小段程序,给你的留言里我写函数的定义,没有具体的内容,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能够直接从一段内存区域中查找一些值的办法,估计应该会有的,大家可以帮忙顶。
Jackahuang 2003-10-21
  • 打赏
  • 举报
回复
因为昨天值班今天才回家,所以回迟了些。楼上的抱歉啊!
Jackahuang 2003-10-21
  • 打赏
  • 举报
回复
感动啊感动!一定给分!
只是我愚笨无比,看不懂。先学习一下先。我还有的一个问题就是获得后如何存储到access 的数据库中呢?
AresChen 2003-10-20
  • 打赏
  • 举报
回复
Public Property Get DataCount() As Long
DataCount = mvarDataCount
End Property

Public 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 Function

Private 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 Function

Private 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
AresChen 2003-10-20
  • 打赏
  • 举报
回复
Option Explicit

Private Const USER_END_NOT_FOUND = -1
Private Const USER_END_OUT_OF_RANGE = -2

Private Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Dim bBuffer() As Byte

Dim mvarDataCount As Long

AresChen 2003-10-20
  • 打赏
  • 举报
回复
不用谢。
既然你提到有显示不出来的字符,那么建议你使用2进制的方式接受,而不要使用文本方式,详细的设置方式可以查MSDN中关于MsComm控件的帮助。
提供给你一段代码,这是我以前写的一个类,主要是接受数据,然后获得真正的数据内容用的。这个类当时是用在Winsock通信上,这么长的代码是因为要考虑传输过程丢包等因素,对于你的需求应该没有这么复杂,但看一看没有坏处。
主要的函数是addData函数,通信端口每次获得到数据都调用这个函数,由这个函数去判断一次通信是什么时候开始、什么时候结束。其中,有些约定是,除了通信协议以外,我在处理的时候,如果一次接受了两个完整的包,我会把第一包当作是上次滞后数据丢掉。
没有更合适的串口通信程序了,不过我认为通信过程,因为MSComm、Winsock等控件都封装好了,所以没什么可想的,倒是如何保证传输的数据是正确的,相对之下比较重要。程序里有些注解,但因为是我自己看着用的,而且我英文并不好,所以你就自己慢慢琢磨吧。补充一句,Copy到VB中看起来容易些。
Shit~~~
太长了。
Jackahuang 2003-10-20
  • 打赏
  • 举报
回复
楼上的各位老鸟,谢谢大家,特别是 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>开头的如上的字符。我本来不想把所有的字符都放到缓冲里面的,但是模仿的源代码如此,幻想的是一条一条处理的,结果水平有限。各位老鸟能否帮忙给个类似的源代码参考一下,我的参考书实在没有类似的啊!谢谢各位了先!
rainstormmaster 2003-10-19
  • 打赏
  • 举报
回复
同意楼上
AresChen 2003-10-19
  • 打赏
  • 举报
回复
按照你所提供的数据来讲,你的通信方式属于一种不可靠的通信协议,主机发出一个请求,客户机不管3721就返回一堆数。
建议首先修改通信协议,比如加上包头、长度、校验码、包尾等信息。有了这些信息,以2进制的形式接受和发送数据,你很简单的就可以确定真正的数据是哪些,而这些数据的分隔符等都是确定的,所以你很容易就知道你想要的东西。
按照你现在的协议方式,只能在接受到数据之后,想全部放到一个缓冲当中,在缓冲里不管3721的将所有数据拼接成一个大字符串,然后查找“1P”的位置作为数据开始位置,依次类推去分析所有数据。
但你提供的程序中有很大的问题,就是串口通信是需要时间的(实际所有的数据通信都一样),也就是说,如果Chr(6)是要求客户机返回数据的命令的话,那么在你发出了命令之后,应该会等一会才接收到新的数据,所有数据显示的部分不应该在Timer事件中,而应该在MSComm控件的OnCom(好像是这么写吧,记不清了)事件里。关于MsCom控件如何激发OnCom事件,你可以查一下MSDN,里面有详细的解释。
subzero 2003-10-19
  • 打赏
  • 举报
回复
有了那台设备的通讯数据格式就一切好办

7,762

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧