我希望就是給我一個用C#來反映PLC的代碼!控制X和Y protected int BytesToRead = 0; protected int ReadStart = 0; protected char[] ReadBuffer = new char[1000]; Port = new SerialPort(COMPort, BaudRate, Parity, DataBit, StopBit); Port.DataReceived += new SerialDataReceivedEventHandler(Port_DataReceived); Port.Open(); Port.Write(…); protected virtual void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { BytesToRead = Port.BytesToRead; Port.Read(ReadBuffer, ReadStart, BytesToRead); } 就是不知道Write裏面寫什麼
參數是 public string COMPort = 3; public int BaudRate = 19200; public Parity Parity = Parity.Even; public int DataBit = 7; public StopBits StopBits = StopBits.One;
X1 X2 X3 X4 Y1 Y2 Y3 Y4 ,然後我用線觸碰PLC的X1 那X1的燈就會亮,跟著我這裡的label X1由黑色變為紅色,反之,如果斷開接觸,label X1由紅色變為黑色!請問我應該怎麼做 或者能給我一個連接上PLC的程式例子嗎?
如果有例子,可以研究例子的写法调试的时候用portmon软件监视,看读写数据是不是完全满足游戏规则
protected int ReadStart = 0;
protected char[] ReadBuffer = new char[1000]; Port = new SerialPort(COMPort, BaudRate, Parity, DataBit, StopBit);
Port.DataReceived += new SerialDataReceivedEventHandler(Port_DataReceived); Port.Open();
Port.Write(…); protected virtual void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
BytesToRead = Port.BytesToRead;
Port.Read(ReadBuffer, ReadStart, BytesToRead);
}
就是不知道Write裏面寫什麼
public int BaudRate = 19200;
public Parity Parity = Parity.Even;
public int DataBit = 7;
public StopBits StopBits = StopBits.One;
然后往COM定对应的指令就好了,
以前干过,
PLC那块是另外部门的同事做的,他让发什么指令就发什么
要往COM口写东西才行,至于写什么就看PLC上是如何定义的了
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;namespace TryPLC
{
public partial class Form1 : Form
{
SerialPort spcom;
public string COMPort = "COM3";
public int BaudRate = 9600;
public Parity Parity = Parity.Even;
public int DataBit = 7;
public StopBits StopBits = StopBits.One;
protected int BytesToRead = 0;
protected int ReadStart = 0;
private string b;
private delegate void MydelegateShow();
private MydelegateShow SerialDelegate; public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
butsend.Click += new EventHandler(butsend_Click);
butrev.Click += new EventHandler(butrev_Click);
} private void Form1_Load(object sender, EventArgs e)
{
spcom = new SerialPort(COMPort, BaudRate, Parity, DataBit, StopBits);
SerialDelegate = new MydelegateShow(UpdateTextBox);
spcom.DataReceived += new SerialDataReceivedEventHandler(spcom_DataReceived);
spcom.ReceivedBytesThreshold = 1; try
{
if (spcom.IsOpen == false)
{
spcom.Open();
}
else
{
spcom.Close();
spcom.Open();
}
}
catch
{
MessageBox.Show("沒有找到串口,請檢查後再試……", "警告");
}
if (spcom.IsOpen == true)
{
spcom.DiscardInBuffer();
}
} public void spcom_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (spcom.BytesToRead == 0)
{
return;
}
char[] buffer = new char[1000];
spcom.Read(buffer, 0, buffer.Length);
b = new string(buffer);
this.Invoke(SerialDelegate);
} private void UpdateTextBox()
{
txtrev.Text += b;
} //發送數據
private void butsend_Click(object sender, EventArgs e)
{
SendStringData(spcom);
} //發送字符串數據
private void SendStringData(SerialPort serialPort)
{
try
{
if (!spcom.IsOpen)
{
spcom.Open();
}
spcom.Write(txtSend.Text);
}
catch
{
MessageBox.Show("沒有找到串口,請先打開串口", "警告");
}
spcom.Close();
} //發送二進制數據
private void SendBytesData(SerialPort serialPort)
{
byte[] bytesSend = Encoding.Default.GetBytes(txtSend.Text);
spcom.Write(bytesSend, 0, bytesSend.Length);
} private void butrev_Click(object sender, EventArgs e)
{
txtrev.Text = "";
} private void txtsend_TextChenged(object sender, EventArgs e)
{
} private void txtrev_TextChanged(object sender, EventArgs e)
{
txtrev.SelectionStart = txtrev.Text.Length;
txtrev.SelectionLength = 0;
txtrev.ScrollToCaret();
}
}
}
這是我已經可以連接串口了,但是怎麼用指令接收PLC的X的on和off的狀態呢?我的是永宏PLC
在PLC中得有相应的程序来接受串口的数据。
比如用modbus,你可以调用编程软件的modbus库,设置校验位,波特率等等,完成PLC编程。
然后用电脑的232,加上232转485的转换器,一般PLC通信都是485的。(注意)
然后通过发送串口数据,才能实现通讯。
不是简单的串口数据收发就完了。
只串口的打开和关闭这不重要,重要是你前面几位兄弟说的通讯协议,因为每个PLC的协议都是不一样的。先把协议吃透,起始符是什么,前几位代表什么,数据位在哪,是什么校验方式,结束符是什么等等等等,然后就是基本的发送和接收了。
按照经验,这样的程序应该用多线程来实现,最简单的,一个UI,一个负责PLC的通讯。
LZ首要解决的是:1)RS232或485的通讯实现 2)PLC协议的理解
通过MODBUS TCP读写PLC源码
功能模块一:读写PLC主模块
using System;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
/// <summary>
/// 通过modbus TCP读写PLC数据,
///
/// 设计:张东启,2011.4.9
/// 2011.5.13更新,加入Application.DoEvents();以防连续读写时引起前台反应迟顿,同时让PLC有处理等待时间
///
///
///
/// </summary>public class PLCFunction
{ public static bool Connected = false;
public static int trytimes = 0;
//内部使用变量
private static byte[] sendBuf = { 0, 0, 0, 0, 0, 06, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //共20个字节
private static byte[] recBuf = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //共20个字节
private static int hi, low, bytes, hi1, low1;
private static Socket zdqSocket;
private static string tiaoshi="N";
private static string plcAddress = "127.0.0.1";
public static int ReadWord(int mwAddress)
{
int rtValue = -99;
if (init_plc() == 0)
{
try
{
hi = mwAddress / 256;
low = mwAddress - hi * 256; sendBuf[7] = 3;
sendBuf[8] = (byte)hi;
sendBuf[9] = (byte)low;
sendBuf[10] = 0;
sendBuf[11] = 1; //发送查询
zdqSocket.Send(sendBuf, 12, 0);
Application.DoEvents();
bytes = zdqSocket.Receive(recBuf, 11, 0); //返回11个字节
if (bytes == 11)
{
hi = recBuf[9];
low = recBuf[10];
rtValue = hi * 256 + low;
}
trytimes = 0;
}
catch (Exception te)
{
if (tiaoshi == "Y") MessageBox.Show(te.ToString());
trytimes++;
}
}
return rtValue;
}
public static void WriteWord(int mwAddress,int mwValue)
{
if (init_plc() == 0)
{
try
{
hi = mwAddress / 256;
low = mwAddress - hi * 256;
hi1 = mwValue / 256;
low1 = mwValue - hi * 256;
sendBuf[7] = 6;
sendBuf[8] = (byte)hi;
sendBuf[9] = (byte)low;
sendBuf[10] = (byte)hi1;
sendBuf[11] = (byte)low1;
zdqSocket.Send(sendBuf, 12, 0);
Application.DoEvents();
bytes = zdqSocket.Receive(recBuf, recBuf.Length, 0); //写一个字返回几个?
trytimes = 0;
}
catch (Exception te)
{
if (tiaoshi == "Y") MessageBox.Show(te.ToString());
trytimes++;
}
}
}
public static int GetMemory(int mwAddress)
{
int rtValue = -99;
if (init_plc() == 0)
{
try
{
hi = mwAddress / 256;
low = mwAddress - hi * 256; sendBuf[7] = 2;
sendBuf[8] = (byte)hi;
sendBuf[9] = (byte)low;
sendBuf[10] = 0;
sendBuf[11] = 1; //发送查询
zdqSocket.Send(sendBuf, 12, 0);
Application.DoEvents();
bytes = zdqSocket.Receive(recBuf, 10, 0); //返回11个字节
if (bytes == 10)
{
hi = recBuf[9];
rtValue = hi;
}
trytimes = 0;
}
catch (Exception te)
{
if (tiaoshi == "Y") MessageBox.Show(te.ToString());
trytimes++;
}
}
return rtValue;
} public static void SetMemory(int mwAddress,int mFlag)
{
if (init_plc() == 0)
{
//线圈置位与复位
int mBit = 0;
if (mFlag == 1) mBit = 255; else mBit = 0;
try
{
hi = mwAddress / 256;
low = mwAddress - hi * 256;
sendBuf[7] = 5;
sendBuf[8] = (byte)hi;
sendBuf[9] = (byte)low;
sendBuf[10] = (byte)mBit;
sendBuf[11] = 0;
zdqSocket.Send(sendBuf, 12, 0);
Application.DoEvents();
bytes = zdqSocket.Receive(recBuf, recBuf.Length, 0);
trytimes = 0; }
catch (Exception te)
{
if (tiaoshi == "Y") MessageBox.Show(te.ToString());
trytimes++;
}
}
}
private static int init_plc()
{
//初始化
int zdqrt = 0;
if (trytimes > 3)
{
//超过3次自动恢复连接
if (zdqSocket.Connected == true) zdqSocket.Disconnect(false);
zdqSocket = null;
trytimes = 0;
}
try
{
if (zdqSocket == null)
{
zdqSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
zdqSocket.ReceiveTimeout = int.Parse(zdqpro.WriteOrReadINI("系统设置", "接收超时"));
plcAddress = zdqpro.WriteOrReadINI("系统设置", "PLC地址"); }
if (zdqSocket.Connected == false)
{
//重新连接
tiaoshi = zdqpro.WriteOrReadINI("系统设置", "PLC调试");
zdqSocket.Connect(plcAddress, 502);
}
}
catch (Exception te)
{
if (tiaoshi == "Y") MessageBox.Show(te.ToString());
trytimes++;
zdqrt = -1;
}
Connected = zdqSocket.Connected;//是否已经连接
Application.DoEvents();
return zdqrt;
}
}读写配置文件功能代码
public static string WriteOrReadINI(string rootNod, string valueNod)
{ //读取配置文件
XmlDocument mydoc = new XmlDocument();
mydoc.Load("zdqsys.ini");
string str1 = rootNod + "/" + valueNod;
string rt = mydoc.SelectSingleNode(str1).InnerText;
return rt;
} public static void WriteOrReadINI(string rootNod, string valueNod, string valueStr)
{
//写入配置文件
XmlDocument mydoc = new XmlDocument();
mydoc.Load("zdqsys.ini");
string str1 = rootNod + "/" + valueNod;
XmlNode mynod = mydoc.SelectSingleNode(str1);
mynod.InnerText = valueStr;
mydoc.Save("zdqsys.ini");
}
配置文件zdqsys.ini内容如下:
<?xml version="1.0" encoding="GB2312"?>
<系统设置>
<PLC地址>192.168.1.200</PLC地址>
<接收超时>10</接收超时>
<PLC调试>N</PLC调试>
</系统设置>
希望能与工控爱好者或相关开发人员相互交流切搓,不当之处敬请指教。
张东启 2011.5.15
Y 输出继电器 Y0000~ Y9999 WY0000~WY9984 DWY0000~ DWY9968
本文信息中单点状态的表示是以一个字符来表示( 1 表示ON,0 表OFF),而
16 位缓存器数据则以4 个字符来表示一个Word 的数值( 0000H~ FFFFH)。