begin是什么意思(工业控制)
admin
2023-09-11 07:27:00
0

一.串口通讯方式

首先,串口、UART口、COM口、USB口是指的物理接口形式(硬件)。而TTL、RS-232、RS-485是指的电平标准(电信号)。

串口:串口是一个统称。UART、TTL、RS232、RS485都遵循类似的通信时序协议,所以都称为串口。

:RS232RS485,工业控制中的通用协议

RS232:是电子工业协会(EIA)制定的异步传输标准接口,同时对应着电平标准和通信协议(时序)。它的电平标准:3V~ 15V对应0,-3v ~-15v对应1。rs232的逻辑电平与TTL不同,但协议相同。

RS485:RS485是一种串行端口接口标准。对于远距离传输,采用差分传输,传输的是差分信号,抗干扰能力比RS232强很多。两条线的压差为-(2~6)V为0,两条线的压差为(2~6)V为1。

常见的D型9针串口(通俗说法)。在台式电脑后边都可以看到。这种接口的协议只有两种:RS-232和RS-485

二.网口通讯方式

TCP/IP是各种互联网相关协议族的总称,如TCP、UDP、IP、FTP、HTTP、ICMP、SMTP等。像这样组装与互联网相关的协议总是被称为TCP/IP。也有人说TCP/IP指的是TCP和IP。还有一种说法是TCP/IP是IP协议在通信过程中使用的协议族的总称。

工业控制中常用的通信是TCP和UDP.

当需要在传输层实现可靠传输时,使用这两个区别就是:TCP。因为它是面向链路的,具有顺序控制和重传控制等机制,所以可以为应用程序提供可靠的传输。一方面,UDP主要用于需要高速传输和实时性的通信或广播通信。让我们举一个通过IP电话打电话的例子。如果使用TCP,数据在传输过程中如果丢失会重新传输,但是呼叫者的语音无法顺利传输,会导致正常通信失败。有了UDP,他就不转发了。所以不会有声音大幅度延迟的问题。即使丢失了一些数据,也支持影响一小部分的呼叫。此外,在多播和广播通信中使用UDP代替TCP。

三.确定PLC硬件

首先要确定PLC支持网口还是串口通信,大部分支持RS232、TCP或者UDP,有的可能需要购买扩展模块进行通信。

四.确定PLC通信协议

通信协议:是指两个实体在完成通信或服务时必须遵循的规则和协议。通过通信信道和设备互连的位于不同地理位置的多个数据通信系统如果要一起工作以实现信息交换和资源共享就必须有一种共同的语言。交流什么,怎么交流,什么时候交流,都要遵循一些双方都能接受的规则。这个规则就是通信协议。

以欧姆龙FINS通讯协议为例。

首先,握手命令

1.客户端向服务器发送命令00000000。该命令长20字节,分为5组,每组4字节。分别是:FINS长度(Hex0C)命令(00000000)错误码(00000000)客户端节点地址。

46494E53是FINS的ASCII码值,是命令头。

0000000C是命令长度20。

000000000是命令代码。

000000000是一个错误代码。

00000005是客户端节点地址,它是计算机IP地址的最后一位。

在发送区输入:46494 e 5300000000000000000000000000000000000005。

点击发送,PLC会立即响应:46494 e 5300000001000000000000000000005000000000020。

至此我们已经成功完成了第一步!接下来需要的是之前介绍的HostLink协议中FINS的知识。

图3。网络调试助手握手成功。2、,这是服务器端(PLC)向客户端(电脑)发送's订单00000001。该命令长24字节,分为6组,每组4字节。分别是:header(FINS)length(hex 10)command(00000001)错误码客户端节点地址服务器地址。

上述命令错误代码为0,客户端ip地址05已被服务器32成功记录(hex20)。

如果出现错误,服务器响应的命令将包含一个错误代码,连接将被断开,端口将立即关闭。连接建立后,不要再发送这个命令,否则服务器会返回03错误代码,这是一个不支持的命令。所有错误代码如下:

十六进制错误代码含义

000000000正常

000000001标题不是“fins”(ascii码)。

数据太长。

00000003不支持的命令。

00000020所有连接都被占用。


00000021制定的节点已经连接。
00000022未被指定的IP地址试图访问一个被保护的节点。
00000023客户端FINS节点地址超范围。
00000024相同的FINS节点地址已经被使用。
00000025所有可用的节点地址都已使用。
二、FINS帧发送命令
如果向服务器发送FINS帧,就要用到这个命令。由于FINS帧长度是12-2012,因此命令长度可变,
头(FINS)+长度+命令(00000002)+错误码+FINS帧。
FINS命令帧内容可参考欧姆龙OMRONPLC之HostLink通讯协议-FINS命令W字/位操作篇,里面有存储区代码和操作代码的内容。
例2-1、读DM0开始的2个通道:
发送:
46494E530000001A0000000200000000800002002000000500FF0101820000000002
20000005:20是目标地址,05是源地址;
00FF0101:0101是读操作;
82000000:82是DM存储区代码,000000是起始地址;
0002:是数量。
返回:
46494E530000001A0000000200000000C00002000500002000FF0101000012345678
00001234:0000代表操作成功,1234是读回的第一个字,即D0=Hex1234,
5678:D1=Hex5678

例2-2、W210寄存器写入Hex0388:
发送:
46494E530000001C0000000200000000800002002000000500FF0102B100D20000010388
20000005:20是目标地址,05是源地址;
00FF0102:0102是写操作代码;
B100D200:B1是W字代码,00D2是起始地址,Hex00D2=212,;
00010388:是写入数量,0388是写入首个内容;
回应:
46494E53000000160000000200000000C00002000500002000FF01020000
0102后面紧跟的0000代表写入成功。
例2-3、W210寄存器读取:
发送:
46494E530000001A0000000200000000800002002000000500FF0101B100D2000001
20000005:20是目标地址,05是源地址;
00FF0101:0101是读操作代码;
B100D200:B1是W字代码,00D2是起始地址,Hex00D2=212,;
0001:是读取数量。
回应:
46494E53000000180000000200000000C00002000500002000FF010100000388
0102后面紧跟的0000代表读取成功,W210=Hex0388
例2-4、强制W212.01=On:
发送:
46494E530000001C0000000200000000800002002000000500FF2301000100013100D401
20000005:20是目标地址,05是源地址;
00FF2301:2301是强制操作代码;
00010001:前面的0001是数量,后面的0001代表强制置位操作;
3100D401:31是W位代码,00D401是起始地址,Hex00D4.01=212.01。
回应:
46494E53000000160000000200000000C00002000500002000FF23010000
2301后面紧跟的0000表示操作成功。
注意在CX-Programmer查看窗口中W212.01的值1后面的(强制)字样。

图4网络调试助手强制置位

图5CX-Programmer强制置位成功
例2-5、强制W212.01=Off:
发送:
46494E530000001C0000000200000000800002002000000500FF2301000100003100D401
20000005:20是目标地址,05是源地址;
00FF2301:2301是强制操作代码;
00010000:0001是数量,0000代表强制复位操作;
3100D401:31是W位代码,00D401是起始地址,Hex00D4.01=212.01。
回应:
46494E53000000160000000200000000C00002000500002000FF23010000
2301后面紧跟的0000表示操作成功。
例2-6、取消W212.01强制:
发送:
46494E530000001C0000000200000000800002002000000500FF23010001FFFF3100D401
20000005:20是目标地址,05是源地址;
00FF2301:2301是强制操作代码;
0001FFFF:0001是数量,FFFF代表取消强制操作;
3100D401:31是W位代码,00D401是起始地址,Hex00D4.01=212.01。
回应:
46494E53000000160000000200000000C00002000500002000FF23010000
2301后面紧跟的0000表示操作成功。
注意在CX-Programmer查看窗口中W212.01的值0后面的(强制)字样不见了,表示已经成功地取消了强制。

图6网络调试助手取消强制


图7CX-Programmer取消强制成功

与CIO不同,对于W、A、H及D这样的寄存器进行位操作,其实不用强制操作,直接写入更简洁,可以减少操作步骤,下面以W位操作为例介绍。

例2-7、W212.01按位置位:

发送:
46494E530000001B0000000200000000800002002000000500FF01023100D401000101
20000005:20是目标地址,05是源地址;
00FF0102:0102是寄存器写操作代码;
3100D401:31是W位代码,00D401是地址,Hex00D4.01=212.01;

000101:0001是数量,01代表写入值1;
回应:

46494E53000000160000000200000000C00002002000000500FF01020000

0102后面紧跟的0000表示操作成功。

例2-8、W212.01按位复位:
发送:
46494E530000001B0000000200000000800002002000000500FF01023100D401000100

20000005:20是目标地址,05是源地址;
00FF0102:0102是寄存器写操作代码;
3100D401:31是W位代码,00D401是地址,Hex00D4.01=212.01;

000100:0001是数量,00代表写入值0;

回应:

46494E53000000160000000200000000C00002002000000500FF01020000

0102后面紧跟的0000表示操作成功。

五.使用C#进行通信

1.串口

串口在C#中使用的是SerialPort这个类

要注意通讯协议中报文内容是16进制,还是ASCII码,还是就是普通的字符串,有格式的话注意发送和接收的报文需要转换

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.IO.Ports;usingSystem.Threading;usingSystem.Windows.Forms;publicclassSerialOP:IDisposable{privateSerialPortComport=newSerialPort();privateAutoResetEvent_manualEvent=newAutoResetEvent(false);privateobject_lockRead=newobject();privateobject_lockWrite=newobject();privatebyte[]_reivedData;privatestringreive=null;privateobjectonRecive=newobject();publicdelegatevoidUpdateByteDelegate(byte[]reive);publiceventUpdateByteDelegateUpdateByte;//////打开串口//////////////////publicboolOpen(stringcom,stringbps,stringdatabit,stringstopbit,stringcheck){try{if(Comport.IsOpen)Comport.Close();Thread.Sleep(100);//串口端口号Comport.PortName=com;//串口波特率Comport.BaudRate=int.Parse(bps);//串口数据位Comport.DataBits=int.Parse(databit);//串口停止位switch(stopbit){case"0":Comport.StopBits=StopBits.None;break;case"1":Comport.StopBits=StopBits.One;break;case"1.5":Comport.StopBits=StopBits.OnePointFive;break;case"2":Comport.StopBits=StopBits.Two;break;default:Comport.StopBits=StopBits.None;break;}//串口奇偶校验switch(check){case"无":Comport.Parity=Parity.None;break;case"奇校验":Comport.Parity=Parity.Odd;break;case"偶校验":Comport.Parity=Parity.Even;break;default:Comport.Parity=Parity.None;break;}//Comport.ReceivedBytesThreshold=1;//1字节触发数据获取//Comport.DataReceived+=newSerialDataReceivedEventHandler(OnReceived);Comport.Open();Comport.DtrEnable=true;Comport.RtsEnable=true;returntrue;}catch(Exceptionex){LogHelper.error(ex.ToString());MessageBox.Show("连续打开关闭串口出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);returnfalse;}}//////检测串口是否打开//////privateboolIsOpen(){try{if(Comport==null)returnfalse;if(Comport.IsOpen)returntrue;elsereturnfalse;}catch(Exceptionex){LogHelper.error(ex.ToString());MessageBox.Show("检测串口是否打开出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);returnfalse;}}privatevoidOnReceived(objectsender,SerialDataReceivedEventArgse){try{lock(onRecive){byte[]reive=newbyte[Comport.BytesToRead];Comport.Read(reive,0,Comport.BytesToRead);UpdateByte.Invoke(reive);}}catch(Exceptionex){LogHelper.error(ex.ToString());MessageBox.Show("串口接收数据出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}finally{_manualEvent.Set();}}//////字符串转ASII码发送//////publicvoidSend_ASCII(stringstr){try{lock(_lockWrite){varByteSendW=Encoding.ASCII.GetBytes(str);//把发送数据转换为ASCII数组Comport.Write(ByteSendW,0,ByteSendW.Length);}}catch(Exceptionex){LogHelper.error(ex.ToString());MessageBox.Show("串口发送数据出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}}//////发送16进制数组,需要用,隔开/////////publicvoidSend_HEX(stringHex){try{lock(_lockWrite){//16进制字符串转换成16进制数组varHEX=Hex.Split(',').Select(temp=>"0x"+temp).Select(temp=>(byte)Convert.ToInt32(temp,16)).ToArray();Comport.Write(HEX,0,HEX.Length);}}catch(Exceptionex){LogHelper.error(ex.ToString());MessageBox.Show("串口发送数据出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}}//////发送字符串不转换//////publicvoidSend_String(stringstr){try{lock(_lockWrite){Comport.Write(str);}}catch(Exceptionex){LogHelper.error(ex.ToString());MessageBox.Show("串口发送数据出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}}//////接收ASCII码,并转换成字符串//////publicvoidRead_ASCII(outstringstr){str="error";try{lock(_lockRead){if(Comport.BytesToRead==0){LogHelper.error("缓存区没有数据");return;}for(inti=0;i<100;i++)//读取100个字节{if(Comport.BytesToRead==0){str=reive;reive=null;break;}stringreivestring="";_reivedData=newbyte[1];Comport.Read(_reivedData,0,_reivedData.Length);reivestring=Encoding.ASCII.GetString(_reivedData);reive+=reivestring;//Comport.DiscardInBuffer();}}}catch(Exceptionex){str=ex.ToString();LogHelper.error(ex.ToString());MessageBox.Show("串口读取数据出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}}//////接收字符串,不进行任何转换//////publicvoidRead_String(outstringstr){str="error";try{lock(_lockRead){if(Comport.BytesToRead==0){LogHelper.error("缓存区没有数据");return;}for(inti=0;i<100;i++)//读取100个字节{if(Comport.BytesToRead==0){str=reive;reive=null;break;}_reivedData=newbyte[1];Comport.Read(_reivedData,0,_reivedData.Length);reive+=_reivedData[0].ToString()+"";}}}catch(Exceptionex){str=ex.ToString();LogHelper.error(ex.ToString());MessageBox.Show("串口读取数据出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}}//////接收到16进制,转成字符串//////publicvoidRead_HEX_String(outstringstr){str="error";try{lock(_lockRead){if(Comport.BytesToRead==0){LogHelper.error("缓存区没有数据");return;}for(inti=0;i<100;i++)//读取100个字节{if(Comport.BytesToRead==0){reive=reive.Substring(0,reive.Length-1);//移除最后一位逗号str=reive;reive=null;break;}_reivedData=newbyte[1];Comport.Read(_reivedData,0,_reivedData.Length);reive+=_reivedData[0].ToString("x2").ToUpper()+",";}}}catch(Exceptionex){str=ex.ToString();LogHelper.error(ex.ToString());MessageBox.Show("串口读取数据出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}}//////关闭串口///publicvoidClose(){try{if(Comport.IsOpen)Comport.Close();}catch(Exceptionex){LogHelper.error(ex.ToString());MessageBox.Show("关闭串口出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}}//////释放串口///publicvoidDispose(){try{if(Comport.IsOpen)Comport.Close();Comport.Dispose();}catch(Exceptionex){LogHelper.error(ex.ToString());MessageBox.Show("释放串口出现错误:"+ex.Message,"SerialPort---Message",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1,MessageBoxOptions.DefaultDesktopOnly);}//Comport.DataReceived-=newSerialDataReceivedEventHandler(Comport_DataReceived);}//////CRC16校验/////////publicstringCRCCalc(stringdata){string[]datas=data.Split('');Listbytedata=newList();foreach(stringstrindatas){bytedata.Add(byte.Parse(str,System.Globalization.NumberStyles.AllowHexSpecifier));}byte[]crcbuf=bytedata.ToArray();//计算并填写CRC校验码intcrc=0xffff;intlen=crcbuf.Length;for(intn=0;n>1;crc=crc&0x7fff;if(TT==1){crc=crc^0xa001;}crc=crc&0xffff;}}string[]redata=newstring[2];redata[1]=Convert.ToString((byte)((crc>>8)&0xff),16);redata[0]=Convert.ToString((byte)((crc&0xff)),16);returnredata[0].ToUpper()+""+redata[1].ToUpper();}}

2.网口

网口分客户端和服务器,协议有TCP和UDP

以下以TCP为例

TCP客户端

publicclassTcpClient{publicboolconnected=false;SocketsocketClient;//客户端接口TaskthreadAcceptClient,//客户端接收线程threadClient;//客户端线程privatestringIpAddress=string.Empty;privateintPort=0;publicTcpClient(stringIpAddress,intPort){this.IpAddress=IpAddress;this.Port=Port;ClientConnectSever();}//////客户端连接服务器///publicboolClientConnectSever(){IPAddressip=IPAddress.Parse(IpAddress);IPEndPointport=newIPEndPoint(ip,Port);//服务器port//创建TCP类型端口socketClient=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);try{socketClient.Connect(port);connected=true;returntrue;}catch(Exceptionex){LogHelper.error(IpAddress+"连接服务器失败:"+ex.Message);returnfalse;}}publicvoidColseConnect(){socketClient.Close();}publicboolClientSendData(stringdata){if(!connected){LogHelper.error(IpAddress+"未连接到服务器");returnfalse;}byte[]msg=Encoding.Default.GetBytes(data);try{NetworkStreamnetStream=newNetworkStream(socketClient);netStream.Write(msg,0,msg.Length);netStream.Flush();returntrue;}catch(Exceptionex){LogHelper.error(IpAddress+"发送失败:"+ex.Message);returnfalse;}}publicstringClientReadData(){try{if(!connected){LogHelper.error(IpAddress+"未连接到服务器");return"error";}NetworkStreamnetStream=newNetworkStream(socketClient);byte[]dataSize=newbyte[1024];netStream.Read(dataSize,0,dataSize.Length);varResult=Encoding.Default.GetString(dataSize).TrimEnd('\0');if(Result.Length>1)returnResult;elsereturnstring.Empty;//this.rtb_accept1.Rtf=Encoding.Unicode.GetString(message);}catch(Exceptionex){LogHelper.error(IpAddress+"读取数据失败:"+ex.Message);return"error";}}}

TCP服务器

publicclassTcpServer{publicdelegatevoidUpdateObjectDelegate(objectsender);publiceventUpdateObjectDelegateUpdataDataString;publiceventUpdateObjectDelegateUpdateMessage;privatestringIpAddress=string.Empty;privateintPort=0;publicTcpServer(stringIpAddress,intPort){this.IpAddress=IpAddress;this.Port=Port;}staticSocketserverSocket;ListClientList=newList();//客户端列表publicboolconnected=false;publicvoidStartListen(){Socketsocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);serverSocket=socket;//ipportsocket.Bind(newIPEndPoint(IPAddress.Parse(IpAddress),Port));//listensocket.Listen(10);//连接等待队列ThreadPool.QueueUserWorkItem(newWaitCallback(this.AcceptClientConnect),socket);}privatevoidAcceptClientConnect(objectsocket){varserverSocket=socketasSocket;UpdateMessage.Invoke("服务器开始监听");while(true){try{varproxSocket=serverSocket.Accept();ClientList.Add(proxSocket);UpdateMessage.Invoke((object)("客户端"+proxSocket.RemoteEndPoint.ToString()+"连接上了"));//接受消息ThreadPool.QueueUserWorkItem(newWaitCallback(this.ReceiveData),proxSocket);connected=true;}catch(Exceptione){UpdateMessage.Invoke("服务器监听错误:"+e.ToString());connected=false;}}}privatevoidReceiveData(objectobj){SocketproxSocket=objasSocket;byte[]data=newbyte[1024*1024];while(true){intreadLen=0;try{readLen=proxSocket.Receive(data,data.Length,0);//if(readLen<=0)//{////客户端正常退出//UpdateMessage.Invoke(string.Format("客户端{0}正常退出",proxSocket.RemoteEndPoint.ToString()));//ClientList.Remove(proxSocket);//CloseListen(proxSocket);//connected=false;//return;//方法结束->终结当前接受客户端数据的异步线程//}stringtxt=Encoding.Default.GetString(data,0,readLen).TrimEnd('\0');if(txt.Length>1)UpdataDataString.Invoke(txt);}catch(Exceptionex){//异常退出时UpdateMessage.Invoke(string.Format("客户端{0}非正常退出,原因{1}",proxSocket.RemoteEndPoint.ToString(),ex.ToString()));ClientList.Remove(proxSocket);CloseListen(proxSocket);connected=false;return;}}}privatevoidCloseListen(SocketproxSocket){try{if(proxSocket.Connected){proxSocket.Shutdown(SocketShutdown.Both);proxSocket.Close(100);connected=false;}}catch(Exception){UpdateMessage("服务器关闭发生异常");connected=false;}}publicboolServerSendData(stringmsg){try{foreach(Socketsinthis.ClientList){//服务端广播式发送给客户端(sasSocket).Send(Encoding.Default.GetBytes(msg));}returntrue;}catch{returnfalse;}}}

相关内容

热门资讯

(辅助挂版本)大凉山生活破解器... 大凉山生活破解器【各.种.外.挂】【:5415480必赢分享“大凉山生活破解器有挂没有挂吗”透视辅助...
新道游金花房卡怎么购买☹️获... 新道游金花房卡怎么购买☹️获取房卡教程 新道游反杀挂大厅房卡咨询微信号:【215338558】无需打...
重大通报“新牛魔王是不是有透视... 您好:新牛魔王这款游戏可以开挂,确实是有挂的,需要软件加微信【8700483】,很多玩家在新牛魔王这...
良心推荐“青鸟大厅房卡游戏挂... 良心推荐“青鸟大厅房卡游戏挂??房卡游戏代理 新道游反杀挂大厅房卡咨询微信号:【215338558】...
(辅助挂分享)小南长牌透视脚本... 小南长牌透视脚本【各.种.外.挂】【:5415480必赢分享“小南长牌透视脚本有挂没有挂吗”透视辅助...