C#實(shí)現(xiàn)上位機(jī)與歐姆龍PLC通訊(FINS)
先介紹下一些基本定義
串行通信:通過(guò)的是PLC上的串行口RS232/RS422/485口,上位機(jī)鏈接系統(tǒng) Hostlink系統(tǒng)是對(duì)于FA系統(tǒng)一種及優(yōu)化有經(jīng)濟(jì)的通信方式。
適用于一臺(tái)上位機(jī)與一臺(tái)或者多臺(tái)的PLC進(jìn)行數(shù)據(jù)通信。
通訊協(xié)議分兩種
1:C-mode commands
只可以通過(guò)串口進(jìn)行通訊
2:Fins commands
既可以通過(guò)串口通訊也可以通過(guò)各類網(wǎng)絡(luò)通訊(適應(yīng)性較強(qiáng))
本文只介紹fins通訊
fins (factory in terfave network service) 通訊協(xié)議是歐姆龍公司開(kāi)發(fā)的一款自動(dòng)化控制網(wǎng)絡(luò)指令/響應(yīng)系統(tǒng)的通訊協(xié)議;運(yùn)用FINS指令可實(shí)現(xiàn)各種網(wǎng)絡(luò)間的無(wú)縫通信
FINS幀結(jié)構(gòu)
- 發(fā)送命令結(jié)構(gòu) 命令碼2個(gè)字節(jié)
- 響應(yīng)命令結(jié)構(gòu) 命令碼2個(gè)字節(jié)
- 命令碼 01 01讀數(shù)據(jù)
- 命令碼 01 02寫數(shù)據(jù)
- 結(jié)束碼 00 00無(wú)錯(cuò)誤
1、獲取PLC節(jié)點(diǎn)地址
上位機(jī)和PLC建立TCP通訊之后,可以發(fā)送以下命令來(lái)獲得PLC的節(jié)點(diǎn)地址;
幀結(jié)構(gòu)見(jiàn)下表:
| 列表 | Content(十六進(jìn)制) | Description(說(shuō)明) |
|---|---|---|
| 頭 | 46 49 4E 53 | ASCII分別代表的是 F I N S |
| 長(zhǎng)度 | 00 00 00 0C | 從Command之后的數(shù)據(jù)包的長(zhǎng)度 |
| 錯(cuò)誤代碼 | 00 00 00 00 | 目前暫時(shí)沒(méi)用,因?yàn)樵诜?wù)器不需要檢測(cè)內(nèi)部錯(cuò)誤 |
| 連接的節(jié)點(diǎn)地址 | 00000000~000000FE | 分別是0~254,當(dāng)設(shè)置為0時(shí)表示自動(dòng)獲取客戶端的Fins節(jié)點(diǎn)地址 |
2、命令碼介紹
詳細(xì)內(nèi)容說(shuō)明介紹見(jiàn)下表:
| 命令內(nèi)容 | 命令代碼(MR SR) | 說(shuō)明 | 功能 |
|---|---|---|---|
| 訪問(wèn)I/O存儲(chǔ)區(qū) | 01 01 | 讀內(nèi)存區(qū) | 讀連續(xù)I/O存儲(chǔ)區(qū)字的內(nèi)容 |
| 訪問(wèn)I/O存儲(chǔ)區(qū) | 01 02 | 寫內(nèi)存區(qū) | 寫連續(xù)I/O存儲(chǔ)區(qū)字的內(nèi)容 |
| 訪問(wèn)I/O存儲(chǔ)區(qū) | 01 03 | 填充內(nèi)存區(qū) | 將相同的數(shù)據(jù)寫入指定范圍的I/O存儲(chǔ)器區(qū) |
| 訪問(wèn)I/O存儲(chǔ)區(qū) | 01 04 | 多個(gè)存儲(chǔ)區(qū)讀取 | 讀取指定的非連續(xù)I/O存儲(chǔ)區(qū)字 |
| 訪問(wèn)I/O存儲(chǔ)區(qū) | 01 05 | 存儲(chǔ)區(qū)傳輸 | 將連續(xù)存儲(chǔ)I/O存儲(chǔ)區(qū)字內(nèi)容復(fù)制到另外的I/O存儲(chǔ)區(qū) |
| 訪問(wèn)參數(shù)區(qū) | 02 01 | 讀取參數(shù)區(qū) | 讀取連續(xù)參數(shù)區(qū)字內(nèi)容 |
| 訪問(wèn)參數(shù)區(qū) | 02 02 | 寫入?yún)?shù)區(qū) | 寫入連續(xù)參數(shù)區(qū)字內(nèi)容 |
| 訪問(wèn)參數(shù)區(qū) | 02 03 | 填充參數(shù)區(qū) | 將相同數(shù)據(jù)寫入到指定范圍參數(shù)區(qū)域字 |
| 改變操作模式 | 04 01 | 設(shè)置CPU操作模式為RUN | 將CPU單元的操作模式更改為RUN或MONITOR |
| 改變操作模式 | 04 02 | 設(shè)置CPU操作模式為STOP | 將CPU單元的操作模式更改為編程 |
| 改變操作模式 | 06 01 | 讀取CPU單元狀態(tài) | 讀取CPU單元狀態(tài) |
| 錯(cuò)誤日志 | 21 01 | 錯(cuò)誤清除 | 清除錯(cuò)誤或錯(cuò)誤信息 |
| 錯(cuò)誤日志 | 21 02 | 讀取錯(cuò)誤日志 | 讀取錯(cuò)誤日志 |
| 錯(cuò)誤日志 | 21 03 | 清除錯(cuò)誤日志 | 清除錯(cuò)誤日志指針 |
3、I / O存儲(chǔ)器地址標(biāo)識(shí)
| 區(qū)域 | 數(shù)據(jù)類型 | 存儲(chǔ)區(qū)代碼 | 存儲(chǔ)區(qū)地址范圍 | 存儲(chǔ)地址 | 字節(jié)長(zhǎng)度 |
|---|---|---|---|---|---|
| DM | Bit | 02 | D0000000到D3276715 | 000000到7FFF0F | 1 |
| DM | Word | 82 | D00000到D32767 | 000000到7FFF00 | 2 |
鑒于我們?cè)诤蚉LC通訊時(shí),一般只需要進(jìn)行讀取DM區(qū)寄存器操作,因?yàn)楸疚闹唤榻B讀取和寫入DM區(qū)寄存器。其他的有需要的童鞋進(jìn)行自己功能拓展。
舉例:
讀取DM區(qū)地址100,連續(xù)10個(gè)地址的數(shù)據(jù)
發(fā)送命令:010182006400000A
返回命令:010100000102030405060708090A
發(fā)送的命令進(jìn)行說(shuō)明:
- 1、01 01代表功能碼,讀連續(xù)I/O存儲(chǔ)區(qū)字的內(nèi)容
- 2、82代表進(jìn)行字操作
- 3、00 64轉(zhuǎn)成十進(jìn)制就是100代表的是我們要讀取的起始地址
- 4、00000A轉(zhuǎn)成十進(jìn)制就是10代表的是我們要讀取得長(zhǎng)度
響應(yīng)的命令說(shuō)明
- 1、01 01代表功能碼,讀連續(xù)I/O存儲(chǔ)區(qū)字的內(nèi)容
- 2、00 00代表結(jié)束碼,當(dāng)不是00 00的時(shí)候表明數(shù)據(jù)幀不對(duì)
- 3、01 02 03 04 05 06 07 08 09 0A分別代表要讀取的十個(gè)寄存器的數(shù)據(jù)值
具體協(xié)議可以查看百度文庫(kù):歐姆龍fins通訊協(xié)議
綜上,結(jié)合之前的博客,C#Socket客戶端:C#Socket客戶端我們可以整合得到一個(gè)歐姆龍fins的類,如下所示:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace OmrEntFINS
{
public class OmronFINS
{
/// <summary>
/// 客戶端連接Socket
/// </summary>
private Socket clientSocket;
/// <summary>
/// 連接狀態(tài)
/// </summary>
public Boolean connected = false;
/// <summary>
/// 發(fā)送數(shù)據(jù)
/// </summary>
private Byte[] SendMess;
/// <summary>
/// 連接點(diǎn)
/// </summary>
private IPEndPoint hostEndPoint;
/// <summary>
/// 連接信號(hào)量
/// </summary>
private static AutoResetEvent autoConnectEvent = new AutoResetEvent(false);
/// <summary>
/// 接受到數(shù)據(jù)時(shí)的委托
/// </summary>
/// <param name="info"></param>
public delegate void ReceiveMsgHandler(Byte[] info);
/// <summary>
/// 接收到數(shù)據(jù)時(shí)調(diào)用的事件
/// </summary>
public event ReceiveMsgHandler OnMsgReceived;
/// <summary>
/// 開(kāi)始監(jiān)聽(tīng)數(shù)據(jù)的委托
/// </summary>
public delegate void StartListenHandler();
/// <summary>
/// 開(kāi)始監(jiān)聽(tīng)數(shù)據(jù)的事件
/// </summary>
public event StartListenHandler StartListenThread;
/// <summary>
/// 發(fā)送信息完成的委托
/// </summary>
/// <param name="successorfalse"></param>
public delegate void SendCompleted(bool successorfalse);
/// <summary>
/// 發(fā)送信息完成的事件
/// </summary>
public event SendCompleted OnSended;
/// <summary>
/// 監(jiān)聽(tīng)接收的SocketAsyncEventArgs
/// </summary>
private SocketAsyncEventArgs listenerSocketAsyncEventArgs;
int Plcport;
public OmronFINS(String hostName, Int32 port, Int32 PLCStaion)
{
Plcport = PLCStaion;
IPAddress[] addressList = Dns.GetHostAddresses(hostName);
this.hostEndPoint = new IPEndPoint(addressList[addressList.Length - 1], port);
this.clientSocket = new Socket(this.hostEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
/// <summary>
/// 連接服務(wù)端
/// </summary>
private bool Connect()
{
using (SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs())
{
connectArgs.UserToken = this.clientSocket;
connectArgs.RemoteEndPoint = this.hostEndPoint;
connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnect);
clientSocket.ConnectAsync(connectArgs);
//等待連接結(jié)果
bool autores = autoConnectEvent.WaitOne(1000);
if (this.connected)
{
listenerSocketAsyncEventArgs = new SocketAsyncEventArgs();
byte[] receiveBuffer = new byte[1024];//設(shè)置接收buffer區(qū)大小
listenerSocketAsyncEventArgs.UserToken = clientSocket;
listenerSocketAsyncEventArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
listenerSocketAsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
StartListenThread();
// SocketExtensions.SetKeepAlive(clientSocket, 3000, 1000);
return true;
}
else
return false;
}
}
/// <summary>
/// 開(kāi)始監(jiān)聽(tīng)線程的入口函數(shù)
/// </summary>
private void Listen()
{
(listenerSocketAsyncEventArgs.UserToken as Socket).ReceiveAsync(listenerSocketAsyncEventArgs);
}
public static List<SocketAsyncEventArgs> s_lst = new List<SocketAsyncEventArgs>();
/// <summary>
/// 發(fā)送信息
/// </summary>
/// <param name="message"></param>
private void Send(Byte[] message)
{
if (this.connected)
{
Byte[] sendBuffer = message;
SocketAsyncEventArgs senderSocketAsyncEventArgs = null;// new SocketAsyncEventArgs();
lock (s_lst)
{
if (s_lst.Count > 0)
{
senderSocketAsyncEventArgs = s_lst[s_lst.Count - 1];
s_lst.RemoveAt(s_lst.Count - 1);
}
}
if (senderSocketAsyncEventArgs == null)
{
senderSocketAsyncEventArgs = new SocketAsyncEventArgs();
senderSocketAsyncEventArgs.UserToken = this.clientSocket;
senderSocketAsyncEventArgs.RemoteEndPoint = this.hostEndPoint;
senderSocketAsyncEventArgs.Completed += (object sender, SocketAsyncEventArgs _e) =>
{
lock (s_lst)
{
s_lst.Add(senderSocketAsyncEventArgs);
}
};
}
senderSocketAsyncEventArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length);
clientSocket.SendAsync(senderSocketAsyncEventArgs);
}
else
{
this.connected = false;
}
SendMess = message;
}
/// <summary>
/// 斷開(kāi)連接
/// </summary>
private bool Disconnect()
{
bool returnDis = true;
try
{
this.clientSocket.Shutdown(SocketShutdown.Both);
this.clientSocket.Close();
//this.clientSocket.Dispose();
//clientSocket.Disconnect(true);
//clientSocket.Disconnect(false);
}
catch (Exception)
{
returnDis = false;
}
finally
{
}
this.connected = false;
return returnDis;
}
/// <summary>
/// 連接的完成方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnConnect(object sender, SocketAsyncEventArgs e)
{
this.connected = (e.SocketError == SocketError.Success);
autoConnectEvent.Set();
}
/// <summary>
/// 接收的完成方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnReceive(object sender, SocketAsyncEventArgs e)
{
if (e.BytesTransferred == 0)
{
//Console.WriteLine("Socket is closed", Socket.Handle);
if (clientSocket.Connected)
{
try
{
clientSocket.Shutdown(SocketShutdown.Both);
}
catch (Exception)
{
//client already closed
}
finally
{
if (clientSocket.Connected)
{
clientSocket.Close();
}
}
}
Byte[] rs = new Byte[0];
OnMsgReceived(rs);
this.connected = false;
}
else
{
byte[] buffer = new byte[e.BytesTransferred];
for (int i = 0; i < e.BytesTransferred; i++)
{
buffer[i] = e.Buffer[i];
}
this.OnMsgReceived(buffer);
Listen();
}
}
/// <summary>
/// 發(fā)送的完成方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnSend(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
OnSended(true);
}
else
{
OnSended(false);
this.ProcessError(e);
}
}
/// <summary>
/// 處理錯(cuò)誤
/// </summary>
/// <param name="e"></param>
private void ProcessError(SocketAsyncEventArgs e)
{
Socket s = e.UserToken as Socket;
if (s.Connected)
{
try
{
s.Shutdown(SocketShutdown.Both);
}
catch (Exception)
{
//client already closed
}
finally
{
if (s.Connected)
{
s.Close();
}
}
this.connected = false;
}
//throw new SocketException((Int32)e.SocketError);
}
#region IDisposable Members
public void Dispose()
{
autoConnectEvent.Close();
if (this.clientSocket.Connected)
{
this.clientSocket.Close();
}
}
#endregion
#region 歐姆龍通訊協(xié)議
/// <summary>
/// 發(fā)送命令反饋
/// </summary>
/// <param name="successorfalse"></param>
void OmronFINS_OnSended(bool successorfalse)
{
if (!successorfalse)
{
}
else
{
}
}
Byte PCS;
Byte PLCS;
int SendOrRev;
int SendOrRev2;
Byte[] SendBack;
Byte[] RecvBack;
/// <summary>
/// 接受命令反饋
/// </summary>
/// <param name="info"></param>
void OmronFINS_OnMsgReceived(byte[] info)
{
if (SendmessHas)
{
if (info.Length >= 24)
{
if (int.Parse(info[23].ToString("X").Trim(), System.Globalization.NumberStyles.HexNumber) == Plcport)
{
PCS = info[19];
PLCS = info[23];
SendmessHas = false;
}
}
}
else
{
if (info.Length > 0)//PLC連接錯(cuò)誤NO
{
if (SendOrRev2 == 1)//發(fā)送命令
{
SendBack = info;
SendOrRev2 = 0;
}
else if (SendOrRev == 2)//接受命令
{
RecvBack = info;
SendOrRev = 0;
}
}
else
{
if (SendOrRev2 == 1)//發(fā)送命令
{
SendBack = new Byte[1];
SendBack[0] = 0x00;
SendOrRev2 = 0;
}
else if (SendOrRev == 2)//接受命令
{
RecvBack = new Byte[1];
RecvBack[0] = 0x00;
SendOrRev = 0;
}
}
}
}
void OmronFINS_StartListenThread()
{
this.Listen();
}
bool SendmessHas = false;
/// <summary>
/// 打開(kāi)連接
/// </summary>
/// <returns></returns>
public bool OpenLinkPLC()
{
bool Ret = false;
this.StartListenThread += new StartListenHandler(OmronFINS_StartListenThread);
this.OnMsgReceived += new ReceiveMsgHandler(OmronFINS_OnMsgReceived);
this.OnSended += new SendCompleted(OmronFINS_OnSended);
Ret = this.Connect();
if (Ret)
{
SendmessHas = true;
this.Send(GetPCAdress());
int addNs = 0;
while (SendmessHas && addNs < 500)
{
Thread.Sleep(2);
addNs++;
}
if (addNs < 500)
{
Ret = true;
}
else
{
Ret = false;
}
}
return Ret;
}
/// <summary>
/// 關(guān)閉連接
/// </summary>
/// <returns></returns>
public bool CloseLinkPLC()
{
return this.Disconnect();
}
/// <summary>
/// 寫入值(Word)
/// </summary>
/// <param name="TypeInt">起始寄存器地址</param>
/// <param name="NumData">個(gè)數(shù)</param>
/// <param name="IntValue">值</param>
/// <returns>true,成功;false,失敗</returns>
public bool WritePlcData(string TypeInt, int NumData, ref int[] IntValue)
{
bool sendRerun = false;
if (NumData > 0)
{
Byte[] numData = BitConverter.GetBytes(NumData);//Use numData[0] and numData[1]
Byte[] SendmessAge = new Byte[34 + NumData * 2];
if (GetType(TypeInt, 0) != 0x00 && Address != null && Address.Length > 1)
{
Byte[] getSendFunc = this.SetPLCvalue(PLCS, PCS, GetType(TypeInt, 0), Address[1], Address[0], 0x00, numData[1], numData[0], NumData);
for (int i = 0; i < 34 + NumData * 2; i++)
{
if (i < 34)
{
SendmessAge[i] = getSendFunc[i];
}
else
{
if ((i - 33) % 2 != 0)
{
Byte[] BuffInvalue = BitConverter.GetBytes(IntValue[(i - 33) / 2]);
SendmessAge[i] = BuffInvalue[1];
}
else
{
Byte[] BuffInvalue = BitConverter.GetBytes(IntValue[(i - 33) / 2 - 1]);
SendmessAge[i] = BuffInvalue[0];
}
//SendmessAge[i]
}
}
SendOrRev2 = 1;
this.Send(SendmessAge);
int Outtime = 0;
while (SendOrRev2 != 0 && this.connected && Outtime < 600)
{
Thread.Sleep(2);
Outtime++;
}
if (Outtime < 600 && SendBack != null)
{
try
{
//if (SendBack.Length > 1 && SendBack[26] == 0x01 && SendBack[27] == 0x02 && SendBack[28] == 0x00 && SendBack[29] == 0x00)
//{
if (SendBack.Length > 1 && SendBack[26] == 0x01 && SendBack[27] == 0x02 && SendBack[28] == 0x00)
{
sendRerun = true;
}
else
{
sendRerun = false;
}
}
catch (Exception)
{
}
}
else
{
SendOrRev2 = 0;
}
}
}
return sendRerun;
}
/// <summary>
/// 讀取值(Word)
/// </summary>
/// <param name="TypeInt">起始寄存器地址</param>
/// <param name="NumData">個(gè)數(shù)</param>
/// <param name="IntValue">值</param>
/// <returns></returns>
public bool ReadPlcData(string TypeInt, int NumData, out int[] IntValue)
{
bool GetPlcRet = false;
IntValue = new int[1];
if (NumData > 0)
{
IntValue = new int[NumData];
Byte[] numData = BitConverter.GetBytes(NumData);//Use numData[0] and numData[1]
Byte[] RecivemessAge = new Byte[34];
if (GetType(TypeInt, 0) != 0x00 && Address != null && Address.Length > 1)
{
Byte[] getReciveFunc = this.GetPLCvalue(PLCS, PCS, GetType(TypeInt, 0), Address[1], Address[0], 0x00, numData[1], numData[0]);
this.Send(getReciveFunc);
SendOrRev = 2;
int Outtime = 0;
while (SendOrRev != 0 && this.connected && Outtime < 600)
{
Thread.Sleep(2);
Outtime++;
}
if (Outtime < 600 && RecvBack != null)
{
try
{
//if (RecvBack.Length > 1 && RecvBack[26] == 0x01 && RecvBack[27] == 0x01 && RecvBack[28] == 0x00 && RecvBack[29] == 0x00)
if (RecvBack.Length == 30 + NumData * 2 && RecvBack[26] == 0x01 && RecvBack[27] == 0x01 && RecvBack[28] == 0x00)
{
GetPlcRet = true;
for (int i = 0; i < NumData; i++)
{
IntValue[i] = int.Parse(RecvBack[30 + i * 2].ToString("X").PadLeft(2, '0') + RecvBack[30 + i * 2 + 1].ToString("X").PadLeft(2, '0'), System.Globalization.NumberStyles.HexNumber);
}
}
else
{
GetPlcRet = false;
}
}
catch (Exception)
{
}
}
else
{
SendOrRev = 0;
}
}
}
return GetPlcRet;
}
/// <summary>
/// 讀取值(Word)
/// </summary>
/// <param name="TypeInt">起始寄存器地址</param>
/// <param name="NumData">個(gè)數(shù)</param>
/// <param name="IntValue">值</param>
/// <returns></returns>
public bool ReadPlcDataCIO(string TypeInt, int NumData, out int[] IntValue)
{
bool GetPlcRet = false;
IntValue = new int[1];
if (NumData > 0)
{
IntValue = new int[NumData];
Byte[] numData = BitConverter.GetBytes(NumData);//Use numData[0] and numData[1]
Byte[] RecivemessAge = new Byte[34];
if (GetType(TypeInt, 0) != 0x00 && Address != null && Address.Length > 1)
{
Byte[] getReciveFunc = this.GetPLCvalue(PLCS, PCS, GetType(TypeInt, 0), Address[1], Address[0], 0x00, numData[1], numData[0]);
this.Send(getReciveFunc);
SendOrRev = 2;
int Outtime = 0;
while (SendOrRev != 0 & this.connected & Outtime < 800)
{
Thread.Sleep(2);
Outtime++;
}
if (Outtime < 800 && RecvBack != null)
{
//try
//{
//if (RecvBack.Length > 1 && RecvBack[26] == 0x01 && RecvBack[27] == 0x01 && RecvBack[28] == 0x00 && RecvBack[29] == 0x00)
if (RecvBack.Length > 30 && RecvBack[26] == 0x01 && RecvBack[27] == 0x01 && RecvBack[28] == 0x00)
{
GetPlcRet = true;
for (int i = 0; i < NumData; i++)
{
IntValue[i] = int.Parse(RecvBack[30 + i * 2].ToString("X").PadLeft(2, '0') + RecvBack[30 + i * 2 + 1].ToString("X").PadLeft(2, '0'), System.Globalization.NumberStyles.HexNumber);
}
}
else
{
GetPlcRet = false;
}
//}
//catch (Exception)
//{
//}
}
else
{
SendOrRev = 0;
}
}
}
return GetPlcRet;
}
/// <summary>
/// 讀取值(Bit)
/// </summary>
/// <param name="TypeInt">起始寄存器地址</param>
/// <param name="IntValue">值</param>
/// <returns></returns>
public bool ReadPlcBitData(string TypeInt, out int IntValue)
{
bool GetPlcRet = false;
IntValue = 0;
Byte[] RecivemessAge = new Byte[34];
if (GetType(TypeInt, 1) != 0x00 && Address != null && Address.Length > 1)
{
Byte[] getReciveFunc = this.GetPLCvalue(PLCS, PCS, GetType(TypeInt, 1), Address[1], Address[0], AddressBit[0]);
this.Send(getReciveFunc);
SendOrRev = 2;
int Outtime = 0;
while (SendOrRev != 0 & Outtime < 600)
{
Thread.Sleep(2);
Outtime++;
}
if (Outtime < 600)
{
if (RecvBack.Length > 1 && RecvBack[26] == 0x01 && RecvBack[27] == 0x01 && RecvBack[28] == 0x00 && RecvBack[29] == 0x00)
{
GetPlcRet = true;
IntValue = int.Parse(RecvBack[30].ToString("X").PadLeft(2, '0'), System.Globalization.NumberStyles.HexNumber);
}
}
else
{
SendOrRev = 0;
}
}
return GetPlcRet;
}
/// <summary>
/// Write值(bit)
/// </summary>
/// <param name="TypeInt">寄存器地址(CIOX.X)</param>
/// <returns></returns>
public bool WriteBitPlcData(string TypeInt, int ItemValue)
{
bool sendRerun = false;
Byte[] SendmessAge = new Byte[35];
if (GetType(TypeInt, 1) != 0x00 && Address != null && Address.Length > 1)
{
Byte[] getSendFunc = this.WritePLCBitvalue(PLCS, PCS, GetType(TypeInt, 1), Address[1], Address[0], AddressBit[0]);
for (int i = 0; i < 35; i++)
{
if (i < 32)
{
SendmessAge[i] = getSendFunc[i];
}
else if (i == 32)
{
SendmessAge[i] = 0x00;
}
else if (i == 33)
{
SendmessAge[i] = 0x01;
}
else
{
if (ItemValue == 1)
SendmessAge[i] = 0x01;
else
SendmessAge[i] = 0x00;
}
}
this.Send(SendmessAge);
SendOrRev2 = 1;
int Outtime = 0;
while (SendOrRev2 != 0 & Outtime < 600)
{
Thread.Sleep(2);
Outtime++;
}
if (Outtime < 600)
{
if (SendBack.Length > 1 && SendBack[26] == 0x01 && SendBack[27] == 0x02 && SendBack[28] == 0x00 && SendBack[29] == 0x00)
{
sendRerun = true;
}
}
else
{
SendOrRev2 = 0;
}
}
return sendRerun;
}
/// <summary>
/// Set 值(bit)
/// </summary>
/// <param name="TypeInt">寄存器地址(CIOX.X)</param>
/// <returns></returns>
public bool SetPlcData(string TypeInt)
{
bool sendRerun = false;
Byte[] SendmessAge = new Byte[35];
if (GetType(TypeInt, 1) != 0x00 && Address != null && Address.Length > 1)
{
Byte[] getSendFunc = this.SetPLCBitvalue(PLCS, PCS, GetType(TypeInt, 1), Address[1], Address[0], AddressBit[0]);
for (int i = 0; i < 35; i++)
{
if (i < 34)
{
SendmessAge[i] = getSendFunc[i];
}
else
{
SendmessAge[i] = 0x00;
}
}
this.Send(SendmessAge);
SendOrRev2 = 1;
int Outtime = 0;
while (SendOrRev2 != 0 & Outtime < 600)
{
Thread.Sleep(2);
Outtime++;
}
if (Outtime < 600)
{
if (SendBack.Length > 1 && SendBack[26] == 0x01 && SendBack[27] == 0x02 && SendBack[28] == 0x00 && SendBack[29] == 0x00)
{
sendRerun = true;
}
}
}
return sendRerun;
}
/// <summary>
/// Rest 值(bit)
/// </summary>
/// <param name="TypeInt">寄存器地址(CIOX.X)</param>
/// <returns></returns>
public bool RestPlcData(string TypeInt)
{
bool sendRerun = false;
Byte[] SendmessAge = new Byte[35];
if (GetType(TypeInt, 1) != 0x00 && Address != null && Address.Length > 1)
{
Byte[] getSendFunc = this.RstPLCBitvalue(PLCS, PCS, GetType(TypeInt, 1), Address[1], Address[0], AddressBit[0]);
for (int i = 0; i < 35; i++)
{
if (i < 34)
{
SendmessAge[i] = getSendFunc[i];
}
else
{
SendmessAge[i] = 0x00;
}
}
this.Send(SendmessAge);
SendOrRev2 = 1;
int Outtime = 0;
while (SendOrRev2 != 0 & Outtime < 600)
{
Thread.Sleep(2);
Outtime++;
}
if (Outtime < 600)
{
if (SendBack.Length > 1 && SendBack[26] == 0x01 && SendBack[27] == 0x02 && SendBack[28] == 0x00 && SendBack[29] == 0x00)
{
sendRerun = true;
}
}
}
return sendRerun;
}
Byte[] Address;
Byte[] AddressBit;
private Byte GetType(string TypeInt, int SizeofInt)
{
Byte ms = 0x00;
if (TypeInt.IndexOf("D") == 0 | TypeInt.IndexOf("d") == 0)
{
if (SizeofInt == 0)
{
ms = 0x82;
if (TypeInt.IndexOf(".") == -1)
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(1, TypeInt.Length - 1)));
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
else
{
ms = 0x02;
if (TypeInt.IndexOf(".") > 1)
{
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(1, TypeInt.IndexOf(".") - 1)));
AddressBit = BitConverter.GetBytes(int.Parse(TypeInt.Substring(TypeInt.IndexOf(".") + 1, TypeInt.Length - TypeInt.IndexOf(".") - 1)));
}
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
}
else if (TypeInt.IndexOf("CIO") == 0 | TypeInt.IndexOf("cio") == 0)
{
if (SizeofInt == 0)
{
ms = 0xB0;
if (TypeInt.IndexOf(".") == -1)
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(3, TypeInt.Length - 3)));
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
else
{
ms = 0x30;
if (TypeInt.IndexOf(".") > 3)
{
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(3, TypeInt.IndexOf(".") - 3)));
AddressBit = BitConverter.GetBytes(int.Parse(TypeInt.Substring(TypeInt.IndexOf(".") + 1, TypeInt.Length - TypeInt.IndexOf(".") - 1)));
}
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
}
else if (TypeInt.IndexOf("W") == 0 | TypeInt.IndexOf("w") == 0)
{
if (SizeofInt == 0)
{
ms = 0xB1;
if (TypeInt.IndexOf(".") == -1)
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(1, TypeInt.Length - 1)));
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
else
{
ms = 0x31;
if (TypeInt.IndexOf(".") > 1)
{
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(1, TypeInt.IndexOf(".") - 1)));
AddressBit = BitConverter.GetBytes(int.Parse(TypeInt.Substring(TypeInt.IndexOf(".") + 1, TypeInt.Length - TypeInt.IndexOf(".") - 1)));
}
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
}
else if (TypeInt.IndexOf("H") == 0 | TypeInt.IndexOf("h") == 0)
{
if (SizeofInt == 0)
{
ms = 0xB2;
if (TypeInt.IndexOf(".") == -1)
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(1, TypeInt.Length - 1)));
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
else
{
ms = 0x32;
if (TypeInt.IndexOf(".") > 1)
{
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(1, TypeInt.IndexOf(".") - 1)));
AddressBit = BitConverter.GetBytes(int.Parse(TypeInt.Substring(TypeInt.IndexOf(".") + 1, TypeInt.Length - TypeInt.IndexOf(".") - 1)));
}
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
}
else if (TypeInt.IndexOf("A") == 0 | TypeInt.IndexOf("a") == 0)
{
if (SizeofInt == 0)
{
ms = 0xB3;
if (TypeInt.IndexOf(".") == -1)
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(1, TypeInt.Length - 1)));
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
else
{
ms = 0x33;
if (TypeInt.IndexOf(".") > 1)
{
Address = BitConverter.GetBytes(int.Parse(TypeInt.Substring(1, TypeInt.IndexOf(".") - 1)));
AddressBit = BitConverter.GetBytes(int.Parse(TypeInt.Substring(TypeInt.IndexOf(".") + 1, TypeInt.Length - TypeInt.IndexOf(".") - 1)));
}
else
{
Address = new Byte[1];
AddressBit = new Byte[1];
}
}
}
return ms;
}
/// <summary>
/// Get PLC DA1 SNA1
/// </summary>
/// <returns></returns>
private Byte[] GetPCAdress()
{
Byte[] ReturnGetPC = new Byte[20];
ReturnGetPC[0] = 0x46;//f
ReturnGetPC[1] = 0x49;//i
ReturnGetPC[2] = 0x4E;//n
ReturnGetPC[3] = 0x53;//s
ReturnGetPC[4] = 0x00;
ReturnGetPC[5] = 0x00;
ReturnGetPC[6] = 0x00;
ReturnGetPC[7] = 0x0C;
ReturnGetPC[8] = 0x00;
ReturnGetPC[9] = 0x00;
ReturnGetPC[10] = 0x00;
ReturnGetPC[11] = 0x00;
ReturnGetPC[12] = 0x00;
ReturnGetPC[13] = 0x00;
ReturnGetPC[14] = 0x00;
ReturnGetPC[15] = 0x00;
ReturnGetPC[16] = 0x00;
ReturnGetPC[17] = 0x00;
ReturnGetPC[18] = 0x00;
ReturnGetPC[19] = 0x00;
return ReturnGetPC;
}
/// <summary>
/// Read Word
/// </summary>
/// <param name="DA1"></param>
/// <param name="SA1"></param>
/// <param name="DataValue"></param>
/// <param name="Address1"></param>
/// <param name="Address2"></param>
/// <param name="Address3"></param>
/// <param name="DataNum1"></param>
/// <param name="DataNum2"></param>
/// <returns></returns>
private Byte[] GetPLCvalue(Byte DA1, Byte SA1, Byte DataValue, Byte Address1, Byte Address2, Byte Address3, Byte DataNum1, Byte DataNum2)
{
Byte[] SendFun = new Byte[34];
SendFun[0] = 0x46;
SendFun[1] = 0x49;
SendFun[2] = 0x4E;
SendFun[3] = 0x53;
SendFun[4] = 0x00;
SendFun[5] = 0x00;
SendFun[6] = 0x00;
SendFun[7] = 0x1A;
SendFun[8] = 0x00;
SendFun[9] = 0x00;
SendFun[10] = 0x00;
SendFun[11] = 0x02;
SendFun[12] = 0x00;
SendFun[13] = 0x00;
SendFun[14] = 0x00;
SendFun[15] = 0x00;
SendFun[16] = 0x80;
SendFun[17] = 0x00;
SendFun[18] = 0x02;
SendFun[19] = 0x00;
SendFun[20] = DA1;
SendFun[21] = 0x00;
SendFun[22] = 0x00;
SendFun[23] = SA1;
SendFun[24] = 0x00;
SendFun[25] = 0x01;
SendFun[26] = 0x01;
SendFun[27] = 0x01;
SendFun[28] = DataValue;
SendFun[29] = Address1;
SendFun[30] = Address2;
SendFun[31] = Address3;
SendFun[32] = DataNum1;
SendFun[33] = DataNum2;
return SendFun;
}
/// <summary>
/// Write Word
/// </summary>
/// <param name="DA1"></param>
/// <param name="SA1"></param>
/// <param name="DataValue"></param>
/// <param name="Address1"></param>
/// <param name="Address2"></param>
/// <param name="Address3"></param>
/// <param name="DataNum1"></param>
/// <param name="DataNum2"></param>
/// <returns></returns>
private Byte[] SetPLCvalue(Byte DA1, Byte SA1, Byte DataValue, Byte Address1, Byte Address2, Byte Address3, Byte DataNum1, Byte DataNum2, int num)
{
Byte[] SendFun = new Byte[34];
SendFun[0] = 0x46;
SendFun[1] = 0x49;
SendFun[2] = 0x4E;
SendFun[3] = 0x53;
SendFun[4] = 0x00;
SendFun[5] = 0x00;
SendFun[6] = 0x00;
SendFun[7] = (byte)(26 + 2 * num);
SendFun[8] = 0x00;
SendFun[9] = 0x00;
SendFun[10] = 0x00;
SendFun[11] = 0x02;
SendFun[12] = 0x00;
SendFun[13] = 0x00;
SendFun[14] = 0x00;
SendFun[15] = 0x00;
SendFun[16] = 0x80;
SendFun[17] = 0x00;
SendFun[18] = 0x02;
SendFun[19] = 0x00;
SendFun[20] = DA1;
SendFun[21] = 0x00;
SendFun[22] = 0x00;
SendFun[23] = SA1;
SendFun[24] = 0x00;
SendFun[25] = 0x01;
SendFun[26] = 0x01;
SendFun[27] = 0x02;
SendFun[28] = DataValue;
SendFun[29] = Address1;
SendFun[30] = Address2;
SendFun[31] = Address3;
SendFun[32] = DataNum1;
SendFun[33] = DataNum2;
return SendFun;
}
/// <summary>
/// Read Bit
/// /// </summary>
/// <param name="DA1"></param>
/// <param name="SA1"></param>
/// <param name="DataValue"></param>
/// <param name="Address1"></param>
/// <param name="Address2"></param>
/// <param name="Address3"></param>
/// <param name="DataNum1"></param>
/// <param name="DataNum2"></param>
/// <returns></returns>
private Byte[] GetPLCvalue(Byte DA1, Byte SA1, Byte DataValue, Byte Address1, Byte Address2, Byte Address3)
{
Byte[] SendFun = new Byte[34];
SendFun[0] = 0x46;
SendFun[1] = 0x49;
SendFun[2] = 0x4E;
SendFun[3] = 0x53;
SendFun[4] = 0x00;
SendFun[5] = 0x00;
SendFun[6] = 0x00;
SendFun[7] = 0x1A;
SendFun[8] = 0x00;
SendFun[9] = 0x00;
SendFun[10] = 0x00;
SendFun[11] = 0x02;
SendFun[12] = 0x00;
SendFun[13] = 0x00;
SendFun[14] = 0x00;
SendFun[15] = 0x00;
SendFun[16] = 0x80;
SendFun[17] = 0x00;
SendFun[18] = 0x02;
SendFun[19] = 0x00;
SendFun[20] = DA1;
SendFun[21] = 0x00;
SendFun[22] = 0x00;
SendFun[23] = SA1;
SendFun[24] = 0x00;
SendFun[25] = 0x01;
SendFun[26] = 0x01;
SendFun[27] = 0x01;
SendFun[28] = DataValue;
SendFun[29] = Address1;
SendFun[30] = Address2;
SendFun[31] = Address3;
SendFun[32] = 0x00;
SendFun[33] = 0x01;
return SendFun;
}
/// <summary>
/// Write Bit
/// </summary>
/// <param name="DA1"></param>
/// <param name="SA1"></param>
/// <param name="DataValue"></param>
/// <param name="Address1"></param>
/// <param name="Address2"></param>
/// <param name="Address3"></param>
/// <returns></returns>
private Byte[] WritePLCBitvalue(Byte DA1, Byte SA1, Byte DataValue, Byte Address1, Byte Address2, Byte Address3)
{
Byte[] SendFun = new Byte[32];
SendFun[0] = 0x46;
SendFun[1] = 0x49;
SendFun[2] = 0x4E;
SendFun[3] = 0x53;
SendFun[4] = 0x00;
SendFun[5] = 0x00;
SendFun[6] = 0x00;
SendFun[7] = 0x1B;
SendFun[8] = 0x00;
SendFun[9] = 0x00;
SendFun[10] = 0x00;
SendFun[11] = 0x02;
SendFun[12] = 0x00;
SendFun[13] = 0x00;
SendFun[14] = 0x00;
SendFun[15] = 0x00;
SendFun[16] = 0x80;
SendFun[17] = 0x00;
SendFun[18] = 0x02;
SendFun[19] = 0x00;
SendFun[20] = DA1;
SendFun[21] = 0x00;
SendFun[22] = 0x00;
SendFun[23] = SA1;
SendFun[24] = 0x00;
SendFun[25] = 0x01;
SendFun[26] = 0x01;
SendFun[27] = 0x02;
SendFun[28] = DataValue;
SendFun[29] = Address1;
SendFun[30] = Address2;
SendFun[31] = Address3;
return SendFun;
}
/// <summary>
/// Set Bit
/// </summary>
/// <param name="DA1"></param>
/// <param name="SA1"></param>
/// <param name="DataValue"></param>
/// <param name="Address1"></param>
/// <param name="Address2"></param>
/// <param name="Address3"></param>
/// <returns></returns>
private Byte[] SetPLCBitvalue(Byte DA1, Byte SA1, Byte DataValue, Byte Address1, Byte Address2, Byte Address3)
{
Byte[] SendFun = new Byte[35];
SendFun[0] = 0x46;
SendFun[1] = 0x49;
SendFun[2] = 0x4E;
SendFun[3] = 0x53;
SendFun[4] = 0x00;
SendFun[5] = 0x00;
SendFun[6] = 0x00;
SendFun[7] = 0x1B;
SendFun[8] = 0x00;
SendFun[9] = 0x00;
SendFun[10] = 0x00;
SendFun[11] = 0x02;
SendFun[12] = 0x00;
SendFun[13] = 0x00;
SendFun[14] = 0x00;
SendFun[15] = 0x00;
SendFun[16] = 0x80;
SendFun[17] = 0x00;
SendFun[18] = 0x02;
SendFun[19] = 0x00;
SendFun[20] = DA1;
SendFun[21] = 0x00;
SendFun[22] = 0x00;
SendFun[23] = SA1;
SendFun[24] = 0x00;
SendFun[25] = 0x01;
SendFun[26] = 0x23;
SendFun[27] = 0x01;
SendFun[28] = 0x01;
SendFun[29] = 0x00;
SendFun[30] = 0x01;
SendFun[31] = DataValue;
SendFun[32] = Address1;
SendFun[33] = Address2;
SendFun[34] = Address3;
return SendFun;
}
/// <summary>
/// RST Bit
/// </summary>
/// <param name="DA1"></param>
/// <param name="SA1"></param>
/// <param name="DataValue"></param>
/// <param name="Address1"></param>
/// <param name="Address2"></param>
/// <param name="Address3"></param>
/// <returns></returns>
private Byte[] RstPLCBitvalue(Byte DA1, Byte SA1, Byte DataValue, Byte Address1, Byte Address2, Byte Address3)
{
Byte[] SendFun = new Byte[35];
SendFun[0] = 0x46;
SendFun[1] = 0x49;
SendFun[2] = 0x4E;
SendFun[3] = 0x53;
SendFun[4] = 0x00;
SendFun[5] = 0x00;
SendFun[6] = 0x00;
SendFun[7] = 0x1B;
SendFun[8] = 0x00;
SendFun[9] = 0x00;
SendFun[10] = 0x00;
SendFun[11] = 0x02;
SendFun[12] = 0x00;
SendFun[13] = 0x00;
SendFun[14] = 0x00;
SendFun[15] = 0x00;
SendFun[16] = 0x80;
SendFun[17] = 0x00;
SendFun[18] = 0x02;
SendFun[19] = 0x00;
SendFun[20] = DA1;
SendFun[21] = 0x00;
SendFun[22] = 0x00;
SendFun[23] = SA1;
SendFun[24] = 0x00;
SendFun[25] = 0x01;
SendFun[26] = 0x23;
SendFun[27] = 0x01;
SendFun[28] = 0x01;
SendFun[29] = 0x00;
SendFun[30] = 0x00;
SendFun[31] = DataValue;
SendFun[32] = Address1;
SendFun[33] = Address2;
SendFun[34] = Address3;
return SendFun;
}
#endregion
}
}至此,我們就可以用上述的類和歐姆龍PLC進(jìn)行FINS通訊。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#之Windows自帶打印功能的實(shí)現(xiàn)
這篇文章主要介紹了C#之Windows自帶打印功能的實(shí)現(xiàn)方式,具有很好的價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
C#實(shí)現(xiàn)手機(jī)拍照并且保存水印照片
這篇文章主要介紹了C#實(shí)現(xiàn)手機(jī)拍照并且保存水印照片的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11
C#中Timer實(shí)現(xiàn)Tick使用精度的問(wèn)題
這篇文章主要介紹了C#中Timer實(shí)現(xiàn)Tick使用精度的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08

