Giới thiệu
Bài viết này hướng dẫn cách tạo ứng dụng Windows Desktop bằng C# Windows Forms để kết nối với PLC Keyence KV Series qua giao thức MC Protocol và đọc trạng thái device DM100.
Yêu cầu
- Visual Studio 2019/2022 (Community Edition miễn phí)
- .NET Framework 4.7.2 hoặc .NET 6/7/8
- PLC Keyence KV Series với Ethernet
- Kết nối mạng TCP/IP
Tạo Project trong Visual Studio
- File → New → Project → Windows Forms App (.NET Framework)
- Đặt tên: PLCKeyenceMonitor
- .NET Framework 4.7.2
- Click Create
Code C# đầy đủ
File: Form1.cs
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace PLCKeyenceMonitor
{
public partial class Form1 : Form
{
private TcpClient tcpClient;
private NetworkStream networkStream;
private Thread monitorThread;
private bool isMonitoring = false;
private bool isConnected = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
txtIP.Text = "192.168.0.1";
txtPort.Text = "8501";
txtDevice.Text = "DM100";
UpdateStatus("Chưa kết nối");
}
// Xây dựng MC Protocol 3E Frame
private byte[] BuildMCProtocolFrame(string device, bool isWrite = false, ushort value = 0)
{
byte devCode;
int devAddr;
if (device.StartsWith("DM"))
{
devCode = 0xA8;
devAddr = int.Parse(device.Substring(2));
}
else if (device.StartsWith("R"))
{
devCode = 0x9C;
devAddr = int.Parse(device.Substring(1));
}
else if (device.StartsWith("T"))
{
devCode = 0xC2;
devAddr = int.Parse(device.Substring(1));
}
else
{
devCode = 0xA8;
devAddr = int.Parse(device);
}
using (var ms = new System.IO.MemoryStream())
{
ms.WriteByte(0x50);
ms.WriteByte(0x00);
ms.WriteByte(0x00);
ms.WriteByte(0xFF);
ms.WriteByte(0xFF);
ms.WriteByte(0x03);
ms.WriteByte(0x00);
long dataLengthPos = ms.Position;
ms.WriteByte(0x00);
ms.WriteByte(0x00);
ms.WriteByte(0x00);
ms.WriteByte(0x10);
if (isWrite)
{
ms.WriteByte(0x01);
ms.WriteByte(0x14);
}
else
{
ms.WriteByte(0x01);
ms.WriteByte(0x04);
}
ms.WriteByte(0x00);
ms.WriteByte(0x00);
ms.WriteByte(devCode);
ms.WriteByte((byte)(devAddr & 0xFF));
ms.WriteByte((byte)((devAddr >> 8) & 0xFF));
ms.WriteByte((byte)((devAddr >> 16) & 0xFF));
ms.WriteByte(0x01);
ms.WriteByte(0x00);
if (isWrite)
{
ms.WriteByte((byte)(value & 0xFF));
ms.WriteByte((byte)((value >> 8) & 0xFF));
}
long currentPos = ms.Position;
int dataLength = (int)(currentPos - dataLengthPos - 2);
ms.Position = dataLengthPos;
ms.WriteByte((byte)(dataLength & 0xFF));
ms.WriteByte((byte)((dataLength >> 8) & 0xFF));
return ms.ToArray();
}
}
private (ushort? value, string message) ParseResponse(byte[] data)
{
if (data.Length < 11)
return (null, "Response too short");
ushort endCode = (ushort)(data[9] | (data[10] <= 13)
{
ushort value = (ushort)(data[11] | (data[12] < 0)
{
Array.Resize(ref buffer, bytesRead);
var (value, msg) = ParseResponse(buffer);
if (value.HasValue)
Log($"📊 {device} = {value.Value} (0x{value.Value:X4})");
else
Log($"⚠️ Lỗi: {msg}");
}
}
catch (Exception ex)
{
Log($"❌ Lỗi đọc: {ex.Message}");
}
}
private void btnMonitor_Click(object sender, EventArgs e)
{
if (isMonitoring)
{
isMonitoring = false;
btnMonitor.Text = "Monitor";
Log("⏹️ Đã dừng monitor");
}
else
{
isMonitoring = true;
btnMonitor.Text = "Dừng";
Log("▶️ Bắt đầu monitor...");
monitorThread = new Thread(MonitorLoop);
monitorThread.IsBackground = true;
monitorThread.Start();
}
}
private void MonitorLoop()
{
while (isMonitoring && isConnected)
{
Invoke(new Action(() => ReadDevice()));
Thread.Sleep(1000);
}
}
private void UpdateStatus(string message)
{
lblStatus.Text = $"Trạng thái: {message}";
}
private void Log(string message)
{
string timestamp = DateTime.Now.ToString("HH:mm:ss");
txtLog.AppendText($"[{timestamp}] {message}\r\n");
}
}
}
Thiết kế Form
- GroupBox “Cấu hình kết nối”: Label + TextBox (txtIP, txtPort)
- GroupBox “Device”: Label + TextBox (txtDevice)
- Button: btnConnect, btnRead, btnMonitor
- TextBox: txtLog (MultiLine, ScrollBars=Vertical)
- StatusStrip: lblStatus
MC Protocol Frame Structure
Frame format tương tự Python: 50 00 (Subheader) + Network/PC/Module + Data Length + Monitoring Timer + Command + Device Code + Address
Chạy ứng dụng
- Nhấn F5 hoặc Start để chạy
- Nhập IP PLC (ví dụ: 192.168.0.1)
- Nhấn “Kết nối”
- Nhập device (DM100)
- Nhấn “Đọc” hoặc “Monitor”
Device Codes
DM: 0xA8 | R: 0x9C | MR: 0x90 | T: 0xC2 | C: 0xC3
Mở rộng
- Đọc nhiều device (RDS command)
- Ghi device (WR command)
- Kết nối Modbus TCP
- Chart real-time với LiveCharts
- Export CSV/Excel
Code dựa trên tài liệu Keyence KV Series. Tested với KV-7500 và KV-8000.
