首页 > 其他分享 >delphi实现modbus通信

delphi实现modbus通信

时间:2023-05-18 20:24:07浏览次数:36  
标签:SendBuff begin end delphi 通信 sMsg modbus var Integer

-------------------------------------------------------------基础单元----start-----------------------------------------------------------------------------

{********************************************************************}
{* 单元名称:UntModBusBase基础单元 *}
{* 功能描述:管理 连接、接收、发送 *}
{* *}
{*新建:张金宝 20230320 *}
{* *}
{* *}
{* *}
{* *}
{* *}
{* *}
{* *}
{* *}
{********************************************************************}
unit UntModBusBase;

interface
uses
Winapi.Windows,System.SysUtils,Classes,Winsock2;

type
TModbusClient=class
private
//连接对象
FSocket: TSocket;
protected

public
//构造函数
constructor Create();
//销毁函数
destructor Destroy();override;
//连接设备
function ConnectDev(IP:string;Port:string;var sMsg:string):Boolean;
//发送数据
function SendBytes(SendBuff:TByteArray;SendLen:Integer;var SucessLen:Integer;var sMsg:string):Boolean;
//接收数据
function RecvBytes(var RecvBuff:TByteArray;var RecvLen:Integer;var sMsg:string):Boolean;
//断开连接
function DisConnDev(var sMsg:string):Boolean;
end;
implementation
{$REGION '构造函数'}
constructor TModbusClient.Create;
begin
inherited;
end;
{$ENDREGION}

{$REGION '销毁函数'}
destructor TModbusClient.Destroy;
begin
inherited;
end;
{$ENDREGION}

{$REGION '连接设备'}
//参数说明:IP IP地址
// Port 端口号
// sMsg 错误消息
//返回值 True 成功,False 失败
function TModbusClient.ConnectDev(IP:string;Port:string;var sMsg:string):Boolean;
var
WSAData:TWSAData;//套接字实现的信息
iResult:Integer;//函数返回值
sockaddr:TSockAddr;//连接地址
begin
Result:=False;
try
//通过进程启动 Winsock DLL 的使用
iResult:=WSAStartup(MAKEWORD(2,2),WSAData);
if (iResult<>NO_ERROR) then
begin
sMsg:=Format('WSAStartup function failed with error: %d',[iResult]);
Exit;
end;
//创建socket连接服务器
FSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (FSocket = INVALID_SOCKET) then
begin
sMsg:=Format('socket function failed with error: %d',[WSAGetLastError()]);
WSACleanup();
Exit;
end;
//设置连接地址 端口
TSockAddrIn(sockaddr).sin_family := AF_INET;
TSockAddrIn(sockaddr).sin_addr.S_addr := inet_addr(PAnsiChar(AnsiString(IP)));
TSockAddrIn(sockaddr).sin_port := htons(StrToInt(Port));
//连接服务
iResult:=connect(FSocket, sockaddr, SizeOf(TSockAddrIn));
if iResult=SOCKET_ERROR then
begin
sMsg:=Format('connect function failed with error: %d',[WSAGetLastError()]);
closesocket(FSocket);
WSACleanup();
Exit;
end;
sMsg:='OK';
Result:=True;
except
on e:Exception do
begin
sMsg:='ConnectDevException:'+e.Message;
end;
end;
end;
{$ENDREGION}

{$REGION '发送数据'}
//参数说明:SendBuff 发送的数据
// SendLen 缓冲区长度
// SucessLen 发送成功的数据长度
// sMsg 错误消息
//返回值 True 成功,False 失败
function TModbusClient.SendBytes(SendBuff:TByteArray;SendLen:Integer;var SucessLen:Integer;var sMsg:string):Boolean;
var
iResult:Integer;//函数返回值
//调用方式标志
//MSG_DONTROUTE:指定数据不应受到路由的约束。 Windows 套接字服务提供程序可以选择忽略此标志。
//MSG_OOB仅) (流式套接字(例如SOCK_STREAM)发送 OOB 数据。
flags:Integer;
begin
Result:=False;
try
SucessLen:=0;
flags:=0;
//发送数据
iResult:=send(FSocket,SendBuff,SendLen,flags);
if iResult = SOCKET_ERROR then
begin
sMsg:=Format('send failed with error: %d',[WSAGetLastError()]);
Exit;
end;
SucessLen:=iResult;
sMsg:='OK';
Result:=True;
except
on e:Exception do
begin
sMsg:='SendBytesException:'+e.Message;
end;
end;
end;
{$ENDREGION}

{$REGION '接收数据'}
//参数说明:RecvBuff 接收到的数据
// RecvLen 接收到的数据长度
// sMsg 错误消息
//返回值 True 成功,False 失败
function TModbusClient.RecvBytes(var RecvBuff:TByteArray;var RecvLen:Integer;var sMsg:string):Boolean;
var
iResult:Integer;//函数返回值
//调用方式标志
//MSG_PEEK 查看传入数据。 数据将复制到缓冲区中,但不会从输入队列中删除。
//MSG_OOB 处理带外 (OOB) 数据。
//MSG_WAITALL 仅当发生以下事件之一时,接收请求才会完成:
//调用方提供的缓冲区已完全满。
//该连接已关闭。
//请求已被取消或出错。
//请注意,如果基础传输不支持MSG_WAITALL,或者套接字处于非阻塞模式,则此调用将失败并出现 WSAEOPNOTSUPP。 此外,如果指定了MSG_WAITALL以及MSG_OOB、MSG_PEEK或MSG_PARTIAL,则此调用将失败并出现 WSAEOPNOTSUPP。 数据报套接字或面向消息的套接字不支持此标志。
flags:Integer;
begin
Result:=False;
try
RecvLen:=4096;//默认4096
flags:=0;
repeat
//接收数据
iResult:=recv(FSocket, RecvBuff[0], RecvLen, flags);
until not iResult<=0;

if iResult<0 then
begin
sMsg:=Format('recv failed: %d',[WSAGetLastError()]);
Exit;
end;
RecvLen:=iResult;
sMsg:='OK';
Result:=True;
except
on e:Exception do
begin
sMsg:='RecvBytesException:'+e.Message;
end;
end;
end;

{$ENDREGION}

{$REGION '断开连接'}
//参数说明:
// sMsg 错误消息
//返回值 True 成功,False 失败
function TModbusClient.DisConnDev(var sMsg:string):Boolean;
var
iResult:Integer;//函数返回值
begin
Result:=False;
try
iResult:=closesocket(FSocket);
if iResult=SOCKET_ERROR then
begin
sMsg:=Format('closesocket function failed with error: %d',[WSAGetLastError()]);
WSACleanup();
Exit;
end;
//函数终止使用 Winsock 2 DLL
WSACleanup();
sMsg:='OK';
Result:=True;
except
on e:Exception do
begin
sMsg:='DisConnDevException:'+e.Message;
end;
end;
end;
{$ENDREGION}

end.

-------------------------------------------------------------基础单元----end-----------------------------------------------------------------------------

-------------------------------------------------------------使用-----start---------------------------------------------------------------------------------

mClient:TModbusClient;

mClient:=TModbusClient.Create;

//连接

procedure TModBusTestForm.ConnectButtonClick(Sender: TObject);
var
bRet:Boolean;//返回值
sMsg:string;//错误信息
begin
try

bRet:=mClient.ConnectDev(IPEdit.Text,PortEdit.Text,sMsg);
if bRet then
begin
StatusBar.Panels[0].Text:='连接成功';
end
else
begin
StatusBar.Panels[0].Text:='连接失败:'+sMsg;
end;

except
on e:Exception do
begin
ShowMessage('连接异常:'+e.Message);
end;
end;
end;

//断开

procedure TModBusTestForm.DisConnButtonClick(Sender: TObject);
var
bRet:Boolean;//返回值
sMsg:string;//错误信息
begin
try
bRet:=mClient.DisConnDev(sMsg);
if bRet then
begin
StatusBar.Panels[0].Text:='断开成功';
end
else
begin
StatusBar.Panels[0].Text:='断开失败:'+sMsg;
end;
except
on e:Exception do
begin
ShowMessage('断开异常:'+e.Message);
end;
end;
end;

//发送

procedure TModBusTestForm.SendButtonClick(Sender: TObject);
var
bRet:Boolean;//返回值
sMsg:string;//错误信息
SendBuff:TByteArray;//发送的报文
SendLen:Integer;//发送的报文长度
SucessLen:Integer;//发送成功的报文长度
addr:Integer;//地址
iValue:Integer;//发送的数据
RecvBuff:TByteArray;//返回的报文
RecvLen:Integer;//返回报文长度
sRet:string;//返回值
begin
try
addr:=StrToInt(SendAddrEdit.Text);
iValue:=StrToInt(SendValueEdit.Text);
SendLen:=12;
SendBuff[0] := $03;//事务处理标识符高位 客户机发起 用户定义
SendBuff[1] := $13;//事务处理标识符低位
SendBuff[2] := $00;//协议标识符高位 固定0X0000
SendBuff[3] := $00;//协议标识符低位 固定0X0000
SendBuff[4] := $00;//长度 高位
SendBuff[5] := $06;//长度 低位
SendBuff[6] := $01;//单元标识符 客户机发起 用户定义
SendBuff[7] := $06;//功能码 写入单个0x06 写入多个0x10 读取0x03
SendBuff[8] := Hi(addr);//寄存器地址高位
SendBuff[9] := Lo(addr);//寄存器地址低位
SendBuff[10] := Hi(iValue);//寄存器值 高位
SendBuff[11] := Lo(iValue);//寄存器值 低位

//sRet:=TEncoding.UTF8.GetString(SendBuff);
//sRet:=BytesToBase64(SendBuff);
bRet:=mClient.SendBytes(SendBuff,SendLen,SucessLen,sMsg);
if bRet then
begin
StatusBar.Panels[0].Text:='发送成功,报文长度:'+IntToStr(SucessLen);
//获取发送返回的报文
bRet:=mClient.RecvBytes(RecvBuff,RecvLen,sMsg);
if bRet then
begin
//返回报文转16进制
bRet:=BytesToStr(RecvBuff,RecvLen,sRet,sMsg);
if bRet then
begin
SendRetMemo.Text:=sRet;
end
else
begin
SendRetMemo.Text:='返回值转换失败:'+sMsg;
end;
end
else
begin
SendRetMemo.Text:='返回值接收失败:'+sMsg;
end;
end
else
begin
StatusBar.Panels[0].Text:='发送失败:'+sMsg;
end;
except
on e:Exception do
begin
ShowMessage('发送异常:'+e.Message);
end;
end;
end;

//接收

procedure TModBusTestForm.RecvButtonClick(Sender: TObject);
var
bRet:Boolean;//返回值
sMsg:string;//错误信息
addr:Integer;//地址
iRecvCount:Integer;//发送的数据
SendBuff:TByteArray;//发送的报文
SendLen:Integer;//发送的报文长度
SucessLen:Integer;//发送成功的报文长度
RecvBuff:TByteArray;//返回的报文
RecvLen:Integer;//返回报文长度
sRet:string;//返回值
begin
try
addr:=StrToInt(RecvAddrEdit.Text);
iRecvCount:=StrToInt(RecvCountEdit.Text);
SendLen:=12;
SendBuff[0] := $00;//事务处理标识符高位 用户定义
SendBuff[1] := $00;//事务处理标识符低位 用户定义
SendBuff[2] := $00;//协议标识符高位 固定0X0000
SendBuff[3] := $00;//协议标识符低位 固定0X0000
SendBuff[4] := $00;//长度 高位
SendBuff[5] := $06;//长度 低位
SendBuff[6] := $01;//单元标识符客户机发起 用户定义
SendBuff[7] := $03;//功能码 写入单个0x06 写入多个0x10 读取0x03
SendBuff[8] := Hi(addr);//起始地址高位
SendBuff[9] := Lo(addr);//起始地址低位
SendBuff[10] := Hi(iRecvCount);//寄存器数量高位
SendBuff[11] := Lo(iRecvCount);//寄存器数量低位
bRet:=mClient.SendBytes(SendBuff,SendLen,SucessLen,sMsg);
if bRet then
begin
//获取发送返回的报文
bRet:=mClient.RecvBytes(RecvBuff,RecvLen,sMsg);
if bRet then
begin
//返回报文转16进制
bRet:=BytesToStr(RecvBuff,RecvLen,sRet,sMsg);
if bRet then
begin
RecvMemo.Text:=sRet;
//返回值格式说明
//1 事务处理标识符 Hi
//1 事务处理标识符 Lo
//2 协议标识符号
//2 长度
//1 单元标识符
//1 功能码,读寄存器
//1 字节个数
//数据节点
end
else
begin
RecvMemo.Text:='返回值转换失败:'+sMsg;
end;
end
else
begin
RecvMemo.Text:='返回值接收失败:'+sMsg;
end;
end
else
begin
StatusBar.Panels[0].Text:='接收发送失败:'+sMsg;
end;
except
on e:Exception do
begin
ShowMessage('接收异常:'+e.Message);
end;
end;
end;

-------------------------------------------------------------使用-----end---------------------------------------------------------------------------------

标签:SendBuff,begin,end,delphi,通信,sMsg,modbus,var,Integer
From: https://www.cnblogs.com/530263009QQ/p/17413175.html

相关文章

  • OneDelphi界面美化
    使用OneDelphi已经有一段时间了,中间件的功能很强大,主要特点:●oneDelphi由OneServer中间件,OneClient控件包组成,自由免费,全源码...●oneDelphi是一个MVC+传统DATASET双架构中间件...●oneFastClient是一个快速开发传统EXE的开发包。OneDelphi的官方QQ群:814696487主界面:优化UI......
  • 车载测试系列:汽车ECU通信之时间同步测试验证
    时钟同步功能给车载系统提供统一的时间基准,在高级别智能驾驶、视音频时钟同步、数据上传分析等场景中发挥着越来越重要的作用。目前以太网时钟同步协议中,使用最多的为精准时钟同步协议(GeneralizedPrecisionTimeProtocol,gPTP),遵循IEEE802.1AS标准。在AUTOSAR中也有对应的......
  • PB6接SCL,PB7接SDA,IIC通信访问 24C02, STM32F103的HAL版本
    在野火霸道板子上,已有at24c02,256个字节。/*测试代码*/staticuint8_tflag;uint8_tdata_w[]={1,2,3,4,5};uint8_tdata_r[5]={0};AT24CXX_Init();//初始化IIC接口flag=AT24CXX_Check();//检查器件if(flag==0){u16Writ......
  • 基于算法通信过程中的常用协议介绍
    基于算法通信过程中的常用协议介绍1、HTTP(HypertextTransferProtocol):HTTP是一种应用层协议,用于客户端和服务器之间的通信。它基于请求-响应模型,通过发送HTTP请求和接收HTTP响应来进行通信。HTTP协议常用于Web应用中,可以用于传输算法请求和响应数据。2、REST(Representation......
  • delphi 写的图片合成工具---品一套图大师 v1.1.0
    在石材行业,套效果图是一个非常重要而经常要面临的工作,如果自身不懂得PS,那就需要经常去麻烦别人,而且客户可能没有办法一直在等你的效果图...基于以上的种种原因,所以就开发了这个工具,只需把图片拉到这工具,点点这个点点那,不到1分钟就可以做出漂亮的效果图~ 软件主界面: 需要套......
  • 数字通信调制方式的误码率matlab仿真,包括OOK,PRK,FSK以及QAM
    1.算法仿真效果matlab2022a仿真结果如下: 2.算法涉及理论知识概要      传输模拟信号时一样,传输数字信号时也有三种基本的调制方式:幅移键控(ASK)、频移键控(FSK)和相移键控(PSK)。它们分别对应于用载波(正弦波)的幅度、频率和相位来传递数字基带信号,可以看成是模拟线性调......
  • 数字通信调制方式的误码率matlab仿真,包括OOK,PRK,FSK以及QAM
    1.算法仿真效果matlab2022a仿真结果如下:2.算法涉及理论知识概要传输模拟信号时一样,传输数字信号时也有三种基本的调制方式:幅移键控(ASK)、频移键控(FSK)和相移键控(PSK)。它们分别对应于用载波(正弦波)的幅度、频率和相位来传递数字基带信号,可以看成是模拟线性调制和角度调制的特......
  • 微服务之间的通信方式
    目录微服务之间的通信方式根据场景选择对应的通信方式异步通信区别与选择.Net示例java示例微服务之间的通信方式微服务之间的通信方式常见的有以下几种:同步通信:微服务之间通过请求-响应的方式进行通信,例如RESTfulAPI和RPC。通信过程中,请求方需要等待响应方的返回结果,因此可靠......
  • 西门子1200plc程序实例,TCP/IP及modbus通讯,版本V15,如有需要也可代写程序。
    西门子1200plc程序实例,TCP/IP及modbus通讯,版本V15,如有需要也可代写程序。功能如下:1,西门子1200控制4台步进电机;2,西门子1200与4台MS300变频器modbus485轮询读写参数;3,西门子1200与上位机TCP/IP通讯控制相机拍照,反馈数据;4,设备为多工位联动控制;5,威纶通人机界面多画面切换可以作为参考......
  • MATLAB仿真dscdma直接序列扩频通信系统 仿真过程使用不同的扩频码对发送
    MATLAB仿真dscdma直接序列扩频通信系统仿真过程使用不同的扩频码对发送信息进行扩频,扩频码可以使m序列或Glod序列,由自己选择,扩频后的数据经过脉冲成形滤波器后通过瑞丽衰落信道同时到达接收端,在接收端分别对不同的用户信息数据进行相关解扩,恢复各个用户的原始信息。ID:6710644052......