环境:打开三菱PLC安装目录下,Act>Samples>Vcs.NET>Sample2010>bin>Debug目录下分别加载以下 dll
WinForm前台设计:(图中的两紫色方块控件是从官方提供的Sample2010(在Act>Samples>Vcs.NET目录下)将这两个控件copy到Form1窗口中即可 )
关于三菱PLC的IO监控代码:
public partial class Form1 : Form
{
private static string iniPath = Application.StartupPath + "\\IO.ini";
//通过读取ini文件动态创建的but集合
static List<Button> butList = new List<Button>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
{//加载控件
if (!File.Exists(iniPath))
{
MessageBox.Show("系统未找到指定文件:" + iniPath);
}
}
}
#region 建立连接
//连接
private void button1_Click(object sender, EventArgs e)
{
//逻辑站
axActUtlType1.ActLogicalStationNumber = int.Parse(this.textBox1.Text);
//密码
axActUtlType1.ActPassword = this.textBox2.Text;
//打开plc
int status = axActUtlType1.Open();
if (status == 0)
{
LoadInputPage(iniPath, ref butList);
LoadOutputPage(iniPath, ref butList);
Monitor_IO(butList);
MessageBox.Show("连接成功!");
}
}
//断开连接
private void button2_Click(object sender, EventArgs e)
{
axActUtlType1.Close();
ClearCreatControl();
}
#endregion
#region 读写
//读
private string btn_ReadDeviceRandom(string text)
{
int iReturnCode; //Return code
String szDeviceName = text; //List data for 'DeviceName'
int iNumberOfData = 1; //Data for 'DeviceSize'
short[] arrDeviceValue = new short[iNumberOfData]; //Data for 'DeviceValue
int iNumber; //Loop counter
System.String[] arrData; //Array for 'Data'
try
{
iReturnCode = axActUtlType1.ReadDeviceRandom2(szDeviceName,
iNumberOfData,
out arrDeviceValue[0]);
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, Name,
MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
if (iReturnCode == 0)
{
//Assign the array for the read data.
arrData = new System.String[iNumberOfData];
//Copy the read data to the 'arrData'.
for (iNumber = 0; iNumber < iNumberOfData; iNumber++)
{
arrData[iNumber] = arrDeviceValue[iNumber].ToString();
}
//Set the read data to the 'Data', and display it.
return arrData[0];
}
return null;
}
//写
private void btn_WriteDeviceRandom(object sender, EventArgs e)
{
Button bt = sender as Button;
int iReturnCode; //Return code
String szDeviceName = bt.Name; //List data for 'DeviceName'
int iNumberOfData = 1; //Data for 'DeviceSize'
short[] arrDeviceValue = new short[iNumberOfData]; //Data for 'DeviceValue'
string value = btn_ReadDeviceRandom(bt.Name);
value = (value == "1")? value = "0" : value = "1";
arrDeviceValue[0] = short.Parse(value);
try
{
//The WriteDeviceRandom2 method is executed.
iReturnCode = axActUtlType1.WriteDeviceRandom2(szDeviceName,
iNumberOfData,
ref arrDeviceValue[0]);
}
//Exception processing
catch (Exception exception)
{
MessageBox.Show(exception.Message, Name,
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
#endregion
#region 控件的动态创建相关
private void ClearCreatControl() {
this.tabPage1.Controls.Clear();
this.tabPage2.Controls.Clear();
butList.Clear();
}
//加载输入IO页
private void LoadInputPage(string iniPath, ref List<Button> butList) {
if (!File.Exists(iniPath))
{
return;
}
string section = "Input";
Dictionary<string,string> inputDic = INI.GetINISectionDic(iniPath,section);
TableLayoutPanel tlp = Creat_Table(inputDic, section, ref butList);
this.tabPage1.Controls.Add(tlp);
}
//加载输出IO页面
private void LoadOutputPage(string iniPath, ref List<Button> butList) {
if (!File.Exists(iniPath))
{
return;
}
string section = "Output";
Dictionary<string, string> ouputDic = INI.GetINISectionDic(iniPath, section);
TableLayoutPanel tlp = Creat_Table(ouputDic, section, ref butList);
this.tabPage2.Controls.Add(tlp);
}
//创建button控件的方法
private List<Button> Creat_Button(Dictionary<string, string> dic, string section, ref List<Button> butList)
{
List<Button> listBut = new List<Button>();
foreach (KeyValuePair<string, string> kv in dic)
{
Button but = new Button();
but.Name = kv.Key;
but.Text = kv.Value;
but.Size = new Size(200, 60);
but.Font = new Font("隶书", 16, FontStyle.Bold);
but.TextAlign = ContentAlignment.MiddleCenter;
//是否允许绑定按钮事件。由INI_IOItem类中的枚举决定,其中value = 1的被定义为具有点击事件
if (section == "Input")
{
//给button绑定出发事件
but.Click += btn_WriteDeviceRandom;
}
butList.Add(but);
listBut.Add(but);
}
return listBut;
}
//创建表格控件的方法
private TableLayoutPanel Creat_Table(Dictionary<string, string> dic, string section, ref List<Button> butList)
{
//创建一个动态TableLayoutPanel控件
TableLayoutPanel table = new TableLayoutPanel();
int dataCount = (dic.Count == 0) ? 1:dic.Count ;
//获取父节控件的大小
int tSize1 = tabControl1.Width - 5;
int tSize2 = dataCount * 60 / 5;
if (dataCount <= 5)
{
tSize2 = dataCount * 60;
}
//设置table大小
table.Size = new Size(tSize1, tSize2);
//显示table边框
//table.CellBorderStyle = TableLayoutPanelCellBorderStyle.OutsetPartial;
int c = 5, r = dic.Count % c == 0 ? dic.Count / c : dic.Count / c + 1;
//动态添加行列
table.RowCount = r;
//设置行
for (int i = 0; i < r; i++)
{
table.RowStyles.Add(new RowStyle(SizeType.Percent, tSize2 / dataCount));
}
table.ColumnCount = c;
//设置列
for (int i = 0; i < c; i++)
{
table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, tSize1 / dataCount));
}
//将创建的button控件添加至表格
table.Controls.AddRange(Creat_Button(dic, section, ref butList).ToArray());
return table;
}
#endregion
#region 线程相关
private void Monitor_IO(List<Button> butList) {
if ( butList == null)
{
return;
}
List<Button> onList = butList;
Thread t = new Thread(delegate () {
try
{
while (true)
{
foreach (Button but in butList)
{
if (btn_ReadDeviceRandom(but.Name) == "0")
{
but.BackColor = Color.Red;
}
else if (btn_ReadDeviceRandom(but.Name) == "1")
{
but.BackColor = Color.Green;
}
Application.DoEvents();
}
Thread.Sleep(200);
}
}
catch (Exception)
{
}
});
t.IsBackground = true;
t.Start();
}
#endregion
}
INI读取类:
class INI
{
/// <summary>
/// 获取某个指定节点(Section)中所有KEY和Value
/// </summary>
/// <param name="lpAppName">节点名称</param>
/// <param name="lpReturnedString">返回值的内存地址,每个之间用\0分隔</param>
/// <param name="nSize">内存大小(characters)</param>
/// <param name="lpFileName">Ini文件</param>
/// <returns>内容的实际长度,为0表示没有内容,为nSize-2表示内存大小不够</returns>
[System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern uint GetPrivateProfileSection(string lpAppName, IntPtr lpReturnedString, uint nSize, string lpFileName);
public static Dictionary<string, string> GetINISectionDic(string iniFile, string section)
{
uint MAX_BUFFER = 32767;
string[] items = null;
//分配内存
IntPtr pReturnedString = System.Runtime.InteropServices.Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char));
uint bytesReturned = GetPrivateProfileSection(section, pReturnedString, MAX_BUFFER, iniFile);
if (!(bytesReturned == MAX_BUFFER - 2) || (bytesReturned == 0))
{
string returnedString = System.Runtime.InteropServices.Marshal.PtrToStringAuto(pReturnedString, (int)bytesReturned);
items = returnedString.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
}
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pReturnedString); //释放内存
//无结果返回空
if (items == null)
{
return null;
}
Dictionary<string, string> dic = new Dictionary<string, string>();
foreach (string item in items)
{
if (!item.Contains("="))
{
continue;
}
string[] part = item.Split('=');
dic.Add(part[0], part[1]);
}
return dic;
}
}
INI文件内容(IO点位)
效果展示:(注意,关闭窗口时需要断开连接)