vb 字节数组的问题
本帖最后由 bcrun 于 2011-12-23 15:02:54 编辑 对于串口通信,你的判断它的起始和结束才对,你的问题很可能在没有判断起始符号我看了下你的接收代码,认为有些问题。
首先,你只是简单的接收,而没有判断是否接收完毕一条数据,需要修改你的串口通信程序,小修改而已。看看这个:http://download.csdn.net/detail/veron_04/1262066
再次,给你一个建议,你最好仔细的研究一下通信协议,因为通信协议是串口通信的规约,搞懂了它就等于搞懂了串口通信数据的含义,那么分析数据也就是很容易的事情了。
要不你把通信协议发上来,让大家帮你看看。 嘿嘿 你是我的贵人啊 又是你
我的通信协议一个例子:
例: 连续夺取多个寄存器
主站请求:
0A 03 00 00 00 05 84 B2
注:十进制地址10为十六进制0A
0X03为读寄存器功能代码
00 00为读首寄存器首地址
00 05 为读寄存器的个数
84 B2 为CRC16(低位在前高位在后)
从站响应:
0A 03 0A 2E 7A 2E 7B 2E 7A 2E 7C 2E 7A 86 64
注:十进制地址10为十六进制0A
0X03为读寄存器功能代码
02 为读取的字节数 --------->这个我也没看懂,哪有02
2E 7A 为读取首寄存器的数据,转换为十进制11898,万位是数据的正负:1代表正,0代表负,11898为要读得数据即:正189.8
以下类似。
86 64 为CRC16(低位在前高位在后)-------->这个不懂。不知道咋校验。
本通讯采用标准Modbus协议,所有传输模式为RTU。 用RS-485通信协议
定义如下: 从站地址 请求代码 数据 CRC16
从站地址:消息中的地址包含两个字符8bit(RTU),从站地址范围1--247.主设备通过将要联络的从设备的地址放入消息中的地址域来选通讯设备。当从设备发回消息时,它把自己的地址放入回应的地址域中,以便主设备知道是哪个设备做出回应。
数据:以二进制代码传输
CRC16:循环冗余错误校验
当间隔时间长于或等于3.5个字符时,即作为检测到帧结束。
通讯口设置
1异步串行通讯接口 :RS-485
波特率:9600bps
2 字节数据格式
一位起始位
八位数据位
一位偶校验位
一位停止位
3 仪表通讯帧格式
从站编号:本机仪表地址必须在1-247之间,且同一总线上仪表地址不可重复
功能代码:0X03
我的理解:
0A 03 0A 2E 7A 2E 7B 2E 7A 2E 7C 2E 7A 86 64
0A:是下位机地址
03:功能码
0A:返回的字节数(2E 7A 2E 7B 2E 7A 2E 7C 2E 7A 正好10个字节),每相邻两个字节组成一个参数
86:CRC16高字节
64:CRC16低字节
你的问题的关键在于CRC16的算法
这是CRC16的测试程序,计算结果正确
本帖最后由 bcrun 于 2011-12-23 15:10:19 编辑 我只是给你写了一个校验的例子
Option Explicit
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
'函数功能:CRC校验和计算
'参数说明:bytData:欲要计算教研和的字节型数组
'返 回 值:返回一个16进制形式的字符串,低位在前,高位在后
'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Private Function funCRC16(bytData() As Byte) As String
Dim bytCheck_H As Byte 'CRC寄存器高位
Dim bytCheck_L As Byte 'CRC寄存器低位
Dim bytCode_H As Byte '多项式高位
Dim bytCode_L As Byte '多项式低位
Dim bytH As Byte
Dim bytL As Byte
Dim intP As Integer
Dim intT As Integer
On Error GoTo errSub
funCRC16 = "0000"
bytCheck_H = &HFF
bytCheck_L = &HFF
bytCode_L = 1
bytCode_H = &HA0
For intP = LBound(bytData) To UBound(bytData)
bytCheck_L = bytData(intP) Xor bytCheck_L
For intT = 0 To 7
bytH = bytCheck_H
bytL = bytCheck_L
bytCheck_H = bytCheck_H \ 2
bytCheck_L = bytCheck_L \ 2
If ((bytH And &H1) = &H1) Then
bytCheck_L = bytCheck_L Or &H80
End If
If (bytL And &H1) = &H1 Then
bytCheck_H = bytCheck_H Xor bytCode_H
bytCheck_L = bytCheck_L Xor bytCode_L
End If
Next intT
Next intP
funCRC16 = Right("00" & Hex$(bytCheck_L), 2) & Right("00" & Hex$(bytCheck_H), 2)
Exit Function
errSub:
Debug.Print Err.Description
End Function
Private Sub Form_Load()
Dim bytA(0 To 12) As Byte
bytA(0) = &HA
bytA(1) = &H3
bytA(2) = &HA
bytA(3) = &H2E
bytA(4) = &H7A
bytA(5) = &H2E
bytA(6) = &H7B
bytA(7) = &H2E
bytA(8) = &H7A
bytA(9) = &H2E
bytA(10) = &H7C
bytA(11) = &H2E
bytA(12) = &H7A
Debug.Print funCRC16(bytA)
End Sub
funCRC16这个函数是合适你用的
你需要修改你的通信代码,加入CRC16计算方法 本帖最后由 bcrun 于 2011-12-23 15:08:41 编辑 唉,兄弟,。。。。 兄弟,你要帮我呀。我是真不会了。。看也看不懂。 留下你的邮箱 shiling1987@sina.cn 本帖最后由 bcrun 于 2011-12-23 15:09:30 编辑 不要用OnComm处理,请仔细看看我给你的例子 不要用定长的数组来接收数据,变长的串光用一行varP = MSComm1.Input不够的
大致的接收可以像下面这样,不过这个函数可能实际运行的时候还需要修正.
Public Function GetData(Comm As MSComm, Optional ByVal OverTime As Integer = 100) As Byte()
Dim BytesReceived As Long, T As Single
If Comm.PortOpen = False Then Exit Function
BytesReceived = 0
T = Timer
Do
If BytesReceived = Comm.InBufferSize Then Exit Do
If Comm.PortOpen = False Then Exit Function
BytesReceived = Comm.InBufferSize
Loop Until Abs(1000 * (Timer - T)) > OverTime
If BytesReceived > 0 Then GetData= Comm.Input
End Function
补充:VB , 基础类