浙江华通信息技术有限公司提供完整Zigbee解决方案    
1/1页1 跳转到查看:352
发新话题 回复该主题

[开发] Delphi编写的Modbus通讯类

Delphi编写的Modbus通讯类

最近有很多仪表和现场设备要组成Modbus RTU网络,自己使用Delphi编写了Modbus的通讯类,可直接使用,大家多多支持啊。







unit Modbus;
{
  通讯协议 : Modbus;
}

interface

uses SysUtils;

type
TDevModbus
=class
 
private
 
//********************************
  Addr:integer;
  Port:
integer;
  Baud:
integer;
  Mode:
integer;//comm para
 
  PortOpenOk:
boolean;
  DebugM:
boolean;

  id_RwDelayTime:
integer;
  id_DataLength:
integer;

 
//***************************

 
procedure GetCRC(Data:array of byte;Nums:integer;var CRCH,CRCL:byte);
 
function CheckCrc(Data:array of byte;Nums:integer):boolean;

 
procedure ClearInBuff;
 
procedure ClearOutBuff;
 
procedure ClearInOutbuff;

 
function SendCmd(cmd:array of byte;len:integer):integer;//send cmd to pw
  function Recv(var rev:array of byte;len:integer):integer;

 
public
 
constructor create;
 
destructor Destroy;override;
 
function PortOpen:integer;
 
function PortClose:integer;
 
function Read(RegAddr,RegNum:integer;var revdata:array of byte):integer;
 
function ReadByte(RegAddr:integer;High:boolean):integer;
 
function ReadWord(RegAddr:integer):integer;
 
function Write(RegAddr:integer;writedata:Word):integer;
 
function WriteByte(RegAddr:integer;writedata:byte;High:boolean):integer;
 
function WriteMore(RegAddr:integer;data:array of byte;len:integer):integer;

 
property PortOk:boolean read portOpenOk write PortOpenOk;

 
published
   
property DevAddr:integer read Addr write Addr;

   
property ComPort:integer read Port write Port;// comm port
    property ComBaud:integer read Baud write Baud;//comm baud
    property ComMode:integer read Mode write Mode;//comm mode

   
property DebugMode:boolean read debugM write debugM;//
    property RwDelayTime:integer read  id_RwDelayTime Write id_RwDelayTime;

end;

implementation

uses PComm;

{ TPowerMtModule }

procedure TDevModbus.GetCRC(Data:array of byte;Nums:integer;var CRCH, CRCL: byte);
var
  i,j:
integer;
  CRC:
integer;
begin
  CRC:
=$FFFF;
 
for i:=0 to Nums-1 do
 
begin
    CRC:
=CRC xor ord(Data[i]);
   
for j:=0 to 7 do
   
begin

     
if (CRC mod 2=1) then
     
begin
        CRC:
= CRC div 2;
        CRC:
=$A001 xor CRC
     
end
     
else
     
begin
        CRC:
= CRC div 2;
     
end;
   
end;
 
end;
  CRCH :
= crc mod 256;
  CRCL :
= crc div 256;
end;

function TDevModbus.CheckCrc(Data: array of byte;
  Nums:
integer): boolean;
var i:integer;
    tmpdata:
array of byte;
    CRCH,CRCL :
byte;
begin
  setlength(tmpdata,Nums);
 
for i:=0 to Nums-1 do
    tmpdata[i] :
= Data[i];
  GetCrc(tmpdata,Nums
-2,CRCH,CRCL);
 
if(CRCH=Data[Nums-2])and(CRCL=Data[Nums-1])then
   
result := true
 
else result := false;
end;

procedure TDevModbus.ClearInBuff;
begin
if not PortOpenOk then exit;

  sio_flush(Port,
0);

end;

procedure TDevModbus.ClearInOutbuff;
begin
if not portOpenOk then exit;

  sio_flush(port,
2);
end;

procedure TDevModbus.ClearOutBuff;
begin
if not PortOpenOk then exit;

  sio_flush(Port,
1);
end;

constructor TDevModbus.create;
begin
  PortOpenOk:
=false;

  id_RwDelayTime:
=3000;
 
inherited;
end;

destructor TDevModbus.Destroy;
begin
 
if portOpenOk then sio_close(Port);
 
inherited;
end;

function TDevModbus.PortClose:integer;
begin
 
if portOpenOk then result:=sio_close(Port);
end;

function TDevModbus.PortOpen: integer;
var
  ret:
integer;
begin
//--------------打开并设置通讯端口
  if DebugM then exit;

 
if Port<1 then
 
begin
    PortOpenok:
=false;
   
result:=-99;
   
exit;
 
end;

 
if portOpenOk then
 
begin
   
result:=0;
   
exit;
 
end;

  PortOpenOk:
=true;
  ret:
= sio_open(Port);
 
if ret<>SIO_OK then//打开端口出错
    begin
     
if ret=sio_openfail then
      PortOpenOk:
=false;

   
end;

   
result:=result+ret;

    ret :
= ret+sio_ioctl (Port,Baud,Mode);//设置端口
    if ret<>SIO_OK then
   
begin
//      showmessage('SWRT端口通讯置错误: '+inttostr(ret));

      PortOpenOk:
=false;
//      application.terminate;//终止程序

   
end;
    portopen:
=ret;

 
if portOpenok then Result:=0;


end;

function TDevModbus.SendCmd(cmd: array of Byte;len:integer): integer;
begin
 
if not portOpenOk then PortOpen;
 
if not portOpenOk then exit;
 
result:=sio_write(Port,@cmd,len);
end;

function TDevModbus.Recv(var rev: array of byte;len:integer): integer;
begin
 
if not portOpenOk then PortOpen;
 
if not portOpenOk then exit;
 
result:=sio_read(Port,@rev,len);
end;

function TDevModbus.ReadWord(RegAddr:integer):integer;
var i,ret:integer;
    rev:
array[0..1] of byte;
begin
  ret:
=read(regaddr,1,rev);
 
if(ret<0)then
 
begin
   
result:=-1;
   
exit;
 
end;

 
result := rev[0]*256+rev[1];
end;

function TDevModbus.ReadByte(RegAddr:integer;High:boolean):integer;
var i,ret:integer;
    rev:
array[0..1] of byte;
begin
  ret:
=read(regaddr,1,rev);
 
if(ret<0)then
 
begin
   
result:=-1;
   
exit;
 
end;
 
 
if(High)then
   
result := rev[0]
 
else
   
result := rev[1];
end;

function TDevModbus.Read(RegAddr,RegNum:integer; var revdata:array of byte):integer;
var cmd,rev:array of byte;
    i,ret,revlen:
integer;
begin
  ClearInOutBuff;
  setlength(cmd,
8);
  cmd[
0]:=Addr;
  cmd[
1]:=$03;
  cmd[
2]:=RegAddr div 256;
  cmd[
3]:=RegAddr mod 256;
  cmd[
4]:=RegNum div 256;
  cmd[
5]:=RegNum mod 256;

  getCRC(cmd,
6,cmd[6],cmd[7]);

  ret:
=SendCmd(cmd,length(cmd));

  sleep(
200);

  revlen:
=RegNum*2+5;
  setlength(rev,revlen);
  ret:
=ret+Recv(rev,revlen);

 
if(ret=revlen+8)then
   
result := 0
 
else
 
begin
   
result :=-1;
   
exit;
 
end;

 
if(CheckCRC(rev,revlen))then
   
result := 0
 
else
 
begin
   
result := -1;
   
exit;
 
end;

 
for i:=0 to RegNum*2-1 do
 
begin
    revdata[i]:
=rev[i+3];
 
end;

end;

function TDevModbus.Write(RegAddr:integer;writedata:word):integer;
var cmd,rev:array of byte;
    i,ret,revlen:
integer;
begin
  ClearInOutBuff;
  setlength(cmd,
8);
  cmd[
0]:=Addr;
  cmd[
1]:=$06;
  cmd[
2]:=RegAddr div 256;
  cmd[
3]:=RegAddr mod 256;
  cmd[
4]:=writedata div 256;
  cmd[
5]:=writedata mod 256;

  getCRC(cmd,
6,cmd[6],cmd[7]);

  ret:
=SendCmd(cmd,length(cmd));

  sleep(
100);

  revlen:
=8;
  setlength(rev,revlen);
  ret:
=ret+Recv(rev,revlen);

 
if(ret=revlen+8)then
   
result := 0
 
else
 
begin
   
result :=-1;
   
exit;
 
end;

 
if(CheckCRC(rev,revlen))then
   
result := 0
 
else
   
result := -1;
end;

function TDevModbus.WriteByte(RegAddr:integer;writedata:byte;High:boolean):integer;
var cmd,rev:array of byte;
    i,ret,revlen:
integer;
    bHigh,bLow:
byte;
begin

  bHigh:
=0;
  bLow:
=0;

 
//先读出整个寄存器中的数据
  setlength(rev,2);
  ret:
=Read(RegAddr,1,rev);
 
if(ret=0)then
 
begin
    bHigh :
=rev[0];
    bLow :
= rev[1];
 
end;

 
//然后写入相应的字节
  ClearInOutBuff;
  setlength(cmd,
8);
  cmd[
0]:=Addr;
  cmd[
1]:=$06;
  cmd[
2]:=RegAddr div 256;
  cmd[
3]:=RegAddr mod 256;
 
if(not High)then
 
begin
    cmd[
4]:=bHigh;
    cmd[
5]:=writedata mod 256;
 
end
 
else
 
begin
    cmd[
4]:=writedata mod 256;
    cmd[
5]:=bLow;
 
end;

  getCRC(cmd,
6,cmd[6],cmd[7]);

  ret:
=SendCmd(cmd,length(cmd));

  sleep(
100);

  revlen:
=8;
  setlength(rev,revlen);
  ret:
=ret+Recv(rev,revlen);

 
if(ret=revlen+8)then
   
result := 0
 
else
 
begin
   
result :=-1;
   
exit;
 
end;

 
if(CheckCRC(rev,revlen))then
   
result := 0
 
else
   
result := -1;
end;

function TDevModbus.WriteMore(RegAddr: integer; data: array of byte;
  len:
integer): integer;
var cmd,rev:array of byte;
    i,ret,revlen:
integer;
begin
  ClearInOutBuff;
  setlength(cmd,len
+8);
  cmd[
0]:=Addr;
  cmd[
1]:=$10;
  cmd[
2]:=RegAddr div 256;
  cmd[
3]:=RegAddr mod 256;

 
for i:=0 to len-1 do
    cmd[i
+4]:=data[i];

  getCRC(cmd,len
+5,cmd[len+6],cmd[len+7]);

  ret:
=SendCmd(cmd,length(cmd));

  sleep(
100);

  revlen:
=8;
  setlength(rev,revlen);
  ret:
=ret+Recv(rev,revlen);

 
if(ret=revlen+8+len)then
   
result := 0
 
else
 
begin
   
result :=-1;
   
exit;
 
end;

 
if(CheckCRC(rev,revlen))then
   
result := 0
 
else
   
result := -1;
end;

end.

TOP

 
1/1页1 跳转到
发表新主题 回复该主题