紫外工控论坛

 找回密码
 立即注册

扫一扫,访问微社区

QQ登录

只需一步,快速开始

搜索
查看: 6466|回复: 14

[VB/VB.NET] VB.NET的modbus代码,可以编译DLL供其他文件调用

[复制链接]
冰糖 发表于 2011-4-21 23:47:23 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
看到有网友要,就找来了
  1. &#65279;''' <summary>
  2. ''' Modbus通讯的基础模块,以Modbus通讯协议运行
  3. ''' </summary>
  4. ''' <remarks></remarks>
  5. Public Class Modbus
  6. #Region "枚举"

  7.     ''' <summary>
  8.     ''' 串口的状态:正常、超时、出错
  9.     ''' </summary>
  10.     ''' <remarks></remarks>
  11.     Public Enum enCommStateType As Byte
  12.         ''' <summary>
  13.         ''' 正常
  14.         ''' </summary>
  15.         ''' <remarks></remarks>
  16.         Normal = 0

  17.         ''' <summary>
  18.         ''' 超时
  19.         ''' </summary>
  20.         ''' <remarks></remarks>
  21.         OutTime = 1

  22.         ''' <summary>
  23.         ''' 出错
  24.         ''' </summary>
  25.         ''' <remarks></remarks>
  26.         Failure = 2
  27.     End Enum

  28.     ''' <summary>
  29.     ''' 串口工作步骤
  30.     ''' </summary>
  31.     ''' <remarks></remarks>
  32.     Public Enum enWorkStateType
  33.         ''' <summary>
  34.         ''' 空闲
  35.         ''' </summary>
  36.         ''' <remarks></remarks>
  37.         Idle = 1

  38.         ''' <summary>
  39.         ''' 接收功能码
  40.         ''' </summary>
  41.         ''' <remarks></remarks>
  42.         ReceiveCommand = 2

  43.         ''' <summary>
  44.         ''' 接收命令信息
  45.         ''' </summary>
  46.         ''' <remarks></remarks>
  47.         ReceiceCommandInfo = 3

  48.         ''' <summary>
  49.         ''' 接收数据
  50.         ''' </summary>
  51.         ''' <remarks></remarks>
  52.         ReceiveData = 4

  53.         ''' <summary>
  54.         ''' 回应
  55.         ''' </summary>
  56.         ''' <remarks></remarks>
  57.         Answer = 5

  58.         ''' <summary>
  59.         ''' 发送命令
  60.         ''' </summary>
  61.         ''' <remarks></remarks>
  62.         SendCommand = 6

  63.         ''' <summary>
  64.         ''' 等待回应
  65.         ''' </summary>
  66.         ''' <remarks></remarks>
  67.         WaitAnswer = 7

  68.         ''' <summary>
  69.         ''' 得到回应数据字节数
  70.         ''' </summary>
  71.         ''' <remarks></remarks>
  72.         GetAnswerBytes = 9

  73.         ''' <summary>
  74.         ''' 回应的最后部分
  75.         ''' </summary>
  76.         ''' <remarks></remarks>
  77.         AnswerLast = 10

  78.         ''' <summary>
  79.         ''' 接收最后部分
  80.         ''' </summary>
  81.         ''' <remarks></remarks>
  82.         ReceiveCRC = 11
  83.     End Enum

  84.     ''' <summary>
  85.     ''' 通讯模块允许的通讯命令编码。
  86.     ''' </summary>
  87.     ''' <remarks></remarks>
  88.     Public Enum enCommandType As Byte
  89.         ''' <summary>
  90.         ''' 读线圈,每个字节表示8个线圈
  91.         ''' </summary>
  92.         ''' <remarks></remarks>
  93.         读线圈 = 1

  94.         ''' <summary>
  95.         ''' 读离散输入,只读的状态,每个字节表示8个状态
  96.         ''' </summary>
  97.         ''' <remarks></remarks>
  98.         读离散输入 = 2

  99.         ''' <summary>
  100.         ''' 强置单个线圈,通断标志:FF 00 ,置线圈ON;00 00 置线圈0FF。
  101.         ''' </summary>
  102.         ''' <remarks></remarks>
  103.         强置单线圈 = 5

  104.         ''' <summary>
  105.         ''' 强置多线圈,强置一串连续逻辑线圈的通断。
  106.         ''' </summary>
  107.         ''' <remarks></remarks>
  108.         强置多线圈 = 15

  109.         ''' <summary>
  110.         ''' 读取保持寄存器
  111.         ''' </summary>
  112.         ''' <remarks></remarks>
  113.         读取保持寄存器 = 3

  114.         ''' <summary>
  115.         '''读取输入寄存器
  116.         ''' </summary>
  117.         ''' <remarks></remarks>
  118.         读取输入寄存器 = 4

  119.         ''' <summary>
  120.         ''' 预置单寄存器,把具体二进值装入一个保持寄存器
  121.         ''' </summary>
  122.         ''' <remarks></remarks>
  123.         预置单寄存器 = 6

  124.         ''' <summary>
  125.         ''' 预置多寄存器,把具体的二进制值装入一串连续的保持寄存器。
  126.         ''' </summary>
  127.         ''' <remarks></remarks>
  128.         预置多寄存器 = 16

  129.         ''' <summary>
  130.         ''' 写多个保持寄存器,并返回多个保持寄存器的数据。(非Modbus标准命令)
  131.         ''' </summary>
  132.         ''' <remarks></remarks>
  133.         读写多寄存器 = 23
  134.     End Enum

  135.     ''' <summary>
  136.     ''' 节点工作模式:主模式、从模式
  137.     ''' </summary>
  138.     ''' <remarks></remarks>
  139.     Public Enum enMasterType
  140.         ''' <summary>
  141.         ''' 主站
  142.         ''' </summary>
  143.         ''' <remarks></remarks>
  144.         Master = 1

  145.         ''' <summary>
  146.         ''' 从站
  147.         ''' </summary>
  148.         ''' <remarks></remarks>
  149.         Slaver = 2
  150.     End Enum

  151. #End Region
复制代码
 楼主| 冰糖 发表于 2011-4-21 23:48:23 | 显示全部楼层
  1. #Region "属性和结构"

  2.     ''' <summary>
  3.     ''' Modbus通讯模块是以这个命令结构来传递命令和数据的。本命令结构包含了Modbus通讯所需要的各种数据。
  4.     ''' </summary>
  5.     ''' <remarks></remarks>
  6.     Public Structure stCommand
  7.         ''' <summary>
  8.         ''' 当模块为Modbus主站,向从站发送命令时,本参数记录需要接收命令的从站地址。
  9.         ''' 当模块为从站,本参数记录本站地址
  10.         ''' </summary>
  11.         ''' <remarks></remarks>
  12.         Public AddressOfReceive As Byte

  13.         ''' <summary>
  14.         ''' 命令代码
  15.         ''' </summary>
  16.         ''' <remarks></remarks>
  17.         Public Command As enCommandType

  18.         ''' <summary>
  19.         ''' 读数据偏置量
  20.         ''' </summary>
  21.         ''' <remarks></remarks>
  22.         Public ReadAddress As UInt16

  23.         ''' <summary>
  24.         ''' 读数据单位总数
  25.         ''' </summary>
  26.         ''' <remarks></remarks>
  27.         Public ReadCount As UInt16

  28.         ''' <summary>
  29.         ''' 写数据偏置量
  30.         ''' </summary>
  31.         ''' <remarks></remarks>
  32.         Public WriteAddress As UInt16

  33.         ''' <summary>
  34.         ''' 写数据单位总数
  35.         ''' </summary>
  36.         ''' <remarks></remarks>
  37.         Public WriteCount As UInt16

  38.         ''' <summary>
  39.         ''' 数据字节数
  40.         ''' </summary>
  41.         ''' <remarks></remarks>
  42.         Public DataLen As UInt16

  43.         ''' <summary>
  44.         ''' 数据数组
  45.         ''' </summary>
  46.         ''' <remarks></remarks>
  47.         Public Data() As Byte
  48.     End Structure

  49.     ''' <summary>
  50.     ''' 通讯状态
  51.     ''' </summary>
  52.     ''' <remarks></remarks>
  53.     Public Structure stState
  54.         ''' <summary>
  55.         ''' 通讯正常或故障状态
  56.         ''' </summary>
  57.         ''' <remarks></remarks>
  58.         Public PortState As enCommStateType

  59.         ''' <summary>
  60.         ''' 通讯时所处的过程阶段状态
  61.         ''' </summary>
  62.         ''' <remarks></remarks>
  63.         Public WorkState As enWorkStateType

  64.         ''' <summary>
  65.         ''' 通讯信息
  66.         ''' </summary>
  67.         ''' <remarks></remarks>
  68.         Public Msg As String
  69.     End Structure

  70.     ''' <summary>
  71.     ''' 读取、设置串口波特率
  72.     ''' </summary>
  73.     ''' <value>[in]波特率只能为 9600、19200、38400 。</value>
  74.     ''' <returns>返回当前波特率</returns>
  75.     ''' <remarks>波特率只能为 9600、19200、38400。</remarks>
  76.     Public Property m_iBaudRate() As Long
  77.         Get
  78.             Return SerialPort1.BaudRate
  79.         End Get
  80.         Set(ByVal Value As Long)
  81.             Select Case Value
  82.                 Case 9600, 19200, 38400
  83.                     SerialPort1.BaudRate = Value
  84.                 Case Else
  85.                     SerialPort1.BaudRate = 9600
  86.             End Select
  87.         End Set
  88.     End Property

  89.     ''' <summary>
  90.     ''' 设置、读取串口号
  91.     ''' </summary>
  92.     ''' <value></value>
  93.     ''' <returns></returns>
  94.     ''' <remarks>可通过GetSerialPortNames获取所有的串口名称</remarks>
  95.     Public Property m_strPortName() As String
  96.         Get
  97.             Return SerialPort1.PortName
  98.         End Get
  99.         Set(ByVal Value As String)
  100.             Try
  101.                 SerialPort1.Close()
  102.             Catch ex As Exception

  103.             End Try

  104.             Try
  105.                 SerialPort1.PortName = Value
  106.                 SerialPort1.Open()      '需要保持串口一直打开
  107.             Catch ex As Exception
  108.                 MsgBox(ex.ToString)
  109.             End Try
  110.         End Set
  111.     End Property

  112.     Private enModbusMaster As enMasterType
  113.     ''' <summary>
  114.     ''' 设置、返回串口通讯PC机所扮演的主从角色
  115.     ''' </summary>
  116.     ''' <value></value>
  117.     ''' <returns></returns>
  118.     ''' <remarks>
  119.     ''' 角色为主,则需要承担通讯的发起者的角色,接收数据不需要回应。
  120.     ''' 角色为从,则没有主动发出信息的权利,只有当通讯的主节点要求时才能发送数据,对于主节点的命令需要回复
  121.     ''' </remarks>
  122.     Public Property m_enModbusMaster() As enMasterType
  123.         Get
  124.             Return enModbusMaster
  125.         End Get
  126.         Set(ByVal Value As enMasterType)
  127.             Try
  128.                 enModbusMaster = Value
  129.                 m_State.WorkState = enWorkStateType.Idle
  130.                 m_State.PortState = enCommStateType.Normal
  131.                 m_State.Msg = ""
  132.             Catch ex As Exception
  133.                 MsgBox(ex.ToString)
  134.             End Try
  135.         End Set
  136.     End Property

  137.     ''' <summary>
  138.     ''' Modbus通讯状态
  139.     ''' </summary>
  140.     ''' <value></value>
  141.     ''' <returns></returns>
  142.     ''' <remarks></remarks>
  143.     Public ReadOnly Property m_ModbusState() As stState
  144.         Get
  145.             Return m_State
  146.         End Get
  147.     End Property
  148. #End Region

  149. #Region "CRC 字节值表"
  150.     ' CRC 高位字节值表
  151.     Private auchCRCHi() As Byte = New Byte() { _
  152.                                                 &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, _
  153.                                                 &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, _
  154.                                                 &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, _
  155.                                                 &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, _
  156.                                                 &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, _
  157.                                                 &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, _
  158.                                                 &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, _
  159.                                                 &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, _
  160.                                                 &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, _
  161.                                                 &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, _
  162.                                                 &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, _
  163.                                                 &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, _
  164.                                                 &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, _
  165.                                                 &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, _
  166.                                                 &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, _
  167.                                                 &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, _
  168.                                                 &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, _
  169.                                                 &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, _
  170.                                                 &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, _
  171.                                                 &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, _
  172.                                                 &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, _
  173.                                                 &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, _
  174.                                                 &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, _
  175.                                                 &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, _
  176.                                                 &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, _
  177.                                                 &H80, &H41, &H0, &HC1, &H81, &H40}

  178.     ' CRC低位字节值表
  179.     Private auchCRCLo() As Byte = New Byte() { _
  180.                                                 &H0, &HC0, &HC1, &H1, &HC3, &H3, &H2, &HC2, &HC6, &H6, _
  181.                                                 &H7, &HC7, &H5, &HC5, &HC4, &H4, &HCC, &HC, &HD, &HCD, _
  182.                                                 &HF, &HCF, &HCE, &HE, &HA, &HCA, &HCB, &HB, &HC9, &H9, _
  183.                                                 &H8, &HC8, &HD8, &H18, &H19, &HD9, &H1B, &HDB, &HDA, &H1A, _
  184.                                                 &H1E, &HDE, &HDF, &H1F, &HDD, &H1D, &H1C, &HDC, &H14, &HD4, _
  185.                                                 &HD5, &H15, &HD7, &H17, &H16, &HD6, &HD2, &H12, &H13, &HD3, _
  186.                                                 &H11, &HD1, &HD0, &H10, &HF0, &H30, &H31, &HF1, &H33, &HF3, _
  187.                                                 &HF2, &H32, &H36, &HF6, &HF7, &H37, &HF5, &H35, &H34, &HF4, _
  188.                                                 &H3C, &HFC, &HFD, &H3D, &HFF, &H3F, &H3E, &HFE, &HFA, &H3A, _
  189.                                                 &H3B, &HFB, &H39, &HF9, &HF8, &H38, &H28, &HE8, &HE9, &H29, _
  190.                                                 &HEB, &H2B, &H2A, &HEA, &HEE, &H2E, &H2F, &HEF, &H2D, &HED, _
  191.                                                 &HEC, &H2C, &HE4, &H24, &H25, &HE5, &H27, &HE7, &HE6, &H26, _
  192.                                                 &H22, &HE2, &HE3, &H23, &HE1, &H21, &H20, &HE0, &HA0, &H60, _
  193.                                                 &H61, &HA1, &H63, &HA3, &HA2, &H62, &H66, &HA6, &HA7, &H67, _
  194.                                                 &HA5, &H65, &H64, &HA4, &H6C, &HAC, &HAD, &H6D, &HAF, &H6F, _
  195.                                                 &H6E, &HAE, &HAA, &H6A, &H6B, &HAB, &H69, &HA9, &HA8, &H68, _
  196.                                                 &H78, &HB8, &HB9, &H79, &HBB, &H7B, &H7A, &HBA, &HBE, &H7E, _
  197.                                                 &H7F, &HBF, &H7D, &HBD, &HBC, &H7C, &HB4, &H74, &H75, &HB5, _
  198.                                                 &H77, &HB7, &HB6, &H76, &H72, &HB2, &HB3, &H73, &HB1, &H71, _
  199.                                                 &H70, &HB0, &H50, &H90, &H91, &H51, &H93, &H53, &H52, &H92, _
  200.                                                 &H96, &H56, &H57, &H97, &H55, &H95, &H94, &H54, &H9C, &H5C, _
  201.                                                 &H5D, &H9D, &H5F, &H9F, &H9E, &H5E, &H5A, &H9A, &H9B, &H5B, _
  202.                                                 &H99, &H59, &H58, &H98, &H88, &H48, &H49, &H89, &H4B, &H8B, _
  203.                                                 &H8A, &H4A, &H4E, &H8E, &H8F, &H4F, &H8D, &H4D, &H4C, &H8C, _
  204.                                                 &H44, &H84, &H85, &H45, &H87, &H47, &H46, &H86, &H82, &H42, _
  205.                                                 &H43, &H83, &H41, &H81, &H80, &H40}

  206. #End Region

  207.     '获得组件对象
  208.     Private TimerOp As New System.Timers.Timer
  209.     Private SerialPort1 As New System.IO.Ports.SerialPort

  210.     '命令结构
  211.     Private m_Cmd As New stCommand
  212.     Private m_State As New stState

  213.     '输入输出暂存
  214.     Private uchCRCHi As Byte = &HFF     ' 高CRC字节初始化
  215.     Private uchCRCLo As Byte = &HFF     '低CRC 字节初始化  

  216.     ''' <summary>
  217.     ''' 通讯结束时发出的消息
  218.     ''' </summary>
  219.     ''' <param name="stCmd">[in/out]包含通讯命令所有信息的命令结构</param>
  220.     ''' <remarks></remarks>
  221.     Public Event CommunicationOverEvent(ByVal stCmd As stCommand, ByVal stState As stState)

  222.     ''' <summary>
  223.     ''' 输入通讯节点地址, 对串口和时钟进行初始化
  224.     ''' </summary>
  225.     ''' <param name="BusAddress">[in]节点地址</param>
  226.     ''' <param name="MasterOrSlaver">[in]节点主从设置</param>
  227.     ''' <param name="OutTimeSetting">[in]通讯超时设置</param>
  228.     ''' <param name="PortName">[in]模块使用的串口名称</param>
  229.     ''' <remarks></remarks>
  230.     Public Sub New(ByVal BusAddress As Byte, ByVal MasterOrSlaver As enMasterType, ByVal PortName As String, ByVal OutTimeSetting As Int16)

  231.         '设置时钟超时参数
  232.         TimerInit(OutTimeSetting)

  233.         '设置Modbus主从模式
  234.         enModbusMaster = MasterOrSlaver

  235.         '设置Modbus节点地址
  236.         If enModbusMaster = enMasterType.Slaver Then
  237.             m_Cmd.AddressOfReceive = BusAddress
  238.         End If

  239.         '初始化Modbus工作状态
  240.         m_State.WorkState = enWorkStateType.Idle
  241.         m_State.PortState = enCommStateType.Normal

  242.         '串口初始化
  243.         SerialPortInit(PortName)
  244.     End Sub


  245. #Region "串口"

  246.     ''' <summary>
  247.     ''' 初始化串口8位数据位2位停止位,无校验,波特率38400,写缓存4096。设置了串口的事件处理函数。
  248.     ''' </summary>
  249.     ''' <remarks></remarks>
  250.     Private Sub SerialPortInit(ByVal PortName As String)
  251.         SerialPort1.StopBits = IO.Ports.StopBits.One
  252.         SerialPort1.Parity = IO.Ports.Parity.Odd
  253.         SerialPort1.BaudRate = 38400
  254.         SerialPort1.DataBits = 8
  255.         SerialPort1.ReceivedBytesThreshold = 1
  256.         SerialPort1.WriteBufferSize = 4096

  257.         AddHandler SerialPort1.DataReceived, AddressOf OnSerialPortReceivedEvent       '指定事件触发函数
  258.         AddHandler SerialPort1.ErrorReceived, AddressOf OnSerialErrorReceivedEvent

  259.         m_strPortName = PortName
  260.     End Sub

  261.     ''' <summary>
  262.     ''' 返回计算机所有串口名称
  263.     ''' </summary>
  264.     ''' <param name="PortNames">[out]返回计算机所有串口名称数组</param>
  265.     ''' <remarks>当需要设置串口时,可能首先调用本函数获取所有的串口名称。</remarks>
  266.     Public Shared Sub GetSerialPortNames(ByRef PortNames As ArrayList)
  267.         PortNames = New ArrayList
  268.         For Each sp As String In My.Computer.Ports.SerialPortNames
  269.             PortNames.Add(sp)
  270.         Next
  271.     End Sub

  272.     ''' <summary>
  273.     ''' 关闭串口连接
  274.     ''' </summary>
  275.     ''' <remarks></remarks>
  276.     Public Function ClosePort()
  277.         Dim str As String = ""
  278.         Try
  279.             SerialPort1.Close()
  280.         Catch ex As Exception
  281.             str = ex.ToString
  282.         End Try
  283.         Return str
  284.     End Function
复制代码
 楼主| 冰糖 发表于 2011-4-21 23:49:01 | 显示全部楼层

  1.     ''' <summary>
  2.     ''' 打开串口连接
  3.     ''' </summary>
  4.     ''' <remarks></remarks>
  5.     Public Function OpenPort()
  6.         Dim str As String = ""
  7.         Try
  8.             SerialPort1.Open()
  9.         Catch ex As Exception
  10.             str = ex.ToString
  11.         End Try
  12.         Return str
  13.     End Function


  14.     ''' <summary>
  15.     ''' 对将要输出的命令按照Modbus的格式进行编码,并加入CRC校验
  16.     ''' </summary>
  17.     ''' <param name="buffer">[out]按照Modbus协议打包好的数据包</param>
  18.     ''' <remarks></remarks>
  19.     Private Sub CommandDecodeOfMaster(ByRef buffer() As Byte)
  20.         Dim i As UInt16

  21.         ReDim buffer(1)
  22.         buffer(0) = m_Cmd.AddressOfReceive
  23.         buffer(1) = m_Cmd.Command

  24.         Select Case m_Cmd.Command
  25.             Case enCommandType.读离散输入, _
  26.                  enCommandType.读线圈, _
  27.                  enCommandType.读取输入寄存器, _
  28.                  enCommandType.读取保持寄存器

  29.                 ReDim Preserve buffer(2 + 4 - 1)

  30.                 '要读取数据的偏置量
  31.                 buffer(2) = (m_Cmd.ReadAddress And &HFF00&) / &H100&
  32.                 buffer(3) = m_Cmd.ReadAddress And &HFF&

  33.                 '要读取数据的单位数
  34.                 buffer(4) = (m_Cmd.ReadCount And &HFF00&) / &H100&
  35.                 buffer(5) = m_Cmd.ReadCount And &HFF&

  36.             Case enCommandType.强置单线圈, _
  37.                  enCommandType.预置单寄存器

  38.                 ReDim Preserve buffer(2 + 4 - 1)

  39.                 '要写的单个数据的偏置量
  40.                 buffer(2) = (m_Cmd.WriteAddress And &HFF00&) / &H100&
  41.                 buffer(3) = m_Cmd.WriteAddress And &HFF&

  42.                 m_Cmd.WriteCount = 1
  43.                 m_Cmd.DataLen = 2

  44.                 ReDim Preserve m_Cmd.Data(m_Cmd.DataLen - 1)
  45.                 buffer(4) = m_Cmd.Data(0)
  46.                 buffer(5) = m_Cmd.Data(1)

  47.             Case enCommandType.强置多线圈, _
  48.                  enCommandType.预置多寄存器

  49.                 ReDim Preserve buffer(2 + 5 + m_Cmd.DataLen - 1)

  50.                 '要写的数据的偏置量
  51.                 buffer(2) = (m_Cmd.WriteAddress And &HFF00&) / &H100&
  52.                 buffer(3) = m_Cmd.WriteAddress And &HFF&

  53.                 '要写的数据的单位数
  54.                 buffer(4) = (m_Cmd.WriteCount And &HFF00&) / &H100&
  55.                 buffer(5) = m_Cmd.WriteCount And &HFF&

  56.                 '要写入数据的字节数
  57.                 buffer(6) = m_Cmd.DataLen

  58.                 '要写入的数据
  59.                 ReDim Preserve m_Cmd.Data(m_Cmd.DataLen - 1)
  60.                 For i = 0 To m_Cmd.DataLen - 1 Step 1
  61.                     buffer(7 + i) = m_Cmd.Data(i)
  62.                 Next i

  63.             Case enCommandType.读写多寄存器

  64.                 ReDim Preserve buffer(2 + 9 + m_Cmd.DataLen - 1)

  65.                 '要读取数据的偏置量
  66.                 buffer(2) = (m_Cmd.ReadAddress And &HFF00&) / &H100&
  67.                 buffer(3) = m_Cmd.ReadAddress And &HFF&

  68.                 '要读取数据的单位数
  69.                 buffer(4) = (m_Cmd.ReadCount And &HFF00&) / &H100&
  70.                 buffer(5) = m_Cmd.ReadCount And &HFF&

  71.                 '要写的数据的偏置量
  72.                 buffer(6) = (m_Cmd.WriteAddress And &HFF00&) / &H100&
  73.                 buffer(7) = m_Cmd.WriteAddress And &HFF&

  74.                 '要写的数据的单位数
  75.                 buffer(8) = (m_Cmd.WriteCount And &HFF00&) / &H100&
  76.                 buffer(9) = m_Cmd.WriteCount And &HFF&

  77.                 '要写入数据的字节数
  78.                 buffer(10) = m_Cmd.DataLen

  79.                 '要写入的数据
  80.                 ReDim Preserve m_Cmd.Data(m_Cmd.DataLen - 1)
  81.                 For i = 0 To m_Cmd.DataLen - 1 Step 1
  82.                     buffer(11 + i) = m_Cmd.Data(i)
  83.                 Next i
  84.         End Select

  85.         '加入CRC校验
  86.         loadCRC(buffer)
  87.     End Sub

  88.     ''' <summary>
  89.     ''' 向Modbus从站发送命令。
  90.     ''' </summary>
  91.     ''' <param name="stCmd">需要发送的命令结构</param>
  92.     ''' <returns>成功返回空,异常返回错误信息。</returns>
  93.     ''' <remarks></remarks>
  94.     Public Function SendCommand(ByVal stCmd As stCommand) As String
  95.         Dim str As String = ""
  96.         Dim buffer() As Byte

  97.         Try
  98.             If m_enModbusMaster = enMasterType.Slaver Then
  99.                 str = "本通讯节点为从站,不能主动发出命令。如果确需发送命令和数据,请先将通讯节点的ModbusMaster属性设置为Master。"
  100.                 Return str
  101.             End If

  102.             '如果没有打开串口,则打开
  103.             If SerialPort1.IsOpen = False Then
  104.                 SerialPort1.Open()
  105.             End If

  106.             TimerOp.Stop()

  107.             '是主站可以通讯

  108.             '清空串口发送和接收缓存
  109.             SerialPort1.DiscardOutBuffer()
  110.             SerialPort1.DiscardInBuffer()
  111.             SerialPort1.ReceivedBytesThreshold = 2

  112.             '保存命令
  113.             m_Cmd = stCmd

  114.             '加入从站地址和功能码
  115.             ReDim buffer(0)

  116.             '对将要输出的命令按照Modbus的格式进行编码,并加入CRC校验
  117.             CommandDecodeOfMaster(buffer)

  118.             '通讯状态进入发送命令状态
  119.             m_State.WorkState = enWorkStateType.SendCommand

  120.             '发送数据
  121.             SerialPort1.Write(buffer, 0, buffer.Length)

  122.             '通讯状态进入发送命令状态
  123.             m_State.WorkState = enWorkStateType.WaitAnswer

  124.             '启动计时
  125.             TimerOp.Start()

  126.         Catch ex As Exception
  127.             m_State.PortState = enCommStateType.Failure
  128.             m_State.Msg = ex.ToString
  129.             str = m_State.Msg
  130.             CommunicationOver()
  131.         End Try

  132.         Return str
  133.     End Function

  134.     ''' <summary>
  135.     ''' 数据接收中断中的主站接收函数
  136.     ''' </summary>
  137.     ''' <remarks></remarks>
  138.     Private Sub ReceiveOfMaster()
  139.         Dim buffer() As Byte
  140.         Dim str As String = ""

  141.         ReDim buffer(0)

  142.         '读取通讯节点地址
  143.         ReadData(buffer)

  144.         Try
  145.             Select Case m_State.WorkState
  146.                 '空闲
  147.                 Case enWorkStateType.WaitAnswer
  148.                     WaitAnswerOfMaster(buffer)

  149.                 Case enWorkStateType.GetAnswerBytes
  150.                     '关闭时钟
  151.                     TimerOp.Stop()

  152.                     '计算CRC值
  153.                     MakeCRC(buffer, buffer.Length, uchCRCHi, uchCRCLo)

  154.                     m_Cmd.DataLen = buffer(0)

  155.                     '通讯状态进入接收回应剩余数据状态
  156.                     m_State.WorkState = enWorkStateType.AnswerLast
  157.                     m_State.Msg = "接收回应剩余数据。"
  158.                     SerialPort1.ReceivedBytesThreshold = m_Cmd.DataLen + 2

  159.                     '打开时钟
  160.                     TimerOp.Start()

  161.                 Case enWorkStateType.AnswerLast
  162.                     '关闭时钟
  163.                     TimerOp.Stop()

  164.                     '计算CRC值
  165.                     MakeCRC(buffer, buffer.Length - 2, uchCRCHi, uchCRCLo)

  166.                     '检查CRC校验,不通过
  167.                     If (uchCRCHi <> buffer(buffer.Length - 2)) Or (uchCRCLo <> buffer(buffer.Length - 1)) Then
  168.                         m_State.PortState = enCommStateType.Failure
  169.                         m_State.Msg = "CRC校验没有通过。"
  170.                     Else
  171.                         If m_Cmd.DataLen > 0 Then
  172.                             '保存数据
  173.                             ReDim m_Cmd.Data(m_Cmd.DataLen - 1)
  174.                             Array.Copy(buffer, m_Cmd.Data, m_Cmd.DataLen)
  175.                         End If

  176.                         m_State.WorkState = enWorkStateType.Idle
  177.                         m_State.Msg = "应答接收完成。"
  178.                     End If

  179.                     '发送通讯结束消息
  180.                     RaiseEvent CommunicationOverEvent(m_Cmd, m_State)

  181.                     '恢复初值
  182.                     m_State.WorkState = enWorkStateType.Idle
  183.                     m_State.PortState = enCommStateType.Normal
  184.                     m_State.Msg = ""
  185.                     SerialPort1.DiscardInBuffer()
  186.                     SerialPort1.ReceivedBytesThreshold = 1

  187.             End Select


  188.             If m_State.PortState <> enCommStateType.Normal Then
  189.                 'Modbus命令结束
  190.                 CommunicationOver()
  191.             End If

  192.         Catch ex As Exception
  193.             m_State.PortState = enCommStateType.Failure
  194.             m_State.Msg = ex.ToString

  195.             'Modbus命令结束
  196.             CommunicationOver()
  197.         End Try

  198.     End Sub

  199.     ''' <summary>
  200.     ''' 主站发送命令完毕后,等待从站回复的处理函数。
  201.     ''' </summary>
  202.     ''' <param name="buffer">[in]接收到的数据包。</param>
  203.     ''' <remarks></remarks>
  204.     Private Sub WaitAnswerOfMaster(ByVal buffer() As Byte)
  205.         Try
  206.             '核对地址
  207.             If (CheckAddress(buffer(0)) = "") And ((buffer(1) And &HFF&) = m_Cmd.Command) Then
  208.                 '关闭时钟
  209.                 TimerOp.Stop()

  210.                 uchCRCHi = &HFF     ' 高CRC字节初始化
  211.                 uchCRCLo = &HFF     '低CRC 字节初始化  

  212.                 '计算CRC值
  213.                 MakeCRC(buffer, buffer.Length, uchCRCHi, uchCRCLo)

  214.                 Select Case m_Cmd.Command
  215.                     Case enCommandType.读线圈, _
  216.                          enCommandType.读离散输入, _
  217.                          enCommandType.读取保持寄存器, _
  218.                          enCommandType.读取输入寄存器, _
  219.                          enCommandType.读写多寄存器

  220.                         '通讯状态进入接收回应数据字节数状态
  221.                         m_State.WorkState = enWorkStateType.GetAnswerBytes
  222.                         m_State.Msg = "接收回应数据字节数。"
  223.                         SerialPort1.ReceivedBytesThreshold = 1

  224.                     Case enCommandType.强置单线圈, _
  225.                          enCommandType.预置单寄存器, _
  226.                          enCommandType.强置多线圈, _
  227.                          enCommandType.预置多寄存器

  228.                         '通讯状态进入接收回应剩余数据状态
  229.                         m_State.WorkState = enWorkStateType.AnswerLast
  230.                         m_State.Msg = "接收回应剩余数据。"
  231.                         SerialPort1.ReceivedBytesThreshold = 6
  232.                 End Select

  233.                 '开始计时
  234.                 TimerOp.Start()
  235.             Else
  236.                 m_State.PortState = enCommStateType.Failure
  237.                 m_State.Msg = "回应的从站地址不正确或功能码不对。"
  238.             End If
  239.         Catch ex As Exception
  240.             m_State.PortState = enCommStateType.Failure
  241.             m_State.Msg = ex.ToString

  242.             'Modbus命令结束
  243.             CommunicationOver()
  244.         End Try
  245.     End Sub

  246.     ''' <summary>
  247.     ''' 通讯结束处理函数
  248.     ''' </summary>
  249.     ''' <remarks></remarks>
  250.     Public Sub CommunicationOver()
  251.         Try
  252.             TimerOp.Stop()

  253.             '发送通讯结束消息
  254.             RaiseEvent CommunicationOverEvent(m_Cmd, m_State)

  255.             '恢复初值
  256.             m_State.WorkState = enWorkStateType.Idle
  257.             m_State.PortState = enCommStateType.Normal
  258.             m_State.Msg = ""

  259.             SerialPort1.DiscardInBuffer()

  260.             SerialPort1.ReceivedBytesThreshold = 1
  261.         Catch ex As Exception

  262.         End Try
  263.     End Sub

  264.     ''' <summary>
  265.     ''' 读取串口缓存的数据
  266.     ''' </summary>
  267.     ''' <param name="buffer">[out]将读取出来的数据暂时放置到该数组中</param>
  268.     ''' <remarks></remarks>
  269.     Private Sub ReadData(ByRef buffer() As Byte)
  270.         Dim i As Int16

  271.         Try
  272.             '设置数据缓存
  273.             ReDim buffer(SerialPort1.ReceivedBytesThreshold - 1)

  274.             '由于SerialPort1数据缓存区的数据数量和read读取的数量可能会不一致,所以通过以下循环不断的执行读数据过程,保证数据被完整取出。
  275.             i = 0
  276.             Do
  277.                 i = i + SerialPort1.Read(buffer, i, SerialPort1.ReceivedBytesThreshold)
  278.                 If m_State.PortState <> enCommStateType.Normal Then
  279.                     m_State.Msg = m_State.PortState.ToString
  280.                     Exit Try
  281.                 End If
  282.             Loop Until i >= SerialPort1.ReceivedBytesThreshold

  283.             m_State.Msg = "成功得到数据。"
  284.         Catch ex As Exception
  285.             m_State.PortState = enCommStateType.Failure
  286.             m_State.Msg = ex.ToString
  287.         End Try
  288.     End Sub

  289.     ''' <summary>
  290.     ''' 核对通讯对象。
  291.     ''' </summary>
  292.     ''' <param name="address">[in]通讯接收节点地址</param>
  293.     ''' <returns>成功返回空,错误返回错误信息。</returns>
  294.     ''' <remarks></remarks>
  295.     Private Function CheckAddress(ByVal address As Int16) As String
  296.         Dim str As String = ""

  297.         If (m_Cmd.AddressOfReceive = address) Or (m_Cmd.AddressOfReceive = 0) Or (enModbusMaster = enMasterType.Master) Then
  298.             str = ""
  299.         Else
  300.             str = "本节点不是通讯接收节点。"
  301.         End If

  302.         Return str
  303.     End Function



  304.     ''' <summary>
  305.     ''' 计算回应数据的CRC校验值,并将该值加入到数据尾部
  306.     ''' </summary>
  307.     ''' <param name="Buffer">[in/out]需要加入校验的数据包</param>
  308.     ''' <remarks></remarks>
  309.     Public Sub loadCRC(ByRef Buffer() As Byte)
  310.         Dim CRCHi As Byte = &HFF     ' 高CRC字节初始化
  311.         Dim CRCLo As Byte = &HFF     ' 低CRC字节初始化  

  312.         '计算校验值
  313.         MakeCRC(Buffer, Buffer.Length, CRCHi, CRCLo)

  314.         '将校验值加入数据包尾部
  315.         ReDim Preserve Buffer(Buffer.Length + 1)
  316.         Buffer(Buffer.Length - 2) = CRCHi
  317.         Buffer(Buffer.Length - 1) = CRCLo
  318.     End Sub

  319.     ''' <summary>
  320.     '''  计算CRC
  321.     ''' </summary>
  322.     ''' <param name="buffer">[in]要计算的数据</param>
  323.     ''' <param name="CRCHi">[in/out]高CRC字节</param>
  324.     ''' <param name="CRCLo">[in/out]低CRC 字节</param>
  325.     ''' <remarks>如果使用本函数来计算全部数据,需要首先初始化uchCRCHi和uchCRCLo为0xFF。</remarks>
  326.     Private Sub MakeCRC(ByVal buffer() As Byte, ByVal length As UInt16, ByRef CRCHi As Byte, ByRef CRCLo As Byte)
  327.         Dim uIndex As Byte              ' CRC循环中的索引  
  328.         Dim DataIndex As UInt16 = 0     '消息索引
  329.         Dim usDataLen As UInt16         ' 消息中字节数  

  330.         usDataLen = length

  331.         '传输消息缓冲区  
  332.         Do
  333.             uIndex = CRCHi Xor buffer(DataIndex)  ' 计算CRC */
  334.             CRCHi = CRCLo Xor auchCRCHi(uIndex)
  335.             CRCLo = auchCRCLo(uIndex)

  336.             DataIndex = DataIndex + 1
  337.         Loop Until DataIndex >= usDataLen
  338.     End Sub

复制代码
 楼主| 冰糖 发表于 2011-4-21 23:49:23 | 显示全部楼层


  1.     ''' <summary>
  2.     ''' 从站回应处理
  3.     ''' </summary>
  4.     ''' <param name="data">[in]将要返回的数据</param>
  5.     ''' <remarks></remarks>
  6.     Public Function SendAnswer(ByVal data() As Byte) As String
  7.         Dim i As Int16
  8.         Dim buffer() As Byte
  9.         Dim str As String = ""

  10.         If (m_enModbusMaster = enMasterType.Master) Then
  11.             m_State.PortState = enCommStateType.Failure
  12.             m_State.Msg = "您是主站不能调用本函数,请使用SendCommand函数"
  13.             Return m_State.Msg
  14.         End If

  15.         If m_State.WorkState <> enWorkStateType.Answer Then
  16.             m_State.PortState = enCommStateType.Failure
  17.             m_State.Msg = "当前通讯状态不在应答状态"
  18.             Return m_State.Msg
  19.         End If

  20.         Try
  21.             ReDim buffer(0)

  22.             Select Case m_Cmd.Command
  23.                 Case enCommandType.读线圈, _
  24.                      enCommandType.读离散输入, _
  25.                      enCommandType.读取保持寄存器, _
  26.                      enCommandType.读取输入寄存器, _
  27.                      enCommandType.读写多寄存器

  28.                     '设置数据包长度
  29.                     ReDim buffer(3 + data.Length - 1)

  30.                     '写从站地址, 写功能码
  31.                     buffer(0) = m_Cmd.AddressOfReceive
  32.                     buffer(1) = m_Cmd.Command

  33.                     '写数据字节数
  34.                     buffer(2) = m_Cmd.DataLen

  35.                     '写有效数据
  36.                     For i = 0 To data.Length - 1 Step 1
  37.                         buffer(3 + i) = data(i)
  38.                     Next i

  39.                     '装入CRC校验值
  40.                     loadCRC(buffer)

  41.                 Case enCommandType.强置单线圈, _
  42.                      enCommandType.预置单寄存器

  43.                     '设置数据包长度
  44.                     ReDim buffer(5)

  45.                     '写从站地址, 写功能码
  46.                     buffer(0) = m_Cmd.AddressOfReceive
  47.                     buffer(1) = m_Cmd.Command

  48.                     '写数据偏置值
  49.                     buffer(2) = (m_Cmd.WriteAddress And &HFF00&) / &H100
  50.                     buffer(3) = m_Cmd.WriteAddress And &HFF&

  51.                     '写有效数据
  52.                     buffer(4) = m_Cmd.Data(0)
  53.                     buffer(5) = m_Cmd.Data(1)

  54.                     '装入CRC校验值
  55.                     loadCRC(buffer)

  56.                 Case enCommandType.强置多线圈, _
  57.                      enCommandType.预置多寄存器

  58.                     '设置数据包长度
  59.                     ReDim buffer(5)

  60.                     '写从站地址, 写功能码
  61.                     buffer(0) = m_Cmd.AddressOfReceive
  62.                     buffer(1) = m_Cmd.Command

  63.                     '写数据偏置值
  64.                     buffer(2) = (m_Cmd.WriteAddress And &HFF00&) / &H100
  65.                     buffer(3) = m_Cmd.WriteAddress And &HFF&

  66.                     '写数据单位数
  67.                     buffer(4) = (m_Cmd.WriteCount And &HFF00&) / &H100
  68.                     buffer(5) = m_Cmd.WriteCount And &HFF&

  69.                     '装入CRC校验值
  70.                     loadCRC(buffer)
  71.             End Select

  72.             '发送数据
  73.             SerialPort1.Write(buffer, 0, buffer.Length)

  74.             '通讯完成,恢复初值
  75.             TimerOp.Stop()
  76.             m_State.WorkState = enWorkStateType.Idle
  77.             m_State.PortState = enCommStateType.Normal
  78.             m_State.Msg = ""
  79.             SerialPort1.DiscardInBuffer()
  80.             SerialPort1.ReceivedBytesThreshold = 1

  81.         Catch ex As Exception
  82.             m_State.PortState = enCommStateType.Failure
  83.             m_State.Msg = ex.ToString
  84.             str = m_State.Msg

  85.             'Modbus命令结束
  86.             CommunicationOver()
  87.         End Try

  88.         Return str
  89.     End Function

  90.     ''' <summary>
  91.     ''' 数据接收中断中的从站接收函数。
  92.     ''' </summary>
  93.     ''' <remarks></remarks>
  94.     Private Sub ReceiveOfSlaver()
  95.         Dim buffer() As Byte
  96.         Dim str As String = ""

  97.         ReDim buffer(0)

  98.         '读取通讯节点地址
  99.         ReadData(buffer)

  100.         Try
  101.             Select Case m_State.WorkState
  102.                 '空闲
  103.                 Case enWorkStateType.Idle
  104.                     '核对地址
  105.                     If CheckAddress(buffer(0)) = "" Then
  106.                         '计算CRC值
  107.                         uchCRCHi = &HFF     ' 高CRC字节初始化
  108.                         uchCRCLo = &HFF     '低CRC 字节初始化  
  109.                         MakeCRC(buffer, buffer.Length, uchCRCHi, uchCRCLo)

  110.                         '通讯状态进入接收命令状态
  111.                         m_State.WorkState = enWorkStateType.ReceiveCommand
  112.                         m_State.Msg = "通过地址核对, 等待输入命令。"
  113.                         SerialPort1.ReceivedBytesThreshold = 1

  114.                         '开始计时
  115.                         TimerOp.Start()
  116.                     End If

  117.                     '读取功能码和数据地址
  118.                 Case enWorkStateType.ReceiveCommand
  119.                     '关闭时钟()
  120.                     TimerOp.Stop()

  121.                     '计算CRC值
  122.                     MakeCRC(buffer, buffer.Length, uchCRCHi, uchCRCLo)

  123.                     '读取功能码
  124.                     m_Cmd.Command = buffer(0)

  125.                     '读数据的偏置地址
  126.                     m_State.WorkState = enWorkStateType.ReceiceCommandInfo
  127.                     m_State.Msg = "接收了功能码,准备接收数据地址和数量信息。"

  128.                     Select Case m_Cmd.Command
  129.                         Case enCommandType.读线圈, _
  130.                              enCommandType.读离散输入, _
  131.                              enCommandType.读取保持寄存器, _
  132.                              enCommandType.读取输入寄存器

  133.                             SerialPort1.ReceivedBytesThreshold = 4

  134.                         Case enCommandType.强置单线圈, _
  135.                              enCommandType.预置单寄存器

  136.                             SerialPort1.ReceivedBytesThreshold = 2

  137.                         Case enCommandType.强置多线圈, _
  138.                              enCommandType.预置多寄存器

  139.                             SerialPort1.ReceivedBytesThreshold = 5

  140.                         Case enCommandType.读写多寄存器
  141.                             '需要读取:读数据的数量,写数据的偏置量、写数据数量和字节数
  142.                             SerialPort1.ReceivedBytesThreshold = 9

  143.                     End Select

  144.                     '开始计时
  145.                     TimerOp.Start()

  146.                 Case enWorkStateType.ReceiceCommandInfo
  147.                     '关闭时钟()
  148.                     TimerOp.Stop()

  149.                     '计算CRC值
  150.                     MakeCRC(buffer, buffer.Length, uchCRCHi, uchCRCLo)

  151.                     Select Case m_Cmd.Command
  152.                         Case enCommandType.读线圈, _
  153.                              enCommandType.读离散输入, _
  154.                              enCommandType.读取保持寄存器, _
  155.                              enCommandType.读取输入寄存器

  156.                             '读取数据的偏置地址
  157.                             m_Cmd.ReadAddress = (buffer(0) * &H100&) Or buffer(1)
  158.                             m_Cmd.ReadCount = (buffer(2) * &H100&) Or buffer(3)

  159.                             m_State.WorkState = enWorkStateType.ReceiveCRC
  160.                             m_State.Msg = "接收了数据地址,准备接收CRC信息。"
  161.                             SerialPort1.ReceivedBytesThreshold = 2

  162.                         Case enCommandType.强置单线圈, _
  163.                              enCommandType.预置单寄存器

  164.                             m_Cmd.WriteAddress = (buffer(0) * &H100&) Or buffer(1)
  165.                             m_Cmd.WriteCount = 1
  166.                             m_Cmd.DataLen = 2

  167.                             m_State.WorkState = enWorkStateType.ReceiveData
  168.                             m_State.Msg = "接收了数据地址,准备接收数据。"
  169.                             SerialPort1.ReceivedBytesThreshold = 2

  170.                         Case enCommandType.强置多线圈, _
  171.                              enCommandType.预置多寄存器

  172.                             '写数据的偏置地址
  173.                             m_Cmd.WriteAddress = (buffer(0) * &H100&) Or buffer(1)
  174.                             m_Cmd.WriteCount = (buffer(2) * &H100&) Or buffer(3)
  175.                             m_Cmd.DataLen = buffer(4)

  176.                             m_State.WorkState = enWorkStateType.ReceiveData
  177.                             m_State.Msg = "接收了数据地址,准备接收数据。"
  178.                             SerialPort1.ReceivedBytesThreshold = m_Cmd.DataLen

  179.                         Case enCommandType.读写多寄存器
  180.                             '写数据的偏置地址
  181.                             m_Cmd.ReadAddress = (buffer(0) * &H100&) Or buffer(1)
  182.                             m_Cmd.ReadCount = (buffer(2) * &H100&) Or buffer(3)
  183.                             m_Cmd.WriteAddress = (buffer(4) * &H100&) Or buffer(5)
  184.                             m_Cmd.WriteCount = (buffer(6) * &H100&) Or buffer(7)
  185.                             m_Cmd.DataLen = buffer(8)

  186.                             m_State.WorkState = enWorkStateType.ReceiveData
  187.                             m_State.Msg = "接收了数据地址,准备接收数据。"
  188.                             SerialPort1.ReceivedBytesThreshold = m_Cmd.DataLen

  189.                     End Select

  190.                     '开始计时
  191.                     TimerOp.Start()

  192.                     '读取数据
  193.                 Case enWorkStateType.ReceiveData
  194.                     '关闭时钟
  195.                     TimerOp.Stop()

  196.                     '计算CRC值
  197.                     MakeCRC(buffer, buffer.Length, uchCRCHi, uchCRCLo)

  198.                     ReDim m_Cmd.Data(m_Cmd.DataLen - 1)
  199.                     Array.Copy(buffer, m_Cmd.Data, m_Cmd.DataLen)

  200.                     m_State.WorkState = enWorkStateType.ReceiveCRC
  201.                     m_State.Msg = "获得数据,准备接收CRC信息。"
  202.                     SerialPort1.ReceivedBytesThreshold = 2

  203.                     '开始计时
  204.                     TimerOp.Start()

  205.                 Case enWorkStateType.ReceiveCRC
  206.                     '关闭时钟
  207.                     TimerOp.Stop()

  208.                     '检查CRC校验
  209.                     If (uchCRCHi = buffer(0)) And (uchCRCLo = buffer(1)) Then
  210.                         m_State.Msg = "CRC校验通过,请调用应答函数回应主站。"

  211.                         '通讯状态进入应答状态
  212.                         m_State.WorkState = enWorkStateType.Answer

  213.                         '发送通讯结束消息
  214.                         RaiseEvent CommunicationOverEvent(m_Cmd, m_State)

  215.                     Else
  216.                         m_State.PortState = enCommStateType.Failure
  217.                         m_State.Msg = "CRC校验错。"
  218.                     End If

  219.             End Select

  220.             If m_State.PortState <> enCommStateType.Normal Then
  221.                 'Modbus命令结束
  222.                 CommunicationOver()
  223.             End If

  224.         Catch ex As Exception
  225.             m_State.PortState = enCommStateType.Failure
  226.             m_State.Msg = ex.ToString

  227.             'Modbus命令结束
  228.             CommunicationOver()
  229.         End Try
  230.     End Sub



  231.     ''' <summary>
  232.     ''' 接收数据中断。根据主站或从站属性调用不同的接收函数。
  233.     ''' </summary>
  234.     ''' <param name="sender"></param>
  235.     ''' <param name="e"></param>
  236.     ''' <remarks>当串口接收到了指定的接收数量后,将引发本事件。</remarks>
  237.     Private Sub OnSerialPortReceivedEvent(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)
  238.         If m_enModbusMaster = enMasterType.Slaver Then
  239.             ReceiveOfSlaver()
  240.         Else
  241.             ReceiveOfMaster()
  242.         End If

  243.     End Sub

  244.     ''' <summary>
  245.     ''' 串口接收错误事件
  246.     ''' </summary>
  247.     ''' <param name="sender"></param>
  248.     ''' <param name="e"></param>
  249.     ''' <remarks></remarks>
  250.     Private Sub OnSerialErrorReceivedEvent(ByVal sender As Object, ByVal e As System.IO.Ports.SerialErrorReceivedEventArgs)
  251.         Dim str As String = ""

  252.         m_State.PortState = enCommStateType.Failure
  253.         m_State.Msg = "串口通讯异常。"

  254.         CommunicationOver()
  255.     End Sub

  256. #End Region
复制代码
游客,如果您要查看本帖隐藏内容请回复
ss283031771 发表于 2011-4-22 06:49:15 | 显示全部楼层
谢谢分享
winare 发表于 2011-10-17 13:17:01 | 显示全部楼层
..............................
a983200 发表于 2011-11-7 23:26:15 | 显示全部楼层
这个不错。谢谢分享。
a983200 发表于 2011-11-7 23:26:49 | 显示全部楼层
嘻嘻。有源文件就好了。。。。。
iacow 发表于 2012-6-14 16:22:03 | 显示全部楼层
前面的代码看了,觉得楼主写得很不错,想要看完整的代码!
hawk_lee 发表于 2012-7-10 09:43:25 | 显示全部楼层
不能传附件上来吗?
air5210 发表于 2012-10-5 15:00:12 | 显示全部楼层
{:soso_e103:} 呵呵额额和,谢谢哦
flywingjie 发表于 2012-12-6 14:20:31 | 显示全部楼层
非常感谢
   手下了
liuguanglei4 发表于 2013-2-11 10:26:33 | 显示全部楼层
谢谢分享
787494255 发表于 2013-12-18 20:16:03 | 显示全部楼层
帅极了,正好在找
sunboy1234 发表于 2014-12-23 21:30:19 | 显示全部楼层

谢谢分享,正好学习
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


--------------------------------------------------------------------------------------------------------------------
本站是工控技术交流站点,论坛内容均为网络收集或会员所发表,并不代表本站立场,会员拥有该内容的所有权力及责任!
本站内容如有侵犯您的版权,请按下面方式联系本站管理员,我们将及时删除处理
管理员:冰糖 QQ:5483695(请直击主题), Mail:admin#ziwai.net(#改成@) 其它非本人.
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论!

QQ|Archiver|手机版|小黑屋|紫外工控论坛. ( 苏ICP备11032118号-1 )

GMT+8, 2024-4-24 09:57 , Processed in 0.500003 second(s), 17 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表