夢雨天涯
微信hui530527 &
級別: 網絡英雄
![]() |
問題是我是一個PLC工程師,想用寫一個上位機程序和三菱FX3U通訊,PLC的IP地址為192.168.0.250,端口號為5551.要求顯示X0到X7,輸出顯示Y0到Y7,還有M0到M9切換按鈕,輸出格式為直接打開的exe文件 以下是使用C#開發的三菱FX3U上位機通信程序實現方案,包含可直接運行的EXE文件生成方法: 一、開發環境配置 開發工具: Visual Studio 2022 (社區版) .NET Framework 4.8 通信參數 NuGet包:Mx.Component.Melsec(三菱協議庫) var config = new MelsecConfiguration { ProtocolType = ProtocolType.TCP, Host = "192.168.0.250", Port = 5551, CpuType = CpuType.FX3U, ConnectTimeout = 3000 }; 二、界面設計(Windows Forms) <!-- MainForm.Designer.cs --> this.Controls.AddRange(new Control[] { // X0-X7狀態指示燈 new StatusLight { Name="x0", Location=new Point(20,20) }, // ...重復創建x1-x7 // Y0-Y7狀態顯示 new StatusLight { Name="y0", Location=new Point(120,20) }, // ...重復創建y1-y7 // M0-M9切換按鈕 new ToggleButton { Name="m0", Text="M0", Location=new Point(220,20) }, // ...創建m1-m9 // 狀態欄 new StatusStrip { Items = { new ToolStripStatusLabel { Name="lblStatus" } } } }); 三、核心通信代碼 public partial class MainForm : Form { private MelsecFxPLC plc; // 初始化PLC連接 private void ConnectPLC() { plc = new MelsecFxPLC(config); var result = plc.Connect(); if (result.IsSuccess) { timer1.Interval = 500; // 500ms輪詢周期 timer1.Start(); } } // 定時讀取狀態 private void timer1_Tick(object sender, EventArgs e) { // 批量讀取X/Y狀態 var xStatus = plc.ReadBytes("X0", 1); var yStatus = plc.ReadBytes("Y0", 1); // 更新指示燈 UpdateLights(xStatus, "x"); UpdateLights(yStatus, "y"); } // M按鈕點擊事件 private void mButton_Click(object sender, EventArgs e) { var btn = sender as ToggleButton; plc.WriteBit($"M{btn.Tag}", btn.Checked); } } 四、可視化組件類 // 狀態指示燈控件 public class StatusLight : PictureBox { public StatusLight() { Size = new Size(30, 30); BackColor = Color.Silver; } public bool Active { set => BackColor = value ? Color.Lime : Color.Red; } } // 切換按鈕控件 public class ToggleButton : CheckBox { public ToggleButton() { Appearance = Appearance.Button; TextAlign = ContentAlignment.MiddleCenter; Size = new Size(50, 30); } } 五、項目打包部署 發布設置: 項目屬性 → 發布 → 選擇"從CD/USB安裝" 包含.NET Framework 4.8運行庫 生成單文件EXE 依賴文件 ├── MelsecFx.dll ├── Newtonsoft.Json.dll └── Mx.Component.Core.dll 六、協議處理流程圖 sequenceDiagram participant UI as 上位機 participant PLC as FX3U PLC UI->>PLC: TCP Connect(192.168.0.250:5551) PLC-->>UI: 連接成功響應 loop 500ms輪詢 UI->>PLC: 讀取X0-X7(0x00B0命令) PLC-->>UI: X狀態數據 UI->>PLC: 讀取Y0-Y7(0x00B0命令) PLC-->>UI: Y狀態數據 end UI->>PLC: 寫入M位(0x1401命令) PLC-->>UI: 寫入確認 七、測試驗證步驟 PLC準備: ; 測試程序 LD M8000 MOV K85 K1Y0 // Y0-Y7循環顯示 上位機操作檢查表: |
|
---|---|---|
|
工控tucao
級別: 略有小成
![]() |
using System; using System.Collections.Generic; using System.Drawing; using System.Net.Sockets; using System.Text; using System.Windows.Forms; namespace MELSEC_FX3U_Comm { public partial class MainForm : Form { private TcpClient plcClient; private NetworkStream stream; private Timer refreshTimer; private byte station = 0x00; // PLC寄存器狀態存儲 private bool[] xStatus = new bool[8]; private bool[] yStatus = new bool[8]; private bool[] mStatus = new bool[10]; public MainForm() { InitializeComponent(); InitializePLCConnection(); SetupUI(); StartRefreshTimer(); } private void InitializePLCConnection() { try { plcClient = new TcpClient(); plcClient.Connect(IPAddress.Parse("192.168.0.250"), 5551); stream = plcClient.GetStream(); StatusLabel.Text = "已連接到PLC"; } catch (Exception ex) { StatusLabel.Text = $"連接失敗: {ex.Message}"; } } private void SetupUI() { // 初始化輸入顯示區域 for (int i = 0; i < 8; i++) { var cb = new CheckBox { Text = $"X{i}", Location = new Point(20 + (i % 4) * 80, 20 + (i / 4) * 30), AutoSize = true }; xCheckBoxes.Add(cb); this.Controls.Add(cb); } // 初始化輸出顯示區域 for (int i = 0; i < 8; i++) { var cb = new CheckBox { Text = $"Y{i}", Location = new Point(200 + (i % 4) * 80, 20 + (i / 4) * 30), AutoSize = true }; yCheckBoxes.Add(cb); this.Controls.Add(cb); } // 初始化M寄存器按鈕 for (int i = 0; i < 10; i++) { var btn = new Button { Text = $"M{i}", Location = new Point(380 + (i % 5) * 80, 20 + (i / 5) * 30), Width = 70 }; btn.Click += (s, e) => ToggleMRegister(i); mButtons.Add(btn); this.Controls.Add(btn); } } private void StartRefreshTimer() { refreshTimer = new Timer { Interval = 500 }; refreshTimer.Tick += async (s, e) => await ReadPLCData(); refreshTimer.Start(); } private async Task ReadPLCData() { try { // 讀取X寄存器 byte[] xData = ReadRegisters(0x0000, 8); for (int i = 0; i < 8; i++) xStatus = (xData[i / 8] & (1 << (7 - (i % 8)))) != 0; // 讀取Y寄存器 byte[] yData = ReadRegisters(0x0010, 8); for (int i = 0; i < 8; i++) yStatus = (yData[i / 8] & (1 << (7 - (i % 8)))) != 0; UpdateUI(); } catch (Exception ex) { StatusLabel.Text = $"讀取錯誤: {ex.Message}"; } } private byte[] ReadRegisters(ushort start, ushort length) { // 構建讀取請求報文 List<byte> query = new List<byte> { 0x80, 0x00, 0x00, 0x00, // 起始符 0x00, 0x02, // 控制代碼 (byte)(station), 0x00, 0x00, // 站號、保留 (byte)(start >> 8), (byte)start, // 起始地址 (byte)(length >> 8), (byte)length,// 寄存器數量 0x00, 0x00 // 結束符 }; SendCommand(query.ToArray()); return ReadResponse(); } private void ToggleMRegister(int index) { mStatus[index] = !mStatus[index]; WriteRegister(0x2000 + index, mStatus[index] ? 1 : 0); mButtons[index].BackColor = mStatus[index] ? Color.LightGreen : SystemColors.Control; } private void WriteRegister(ushort address, ushort value) { // 構建寫請求報文 List<byte> query = new List<byte> { 0x80, 0x00, 0x00, 0x00, // 起始符 0x00, 0x12, // 控制代碼 (byte)(station), 0x00, 0x00, // 站號、保留 (byte)(address >> 8), (byte)address,// 地址 (byte)(value >> 8), (byte)value, // 值 0x00, 0x00 // 結束符 }; SendCommand(query.ToArray()); } private void SendCommand(byte[] command) { stream.Write(command, 0, command.Length); } private byte[] ReadResponse() { byte[] buffer = new byte[1024]; int bytesRead = stream.Read(buffer, 0, buffer.Length); Array.Resize(ref buffer, bytesRead); return buffer; } private void UpdateUI() { // 更新X寄存器顯示 for (int i = 0; i < 8; i++) xCheckBoxes.Checked = xStatus; // 更新Y寄存器顯示 for (int i = 0; i < 8; i++) yCheckBoxes.Checked = yStatus; // 更新M寄存器顯示 for (int i = 0; i < 10; i++) mButtons.BackColor = mStatus ? Color.LightGreen : SystemColors.Control; } protected override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); plcClient?.Close(); } [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } } } |
---|---|
|
cstw18
級別: 略有小成
![]() |
你是一個PLC工程師,這個是你自己的內心臺詞。你應該以工程師的角度,提出專業的需求,它幫你做到。而不是輸入:我是PLC工程師。 比如,你可以輸入人機界面的品牌 型號,你需要哪些軟按鍵功能,讓AI給你做觸摸屏程序。 再輸入PLC信息,使用的通訊協議等等,讓AI給你寫通訊程序。 |
---|---|
|
congrikunge
級別: 略有小成
![]() |
牛逼 |
---|---|
|