wjun7610
级别: 略有小成
精华主题: 0
发帖数量: 127 个
工控威望: 249 点
下载积分: 708 分
在线时间: 31(小时)
注册时间: 2007-09-16
最后登录: 2024-11-08
查看wjun7610的 主题 / 回贴
楼主  发表于: 2008-07-19 19:10
modbus rtu通信协议串口通讯动态链接库DLL(以下简称DLL),是为满足工业通信需要,
针对工业领域要求上位机对PLC、工业仪表通讯实时采集与控制的组态编程而设计。
本DLL是采用Delphi语言开发的标准串口通讯库,具有以下特点:
1)、遵循modbus rtu串口通讯协议(施耐德、西门子、台达、永宏等品牌PLC及各类工业仪表等支持本协议);
2)、实时性、可靠性好,通用性强;
3)、适用于多PLC联网和上位机通信,满足多方面的需要(联网时可采用485总线式);
4)、函数接口功能全,操作简单,支持modbus的大部分读写功能函数;
5)、附加实用转换与读取函数,易于快速开发(VC等非RAD开发环境的开发);
6)、支持USB、PC扩展卡等扩展串口号;
7)、支持多种操作系统win9x/win2000/winXP(标注Win32 DLL);
8)、可在多种编程环境下使用,例如VB、VC、Delphi等开发环境。

9)、支持modbus rtu标准的功能代码01、02、03、04、05、06、15、16且对相关功能代码的读取和写如做了一些扩充更加符合工业自动化领域的工控软件的开发,是广大工控工程师的必备工具软件。

二、modbus rtu通讯协议简介

    Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)
和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集
中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请
求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共
格式。当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定
要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消
息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。
1、在Modbus网络上转输
标准的Modbus口是使用一RS-232C兼容串行接口,它定义了连接口的针脚、电缆、信号位、传输波特率、奇偶校验。控制
器能直接或经由Modem组网。控制器通信使用主—从技术,即仅一设备(主设备)能初始化传输(查询)。其它设备(从设备)
根据主设备查询提供的数据作出相应反应。典型的主设备:主机和可编程仪表。典型的从设备:可编程控制器。主设备
可单独和从设备通信,也能以广播方式和所有从设备通信。如果单独通信,从设备返回一消息作为回应,如果是以广播
方式查询的,则不作任何回应。Modbus协议建立了主设备查询的格式:设备(或广播)地址、功能代码、所有要发送的数
据、一错误检测域。从设备回应消息也由Modbus协议构成,包括确认要行动的域、任何要返回的数据、和一错误检测域。
如果在消息接收过程中发生一错误,或从设备不能执行其命令,从设备将建立一错误消息并把它作为回应发送出去。
2、在其它类型网络上转输
在其它网络上,控制器使用对等技术通信,故任何控制都能初始和其它控制器的通信。这样在单独的通信过程中,控制
器既可作为主设备也可作为从设备。提供的多个内部通道可允许同时发生的传输进程。在消息位,Modbus协议仍提供了
主—从原则,尽管网络通信方法是“对等”。如果一控制器发送一消息,它只是作为主设备,并期望从从设备得到回应。
同样,当控制器接收到一消息,它将建立一从设备回应格式并返回给发送的控制器。
3、查询—回应周期
(1)、查询    
    查询消息中的功能代码告之被选中的从设备要执行何种功能。数据段包含了从设备要执行功能的任何附加信息。例
如功能代码03是要求从设备读保持寄存器并返回它们的内容。数据段必须包含要告之从设备的信息:从何寄存器开始读
及要读的寄存器数量。错误检测域为从设备提供了一种验证消息内容是否正确的方法。
(2)、回应    
    如果从设备产生一正常的回应,在回应消息中的功能代码是在查询消息中的功能代码的回应。数据段包括了从设备
收集的数据:象寄存器值或状态。如果有错误发生,功能代码将被修改以用于指出回应消息是错误的,同时数据段包含
了描述此错误信息的代码。错误检测域允许主设备确认消息内容是否可用。

3、两种传输方式
    控制器能设置为两种传输模式(ASCII或RTU)中的任何一种在标准的Modbus网络通信。用户选择想要的模式,包括串
口通信参数(波特率、校验方式等),在配置每个控制器的时候,在一个Modbus网络上的所有设备都必须选择相同的传输
模式和串口参数。
ASCII模式
   -------------------------------------------
   | 地址 | 功能代码 | 数据数量 | 数据1 ... 数据n | LRC高字节 | LRC低字节 | 回车 | 换行 |
   -------------------------------------------
RTU模式
   ------------------------------------
   | 地址 | 功能代码 | 数据数量 | 数据1 ... 数据n | CRC高字节 | CRC低字节 |
   ------------------------------------
    所选的ASCII或RTU方式仅适用于标准的Modbus网络,它定义了在这些网络上连续传输的消息段的每一位,以及决定
怎样将信息打包成消息域和如何解码。在其它网络上(象MAP和Modbus Plus)Modbus消息被转成与串行传输无关的帧。
    因ASCII模式通讯效率较低一多采用RTU模式,这里只对RTU模式进行详细介绍。

4、Modbus RTU模式

    当控制器设为在Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制
字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据。

代码系统

    8位二进制,十六进制数0...9,A...F
    消息中的每个8位域都是一个两个十六进制字符组成

每个字节的位

    1个起始位
    8个数据位,最小的有效位先发送
    1个奇偶校验位,无校验则无
    1个停止位(有校验时),2个Bit(无校验时)

错误检测域
    
     CRC(循环冗长检测)

地址域

    消息帧的地址域包含8Bit(RTU)。可能的从设备地址是0...247(十进制)。单个设备的地址范围是1...247。主设备通过
将要联络的从设备的地址放入消息中的地址域来选通从设备。当从设备发送回应消息时,它把自己的地址放入回应的地址域
中,以便主设备知道是哪一个设备作出回应。地址0是用作广播地址,以使所有的从设备都能认识。当Modbus协议用于更高
水准的网络,广播可能不允许或以其它方式代替。

如何处理功能域

    数据域是由两个十六进制数集合构成的,范围00...FF。根据网络传输模式,这可以是由一RTU字符组成。从主设备发给
从设备消息的数据域包含附加的信息:从设备必须用于进行执行由功能代码所定义的所为。这包括了象不连续的寄存器地址,
要处理项的数目,域中实际数据字节数。例如,如果主设备需要从设备读取一组保持寄存器(功能代码03),数据域指定了起
始寄存器以及要读的寄存器数量。如果主设备写一组从设备的寄存器(功能代码10十六进制),数据域则指明了要写的起始寄
存器以及要写的寄存器数量,数据域的数据字节数,要写入寄存器的数据。如果没有错误发生,从从设备返回的数据域包含
请求的数据。如果有错误发生,此域包含一异议代码,主设备应用程序可以用来判断采取下一步行动。在某种消息中数据域
可以是不存在的(0长度)。例如,主设备要求从设备回应通信事件记录(功能代码0B十六进制),从设备不需任何附加的信息。

作者:  wjun7610
QQ:    157610979
淘宝店:http://shop34821629.taobao.com
[ 此贴被wjun7610在2008-07-20 14:25重新编辑 ]
附件: Modbus.rar (153 K) 下载次数:2205
网站提示: 请不要用迅雷下载附件,容易出错
wjun7610
级别: 略有小成
精华主题: 0
发帖数量: 127 个
工控威望: 249 点
下载积分: 708 分
在线时间: 31(小时)
注册时间: 2007-09-16
最后登录: 2024-11-08
查看wjun7610的 主题 / 回贴
1楼  发表于: 2008-07-19 19:10
三、DLL函数说明


modbus.DLL是王俊于2007年最新开发的基于施耐得modbus rtu 通讯协议的串口通讯链接库。modbus.DLL专业版实现了对保持寄存器40001~4XXXX区数据读写(FCN03:读、FCN16:写,FCN06写单个数据);对逻辑线圈00001~0XXXX的 读写(FCN01:读取一组线圈,FCN05:强置单线圈,FCN15强置多线圈);对输入状态10001~1XXXX的读(FCN02);对输入寄存器30001~3XXXX的读(FCN04)。

DLL中的主要函数:

ComOpen:打开串口

ComClose:关闭串口

FCN01:读取一组线圈(00001~0XXXX)

FCN02:取得一组开关输入状态数据(10001~1XXXX)

FCN03:读多个保持寄存器数据(40001~4XXXX)

FCN04:读多个输入寄存器数据(30001~3XXXX)

FCN05S:置位单线圈(00001~0XXXX)

FCN05R:复位单线圈(00001~0XXXX)

FCN06: 预置单保持寄存器数据(40001~4XXXX)

FCN15: 强置多线圈的通断数据(00001~0XXXX)

FCN16: 写多个保持寄存器数据(40001~4XXXX)

FCN16_xSet:单保持寄存器的0~15相应位的置位(40001.0-40001.15~4XXXX.0-4XXXX.15)

FCN16_xReset:单保持寄存器的0~15相应位的复位(40001.0-40001.15~4XXXX.0-4XXXX.15)

FCN16_xSetReset:单保持寄存器的0~15相应位的置复位(40001.0-40001.15~4XXXX.0-4XXXX.15),
                 指使相应的位短时间通断一次(约通60ms)

ComTrue:读取DLL中的串口是否备有效打开

CinBin: 字中相应的位的状态抽取

1、打开串口

Function ComOpen(nport,BaudRate,DataBits,Parity,StopBits:longint;User:Pchar):longint;stdcall;

参数:nport: 打开串口号,取值为1~8,代表COM1~COM8;
      
      BaudRate:波特率,取值为:1200、2400、4800、9600、19200、38400;
    
      DataBits:数据位,取值为5、6、7、8;

      Parity:  校验位,取值1(代表Even)、取值2(代表Odd)、取值3(代表Mark)、取值4(代表Space)、取值5(代表None);
  
      StopBits:停止位,取值1(代表1位停止位)、取值2(代表2位停止位)、取值3(代表1.5位停止位);

      User:DLL授权用户名;

返回值:长整型,操作成功返回“1”或“2”;1表示注册授权用户,2表示用户未注册;

操作不成功返回为“0”时的原因:1)、串口不存在或被占用; 2)、DLL注册授权不正确。

注:本DLL用户不注册除了下面说明的功能限制外没有其他限制,未注册用户请使用特定用户名:wangjun。

    注册用户功能上无任何限制,且将得到永久的软件使用和更新升级服务;

使用举例:

Delphi:ComOpen(1,9600,8,1,1,Pchar('wangjun')) , 打开COM1口。

VB:ComOpen(1,9600,8,1,1,"wangjun") , 打开COM1口。(注:下面的示例都以VB调用形式给出)

2、关闭串口

Function ComClose(nport:longint):longint;stdcall;

参数:nport: 串口号,取值为1~8,代表COM1~COM8;

返回值:长整型,操作成功返回“1”,否则返回“0”;

使用举例:

ComClose(1) ,关闭打开的COM1口。

3、modbus相应功能码所对应的读取功能函数。

1)、01功能码位元件的读取(读取一组线圈)

Function FCN01(nport,node,address,Count:longint):Pchar;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从00001~0XXXX地址区(逻辑线圈)值(你要读标准modbus的00001地址这个值为0000,依次类推)

Count:   读取的位元件个数,一次最多读取1000个但不能超出寻址范围;

返回值: 16进制字符串数据,字符串数据的终止符为"@";

使用举例:

FCN01(1,1,19,37),由COM1读取modbus 1号从站00020~00056(标准modbus地址)的位状态值,返回值为“CD6BB20E1B@”

则表示27~20:CD, 35~28:6B, 43~36:B2, 51~44:0E, 56~52:1B;

字节值与实际的位状态值对应参考(其他位功能函数的说明不再重复本内容):
            
位地址:    | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 35 | 34 | 33 | 32 | 31 | 30 | 29 | 28 |
            -----------------------------------------
各位赋值:   | 1  | 1  | 0  | 0  | 1  | 1  | 0  | 1  | 0  | 1  | 1  | 0  | 1  | 0  | 1  | 1  |
            -----------------------------------------
16进制串:  |         C         |         D         |         6         |         B         |
            -----------------------------------------

不足8位的位组的状态值参考:

位地址:    | 56 | 55 | 54 | 53 | 52 |
            -------------
各位赋值:   | 0  | 1  | 0  | 1  | 1  |
            -------------
16进制串:  | 1  |         B         |
            -------------

在读取错误或不能读取的情况下返回“Error@”

注:没有注册的用户只能读取00001~00006范围的状态值;

2)、02功能码位元件的读取(取得一组开关输入状态数据)

Function FCN02(nport,node,address,Count:longint):Pchar;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从10001~1XXXX地址区(开关输入状态)值(你要读标准modbus的10001地址这个值为0000,依次类推)

Count:   读取的位元件个数,一次最多读取1000个但不能超出寻址范围;

返回值: 16进制字符串数据,字符串数据的终止符为"@";

使用举例:

FCN02(1,1,196,22),由COM1读取modbus 1号从站10197~10218(标准modbus地址)的位状态值,返回值为“ACDB35@”

则表示10204~10197:AC, 10212~10205:DB, 10218~10213:35;

在读取错误或不能读取的情况下返回“Error@”

注:没有注册的用户只能读取10001~10006范围的状态值;

3)、03功能码字元件的读取(读多个保持寄存器数据)

Function FCN03(nport,node,address,Count:longint):Pchar;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从40001~4XXXX地址区(保持寄存器数据)值(你要读标准modbus的40001地址这个值为0000,依次类推)

Count:   读取的位元件个数,一次最多读取60个但不能超出寻址范围;

返回值: 16进制字符串数据,字符串数据的终止符为"@";

使用举例:

FCN03(1,1,107,3),由COM1读取modbus 1号从站40108~40110(标准modbus地址)的字状态值,返回值为“022B00000064@”

则表示40108:022B, 40109:0000, 40110:0064;

在读取错误或不能读取的情况下返回“Error@”

注:没有注册的用户只能读取40001~40003范围的状态值;

4)、04功能码字元件的读取(读多个输入寄存器数据)

Function FCN04(nport,node,address,Count:longint):Pchar;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从30001~3XXXX地址区(输入寄存器数据)值(你要读标准modbus的30001地址这个值为0000,依次类推)

Count:   读取的位元件个数,一次最多读取60个但不能超出寻址范围;

返回值: 16进制字符串数据,字符串数据的终止符为"@";

使用举例:

FCN04(1,17,8,1),由COM1读取modbus 17号从站30009(标准modbus地址)的字状态值,返回值为“000A@”

则表示30009:000A;

在读取错误或不能读取的情况下返回“Error@”

注:没有注册的用户只能读取30001~30003范围的状态值;

4、modbus相应功能码所对应的写入功能函数

1)、05功能码线圈的置复位功能函数

    1、线圈置位
            
       Function FCN05S(nport,node,address:longint):longint;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从00001~0XXXX地址区(逻辑线圈)值(你要写标准modbus的00001地址这个值为0000,依次类推)

返回值: 长整数,操作成功返回1,不能写入或操作错误返回0;

使用举例:

FCN05S(1,12,15),由COM1将modbus 12号从站00013(标准modbus地址)的位状态值置1,返回值为1表示成功

注:没有注册的用户只能写入00001~00006范围的状态值;

       2、线圈复位
            
       Function FCN05R(nport,node,address:longint):longint;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从00001~0XXXX地址区(逻辑线圈)值(你要写标准modbus的00001地址这个值为0000,依次类推)

返回值: 长整数,操作成功返回1,不能写入或操作错误返回0;

使用举例:

FCN05R(1,12,15),由COM1将modbus 12号从站00013(标准modbus地址)的位状态值置0,返回值为1表示成功

注:没有注册的用户只能写入00001~00006范围的状态值;

2)、06功能码预置单保持寄存器数据功能函数

Function FCN06(nport,node,address:longint;Sendstr:pchar):longint;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从40001~4XXXX地址区(保持寄存器)值(你要写标准modbus的40001地址这个值为0000,依次类推)

Sendstr: 写入字值,该值为4个一组的16进制字符串组成其取值为0000~FFFF(整数值为0~65535);

返回值: 长整数,操作成功返回1,不能写入或操作错误返回0;

当要写入字值时依次排列即可。如给40001写值1000,先将1000转成16进制字符串03E8,则sendstr=03E8;

使用举例:

FCN06(1,2,2,"03E8"),由COM1给modbus 2号从站40003(标准modbus地址)的字单元写入1000(16进制03E8),返回值为1表示成功

注:没有注册的用户只能写入40001~40003范围的状态值;

(00001~0XXXX)

3)、15功能码强置多线圈的通断数据功能函数

Function FCN15(nport,node,address,Count:longint;Sendstr:pchar):longint;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从00001~0XXXX地址区(逻辑线圈)值(你要写标准modbus的00001地址这个值为0000,依次类推)

Count:  写入位元件个数,一次最多1000个但不能超出寻址范围;

Sendstr: 给位元件写入的值按8个为一组和成字节值在写入,该值为2个一组的16进制字符串组其取值为00~FF(整数值为0~255);

返回值: 长整数,操作成功返回1,不能写入或操作错误返回0;

                  ---------- - ~ - ------
写字符串序列如:  | 00 | FF | 10 | 64 |   ~    | 08 | 04 |
                  ---------- - ~ - ------

实际字符串与位地址的数值应如下表:  
          
位地址:    | 40 | 39 | 38 | 36 | 35 | 34 | 33 | 32 | 48 | 47 | 46 | 45 | 44 | 43 | 42 | 41 |
            -----------------------------------------
各位赋值:   | 0  | 1  | 1  | 0  | 0  | 1  | 0  | 0  | 0  | 1  | 0  | 1  | 0  | 0  | 0  | 0  |
            -----------------------------------------
16进制串:  |         6         |         4         |         5         |         0         |
            -----------------------------------------

使用举例:

FCN06(1,2,19,10,"CD01"),由COM1给modbus 2号从站00020~00029(标准modbus地址)10个位单元写如相应值,返回值为1表示成功

写入值的参考 27~20:CD; 29~28:01;

位地址:    | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | -- | -- | -- | -- | -- | -- | 29 | 28 |
            -----------------------------------------
各位赋值:   | 1  | 1  | 0  | 0  | 1  | 1  | 0  | 1  | 0  | 0  | 0  | 0  | 0  | 0  | 0  | 1  |
            -----------------------------------------
16进制串:  |         C         |         D         |         0         |         1         |
            -----------------------------------------

注:没有注册的用户只能写入00001~00006范围的状态值;

4)、16功能码写多个保持寄存器数据功能函数

Function FCN16(nport,node,address,Count:longint;Sendstr:pchar):longint;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从40001~4XXXX地址区(保持寄存器)值(你要写标准modbus的40001地址这个值为0000,依次类推)

Count:  写入字元件个数,一次最多60个但不能超出寻址范围;

Sendstr: 给字写入的值,该值为4个一组的16进制字符串组其取值为0000~FFFF(整数值为0~65535);

返回值: 长整数,操作成功返回1,不能写入或操作错误返回0;

当要写入多个字值时依次排列即可。如给40001与40002写值100和1000,先将100转成16进制字符串0064、1000转成16进制字符串03E8,

则sendstr=006403E8;一次最多写64个字即字符串长应小于等于256;

                            ---------- ----   ~  ---------
写字符串序列如:             | 0064 | 03E8 | 0010 | 6004 |   ~     | 0008 | 0400 |
                            ---------- ----   ~  ---------

使用举例:

FCN16(1,2,1,"000A0102"),由COM1给modbus 2号从站40002(标准modbus地址)的字单元写入给10(16进制000A)、40003(标准modbus地址)

的字单元写入给258(16进制0102)返回值为1表示成功;

注:没有注册的用户只能写入40001~40003范围的状态值;

5)、modbus功能码16的扩展功能函数

       1、单保持寄存器的0~15相应位的置位 (40001.0-40001.15~4XXXX.0-4XXXX.15)
            
       Function FCN16_xSet(nport,node,address,Bit:longint):longint;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从40001~4XXXX地址区(保持寄存器)值(你要写标准modbus的40001地址这个值为4000,依次类推)

Bit:     保持寄存器的位,取值0~15;

返回值: 长整数,操作成功返回1,不能写入或操作错误返回0;

使用举例:

FCN16_xSet(1,12,2,0),由COM1将modbus 12号从站40003(标准modbus地址)的第0个位状态值置1,返回值为1表示成功

注:没有注册的用户不能使用本功能;

        2、单保持寄存器的0~15相应位的复位 (40001.0-40001.15~4XXXX.0-4XXXX.15)
            
        Function FCN16_xReset(nport,node,address,Bit:longint):longint;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从40001~4XXXX地址区(保持寄存器)值(你要写标准modbus的40001地址这个值为4000,依次类推)

Bit:     保持寄存器的位,取值0~15;

返回值: 长整数,操作成功返回1,不能写入或操作错误返回0;

使用举例:

FCN16_xReset(1,10,3,12),由COM1将modbus 10号从站40004(标准modbus地址)的第12个位状态值置0,返回值为1表示成功

注:没有注册的用户不能使用本功能;

        3、单保持寄存器的0~15相应位的置复位 (40001.0-40001.15~4XXXX.0-4XXXX.15)指使相应的位短时间通断一次(接通约60ms)
            
        Function FCN16_xSetReset(nport,node,address,Bit:longint):longint;stdcall;

参数:

nport:   串口号,取值为1~8,代表COM1~COM8;

node:   modbus从站号,取值1~255;

address: 元件地址,取值范围从40001~4XXXX地址区(保持寄存器)值(你要写标准modbus的40001地址这个值为4000,依次类推)

Bit:     保持寄存器的位,取值0~15;

返回值: 长整数,操作成功返回1,不能写入或操作错误返回0;

使用举例:

FCN16_xSetReset(1,10,9,10),由COM1将modbus 10号从站40010(标准modbus地址)的第10个位状态值置1后约60ms再置0,返回值为1表示成功

注:没有注册的用户不能使用本功能;

四、DLL附加函数说明 (本段函数对未注册用户没有限制,完全可以使用。)

1、串口打开状态的读取

Function ComTrue(nport:longint):longint;stdcall;

参数:

noprt: 串口号,取值为1~8,代表COM1~COM8;

返回值:长整型,串口成功打开返回“1”,否则返回“0”;

这里读取是DLL有效取得了串口的控制权,如果其他程序占用(串口不存在)等原因仍返回“0”。

2、整数转换成16进制字符串 (为VC等非RAD开发环境所增设)

Function CIntToHex(Dcint,Digits:Longint):Pchar;stdcall;

参数:

Cint: 待转换整数,取值为(0~65535);

Digits: 转换的字符串位数,指定位数小于实际位数时按实际输出;

在参数错误等非法的情况下返回“Error@”

使用举例:

CIntToHex(200,2),则返回字符串“C8@”;
CIntToHex(200,4),则返回字符串“00C8@”;
CIntToHex(200,8),则返回字符串“000000C8@”;
CIntToHex(4500,4),则返回字符串“1194@”;
CIntToHex(4500,3),则返回字符串“1194@”,因为“194”不足以表示4500这个数所以按实际输出字符串“1194@”;

"@"为字符串数据的终止符。

3、16进制字符串转换成整数 (为VC等非RAD开发环境所增设)

Function CHexToInt(CHex:Pchar):Longint;stdcall;

参数:

CHex: 待转换字符串,取值为(0000~FFFF);

使用举例:

CHexToInt("03E8"),则返回整数1000;

注:在参数不正确等出错情况下返回值为“-1”。

4、抽取(0~65535)所示整数中(0~15)某个位的值

Function CinBin(CHex,Start:longint):longint;stdcall;

参数:

CHex: 待转换整数,取值为0~65535(0000~FFFF);

Start: 抽取的位,取值为(0~15);

使用举例:

CinBin(15,3),则返回值1;
CinBin(15,4),则返回值0;
CinBin(1000,6),则返回值1;

读取MB0组合成的字节值为“FC”(252)时,要读取M0.1的值时,则调用CinBin(252,1)返回值0表示M0.1的值为0。

注:在参数不正确等出错情况下返回值为“-1”。

5、返回字符串Text左边的Count个字符  (为VC等非RAD开发环境所增设)

Function CLeftStr(Text:Pchar;Count:longint):Pchar;stdcall;

参数:

Text: 字符串原型;

Count: 指定返回左侧字符串个数;

在参数错误等非法的情况下返回“Error@”

使用举例:

CleftStr("123456", 3) = "123@";

"@"为字符串数据的终止符。

6、返回字符串Text右边的Count个字符  (为VC等非RAD开发环境所增设)

Function CRightStr(Text:Pchar;Count:longint):Pchar;stdcall;

参数:

Text: 字符串原型;

Count: 指定返回右侧字符串个数

在参数错误等非法的情况下返回“Error@”

使用举例:

CRightStr("123456", 3) = "456@";

"@"为字符串数据的终止符。

7、返回字符串Text从Start开始的Count个字符 (为VC等非RAD开发环境所增设)

Function CMidStr(Text:Pchar;Start,Count:longint):Pchar;stdcall;

参数:

Text: 字符串原型;

Start: 指定返回字符串的起始位置;

Count: 指定返回字符串个数;

在参数错误等非法的情况下返回“Error@”

使用举例:

CMidStr("123456",2,3) = "234@";

"@"为字符串数据的终止符。

8、字符串Cstr开始于字符串Ostr的位置 (为VC等非RAD开发环境所增设)

Function Cinstr(Ostr,Ckstr:Pchar;Dcint:Longint):Longint;stdcall;

参数:

Ostr:  字符串原型;

Cstr:  查询的字符串;

Dcint: 设定查询字符串的起始位置,取值>=1,即最少从源字符串的第一个字符开始查询;

返回值:长整型;

使用举例:

CinStr("1Tfdg23456","2",2) = 6

注:在参数不正确等出错情况下返回值为“0”。

9、PC喇叭的报警过程函数;

Function MyBeep(SoundHz:longint):longint;stdcall;

参数:SoundHz:长整型;

返回值:长整型,操作成功返回“1”,否则返回“0”。

使用举例:

MyBeep(2000); 按2000的频率发出报警声。

DLL中关于传出字符串值的函数都以"@"为字符串函数值终止符,这是对多开发环境应用时方便用户正确读取返回字符串数据而设。

五、Delphi、VB、VC语言环境的开发使用说明

1、Delphi语言环境开发说明

在Delphi环境下将modbus.dll、serialmodbus.slip(许可文件)复制到应用程序目录下(即将上述文件与编译后的可执行文件方入同一文件内);

在工程文件的主程序窗体(pas)文件中声明:

  Function ComOpen(nport,BaudRate,DataBits,Parity,StopBits:longint;User:Pchar):longint;stdcall;External'modbus.dll';
  Function ComClose(nport:longint):longint;stdcall;External'modbus.dll';
  Function FCN01(nport,node,address,Count:longint):Pchar;stdcall;External'modbus.dll';
  Function FCN02(nport,node,address,Count:longint):Pchar;stdcall;External'modbus.dll';
  Function FCN03(nport,node,address,Count:longint):Pchar;stdcall;External'modbus.dll';
  Function FCN04(nport,node,address,Count:longint):Pchar;stdcall;External'modbus.dll';
  Function FCN05S(nport,node,address:longint):longint;stdcall;External'modbus.dll';
  Function FCN05R(nport,node,address:longint):longint;stdcall;External'modbus.dll';
  Function FCN06(nport,node,address:longint;Sendstr:pchar):longint;stdcall;External'modbus.dll';
  Function FCN15(nport,node,address,Count:longint;Sendstr:pchar):longint;stdcall;External'modbus.dll';
  Function FCN16(nport,node,address,Count:longint;Sendstr:pchar):longint;stdcall;External'modbus.dll';
  Function FCN16_xSet(nport,node,address,Bit:longint):longint;stdcall;External'modbus.dll';
  Function FCN16_xReset(nport,node,address,Bit:longint):longint;stdcall;External'modbus.dll';
  Function FCN16_xSetReset(nport,node,address,Bit:longint):longint;stdcall;External'modbus.dll';
  Function ComTrue(nport:longint):longint;stdcall;External'modbus.dll';
  Function MyBeep(SoundHz:longint):longint;stdcall;External'modbus.dll';

其它附加函数Delphi有实用函数,建议用Delphi自带函数,如需使用声明参照上例;

注:所有DLL的函数必须声明方能使用,建议本DLL的声明采用示例所示的静态声明方式。 声明后可以在程序中使用这些函数,附加函数

中除ComTrue、CinBin、MyBeep等Delphi系统自带有类似功能函数。通信时必须先使用ComOpen函数打开串口,在串口打开后可以有效操作

相关函数,为确保通信可在程序运行开始时打开串口,程序退出前关闭串口。应用程序退出之前请务必将关闭所有串口,如串口没有关闭

而退出程序将抛出异常错误。

确保应用程序在关闭释放前关闭打开的串口。解决方法,在form的OnDestroy事件中加入如下语句:

for i:=1 to 8 do
begin
  if ComTrue(i)=1 then ComClose(i);
end;

在Delphi中给中给DLL中的函数传pchar值问题,建议string型转换到Pchar型采用strPCopy()函数,Pchar型转换到string型采用straps()函数,

不推荐使用直接转换法即string到Pchar类型采用Mpchar=Pchar(str),Pchar到string采用str:=Mpchar (str为string类型、Mpchar为Pchar

类型)。上述可以详细参照DEMO程序。

2、VB语言环境开发说明

在VB环境下将modbus.dll、serialmodbus.slip(许可文件)复制到应用程序目录下(即将上述文件与编译后的可执行文件方入同一文件夹内);

函数说明中给出的是Delphi的函数原型,在VB中声明时只要注意一下类型的对应即可Delphi中的longint类型对应VB中的Long类型、

Delphi中的Pchar对应VB中的String类型,下面给出主要函数的声明:

Private Declare Function ComOpen Lib "modbus.dll" (ByVal nport As Long, ByVal BaudRate As Long, ByVal DataBits As Long, ByVal Parity As Long, ByVal StopBits As Long, ByVal User As String) As Long
Private Declare Function ComClose Lib "modbus.dll" (ByVal nport As Long) As Long
Private Declare Function FCN01 Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Count As Long) As String
Private Declare Function FCN02 Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Count As Long) As String
Private Declare Function FCN03 Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Count As Long) As String
Private Declare Function FCN04 Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Count As Long) As String
Private Declare Function FCN05S Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long) As Long
Private Declare Function FCN05R Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long) As Long
Private Declare Function FCN06 Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Sendstr As String) As Long
Private Declare Function FCN15 Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Count As Long, ByVal Sendstr As String) As Long
Private Declare Function FCN16 Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Count As Long, ByVal Sendstr As String) As Long
Private Declare Function FCN16_xSet Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Bit As Long) As Long
Private Declare Function FCN16_xReset Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Bit As Long) As Long
Private Declare Function FCN16_xSetReset Lib "modbus.dll" (ByVal nport As Long, ByVal node As Long, ByVal address As Long, ByVal Bit As Long) As Long
Private Declare Function ComTrue Lib "modbus.dll" (ByVal nport As Long) As Long
Private Declare Function MyBeep Lib "modbus.dll" (ByVal SoundHz As Long) As Long
Private Declare Function CinBin Lib "modbus.dll" (ByVal CHex As Long, ByVal start As Long) As Long

其它附加函数VB有实用函数,建议用VB自带函数,如需使用声明参上面的例子给相应的函数声明;做完上述声明后,便可以在程序中使用

相关函数了。本DLL是串口通信库,通信时必须先使用ComOpen函数打开串口,在串口打开后可以有效操作相关函数,为保证通信可以在

程序运行开始时打开串口,程序退出前关闭串口。在应用程序关闭之前请务必将关闭所有串口,如您的程序串口没有关闭退出程序将抛

出异常。当出现这样的异常请更改您的程序,确保应用程序在关闭释放前关闭所打开的串口。

解决方法,在form的Unload事件中加入如下例:

If ComTrue(1)=1 then
  ComClose(1)
End if

为确保Unload事件有效执行程序中不应使用“End”语句,而尽量使用“Unload”语句释放所有窗体,因使用“End”语句系统不会执行

正常的窗体释放等事件而直接退出程序,如程序中有form1,form2两个窗体,则使用下面语句:

Unload  form1
Unload  form2

VB会在所有窗体关闭后释放所有占用资源。上述可以详细参照DEMO程序。当然也可在使用“End”语句前将串口关闭也是可以释放串口的。

3、VC语言环境开发说明

在VC环境下将modbus.dll、serialmodbus.slip(许可文件)复制到应用程序目录下(即将上述文件与编译后的可执行文件方入同一文件夹内);

在VC中使用DLL一般都是采用动态声明的方式,函数说明中给出的是Delphi的函数原型,在VC中声明时只要注意一下类型的对应即可

Delphi中的longint类型对应VC中的Long类型、Delphi中的Pchar对应VC中的char* 类型,下面给出主要函数的声明:

在工程主文件cpp中声明一个句柄:

HINSTANCE m_handle;

用来标识导入的动态链接库。

1)、导入动态链接库,如例所示:

   m_handle =:: LoadLibrary("modbus.dll");

2)、按下例说明声明相关各个函数:

typedef long (CALLBACK* pOpen)(long nport, long BaudRate, long DataBits, long Parity, long StopBits, char* User);
typedef long (CALLBACK* pClose)(long nport);
typedef char* (CALLBACK* pFCN01)(long nport, long node, long address, long Count);
typedef char* (CALLBACK* pFCN02)(long nport, long node, long address, long Count);
typedef char* (CALLBACK* pFCN03)(long nport, long node, long address, long Count);
typedef char* (CALLBACK* pFCN04)(long nport, long node, long address, long Count);
typedef long (CALLBACK* pFCN05S)(long nport, long node, long address);
typedef long (CALLBACK* pFCN05R)(long nport, long node, long address);
typedef long (CALLBACK* pFCN06)(long nport, long node, long address, char* Sendstr);
typedef long (CALLBACK* pFCN15)(long nport, long node, long address, long Count, char* Sendstr);
typedef long (CALLBACK* pFCN16)(long nport, long node, long address, long Count, char* Sendstr);
typedef long (CALLBACK* pFCN16_xSet)(long nport, long node, long address, long Bit);
typedef long (CALLBACK* pFCN16_xReset)(long nport, long node, long address, long Bit);
typedef long (CALLBACK* pFCN16_xSetReset)(long nport, long node, long address, long Bit);
typedef long (CALLBACK* pTrue)(long nport);
typedef char* (CALLBACK* pIntHex)(long Dcint,long Digits);
typedef long (CALLBACK* pHexInt)( char* CHex);
typedef long (CALLBACK* pBin)( long Chex, long Start);
typedef char* (CALLBACK* pLeft)( char* Text, long Count);
typedef char* (CALLBACK* pRight)( char* Text, long Count);
typedef char* (CALLBACK* pMid)( char* Text, long  Start, long Count);
typedef long (CALLBACK* pinstr)( char* Ostr, char* Ckstr, Long Dcint);
typedef long (CALLBACK* pBeep)( long SoundHz);

3)、声明并建立动态链接库中的函数与新函数名的对应关系,如下:

pOpen Copen = (pOpen)GetProcAddress(m_handle,"ComOpen");
pClose Cclose = (pClose)GetProcAddress(m_handle,"ComClose");
pFCN01 CFCN01 = (pFCN01)GetProcAddress(m_handle,"FCN01");
pFCN02 CFCN02 = (pFCN02)GetProcAddress(m_handle,"FCN02");
pFCN03 CFCN03 = (pFCN03)GetProcAddress(m_handle,"FCN03");
pFCN04 CFCN04 = (pFCN04)GetProcAddress(m_handle,"FCN04");
pFCN05S CFCN05S = (pFCN05S)GetProcAddress(m_handle,"FCN05S");
pFCN05R CFCN05R = (pFCN05R)GetProcAddress(m_handle,"FCN05R");
pFCN15 CFCN15 = (pFCN15)GetProcAddress(m_handle,"FCN15");
pFCN16 CFCN16 = (pFCN16)GetProcAddress(m_handle,"FCN16");
pFCN16_xSet CFCN16_xSet = (pFCN16_xSet)GetProcAddress(m_handle,"FCN16_xSet");
pFCN16_xReset CFCN16_xReset = (pFCN16_xReset)GetProcAddress(m_handle,"FCN16_xReset");
pFCN16_xSetReset CFCN16_xSetReset = (pFCN16_xSetReset)GetProcAddress(m_handle,"FCN16_xSetReset");
pTrue Ctrue = (pTrue)GetProcAddress(m_handle," ComTrue");
pIntHex Cinthex = (pIntHex)GetProcAddress(m_handle," CIntToHex");
pHexInt Chexint = (pHexInt)GetProcAddress(m_handle," CHexToInt");
pBin Cbin = (pBin)GetProcAddress(m_handle," CinBin");
pLeft Cleft = (pLeft)GetProcAddress(m_handle," CLeftStr");
pRight Cright = (pRight)GetProcAddress(m_handle," CRightStr");
pMid Cmid= (pMid)GetProcAddress(m_handle," CMidStr");
pinstr Cinstr=(pinstr)GetProcAddress(m_handle," CinStr");
pTrue CBeep = (pBeep)GetProcAddress(m_handle," MyBeep");

注:双引号中为动态链接库中的函数名。

4)、接下来就可以自由使用动态链接库中的函数了,如:

Copen(参数略);
Cclose(参数略);
CFCN01(参数略);
CFCN02(参数略);
CFCN03(参数略);
CFCN04(参数略);
CFCN05S(参数略);
CFCN05R(参数略);
CFCN15(参数略);
CFCN16(参数略);
CFCN16_xSet(参数略);
CFCN16_xReset(参数略);
CFCN16_xSetReset(参数略);
Ctrue(参数略);
Cinthex(参数略);
Chexint(参数略);
Cbin(参数略);
Cleft(参数略);
Cright(参数略);
Cmid(参数略);
Cinstr(参数略);
CBeep(参数略);

注:函数中用到了char*型参数,这里介绍下char*与Cstring的相互转换的函数:

(1)char*->CString

char* sz;
CString str;
str.Format("%s",sz);  //可以用此函数将读取的值转成字符串

(2) CString -> char*

CString str;
char* sz = str.GetBuffer(0);//可将字符串转成char*给函数赋值


5)、当不再需要使用DLL时记得关闭串口及释放动态链接库,如:

关闭串口

if cTrue(1)==1 then
{
  cClose(1);
}

6)、释放DLL

FreeLibrary(m_handle);

六、详细的DLL使用请参DEMO程序,相关DEMO程序和说明所使用的开发环境VB指的是VB6.0,Delphi指的是Delphi6.0/Delphi7.0,

VC指的是VC6.0。如果使用了高版本开发环境请根据开发软件更新后所兼容的声明方式进行声明调用。VC的串口调用没DEMO程序

请参照本手册的说明进行调用(本说明的方法经过测试是可行有效的)。

DLl已经过使用和测试具有很好的稳定性(测试平台为Win2000/WinXP),目前还没有用户方面返回的缺陷报告,如果你在使用过程中发现

有什么缺陷也请和我联系,我将在最短时间内给你更新升级(更新升级只针对注册用户)。

作者:  wjun7610
QQ:    157610979
淘宝店:http://shop34821629.taobao.com