【C#】上位リンク通信を使ってPC⇔PLCで読み書きしてみた

# 初めに
昨今PLCからデータをPCからリアルタイムで入出力することが多々見られます。
最近の業務でも携わることが多い為、勉強用で簡単なプログラムを作ってみました。

### 大枠の機能
・フォームにあるボタンを押すと指定アドレスにON/OFFの書き込む
・指定アドレスの状態を監視し、ON時にラベルの色を変更
### 構成
プログラミング言語:C#
PLC:KV-7500
# 画面
・ON/OFFを書き込むボタンと、指定アドレスの状態監視用にラベルを設置。

![スクリーンショット 2025-01-12 000159.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638137/3b7ae9e3-1fca-a0d7-5516-015b446e0d2a.png)

# ソースコード
```c#
using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;


namespace win_kv_link
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private TcpClient tcpclient = new TcpClient();
        private NetworkStream netstream;

        private void Form1_Load(object sender, EventArgs e)
        {
            // TCP接続　PLC側のIPアドレス指定  PLCリンク通信ポート:8501  ※PC側とPLC側のIPアドレスは同一ネットワーク(サブネットマスク範囲を指定すること)
            tcpclient.Connect("192.168.0.10", 8501);
            // ストリーム取得
            netstream = tcpclient.GetStream();
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            netstream.Close();
            tcpclient.Close();
        }

        //PL状態を監視する　
        private void timer1_Tick(object sender, EventArgs e)
        {
            string PL_result = PL_Send();
            string[] PL_result2 = PL_result.Split(' ');
            if (PL_result2.Length == 4)
            {
                PL_Status_Change(PL_result2);
            }
            else
            {
                //機種No_textBox1.Text = "";

            }
        }


        private void 黒_button_Click(object sender, EventArgs e)
        {
            string sendcmd1 = "WR MR100 1\r";
            string sendcmd2 = "WR MR100 0\r";
            PB_send(sendcmd1);
            string result = PB_send(sendcmd2);
            if (result == "NG")
            {
                MessageBox.Show("コマンドエラー");
            }
        }

        private void 黄_button_Click(object sender, EventArgs e)
        {
            string sendcmd1 = "WR MR101 1\r";
            string sendcmd2 = "WR MR101 0\r";
            PB_send(sendcmd1);
            string result = PB_send(sendcmd2);
            if (result == "NG")
            {
                MessageBox.Show("コマンドエラー");
            }
        }

        private void 緑_button_Click(object sender, EventArgs e)
        {
            string sendcmd1 = "WR MR102 1\r";
            string sendcmd2 = "WR MR102 0\r";
                            PB_send(sendcmd1);
            string result = PB_send(sendcmd2);
            if (result == "NG")
            {
                MessageBox.Show("コマンドエラー");
            }
            
        }

        private void 赤_button_Click(object sender, EventArgs e)
        {
            string sendcmd1 = "WR MR103 1\r";
            string sendcmd2 = "WR MR103 0\r";
            PB_send(sendcmd1);
            string result = PB_send(sendcmd2);
            if (result == "NG")
            {
                MessageBox.Show("コマンドエラー");
            }
        }

        //ボタンON OFF処理
        private string PB_send(string sendcmd)
        {
            string result = "";
            byte[]  send = Encoding.GetEncoding("SHIFT-JIS").GetBytes(sendcmd);
            netstream.Write(send, 0, send.GetLength(0));
            byte[] receive = new byte[tcpclient.Available];
            netstream.Read(receive, 0, receive.Length);
             result = Encoding.GetEncoding("SHIFT-JIS").GetString(receive);

            return result;
        }
        //PLの状態確認
        private string PL_Send() 
        {
            string Pl_data = "";
            //機種問合せコマンド「?K」
            byte[] send = Encoding.GetEncoding("SHIFT-JIS").GetBytes("RDS MR200 4\r");
            //送信
            netstream.Write(send, 0, send.GetLength(0));
            byte[] receive = new byte[tcpclient.Available];
            //受信
            netstream.Read(receive, 0, receive.Length);
            //結果表示
            Pl_data = Encoding.GetEncoding("SHIFT-JIS").GetString(receive);


            return Pl_data;
        }
        //PLの状態を各ラベルに反映させる
        private void PL_Status_Change(string[] Label)
        {
            int[] Label2 = Array.ConvertAll(Label, int.Parse);
            //okokの場合との処理分けが必要
            if (Label2[0] == 0)
            {
                白_label.BackColor = Color.FromArgb(64, 64, 64);
            }
            else
            {
                白_label.BackColor = Color.White;
            }
            if (Label2[1] == 0)
            {
                橙_label.BackColor = Color.FromArgb(64, 64, 64);
            }
            else
            {
                橙_label.BackColor = Color.FromArgb(255, 128, 0);
            }
            if (Label2[2] == 0)
            {
                緑_label.BackColor = Color.FromArgb(64, 64, 64);
            }
            else
            {
                緑_label.BackColor = Color.Green;
            }
            if (Label2[3] == 0)
            {
                赤_label.BackColor = Color.FromArgb(64, 64, 64);
            }
            else
            {
                赤_label.BackColor = Color.Red;
            }
        }

        
    }

}

```




# あとがき
今回はPLC側で通信処理プログラムがいらない上位リンク通信で作成しました。

時間に余裕があればKV-7500を使ってKVソケットかMCプロトコルでの通信もやってみたいですね。