C# SerialPort 读写三菱FX系列PLC

1:串口初始化  

com = new SerialPort("COM3", 9600, Parity.Even, 7, StopBits.One);

2:打开关闭串口

if (com.IsOpen)

 {com.Close();}

com.Open();

3:C# ASCII转字符及字符转ASCII

public static string Chr(int asciiCode)
        {
            if (asciiCode >= 0 && asciiCode <= 255)
            {
                System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();//转为
                byte[] byteArray = new byte[] { (byte)asciiCode };
                string strCharacter = asciiEncoding.GetString(byteArray);//转为字符
                return (strCharacter);
            }
            else
            {
                throw new Exception("ASCII Code is not valid.");
            }

        }

public static int Asc(string character)
        {
            if (character.Length == 1)
            {
                System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
                int intAsciiCode = (int)asciiEncoding.GetBytes(character)[0];
                return (intAsciiCode);
            }
            else
            {
                throw new Exception("Character is not valid.");
            }

        }

4:写入串口的命令字符串的和校验

       public string SumCheck(string data)
        {
            int sum = 0;
            for (int i = 0; i < data.Length; i++)
            {
                sum += Asc(data.Substring(i, 1));
            }

            string res = sum.ToString("X");
            res = res.Substring(res.Length - 2, 2);
            return res;

        }

5:写入PLC

private void btnWrite_Click(object sender, EventArgs e)

        { 

            string[] write = new string[] { "2","2"}; //将准备写入PLC的值
            //将要写入的值转换成16进制数,补齐两个字节,注意高低字节需要交换
            string sWriteData = "";
            for (int i = 0; i < write.Length; i++)
            {
                int val = Convert.ToInt32(write[i].Length>0?write[i]:"0");
                string s = val.ToString("X");
                while (s.Length<4)
                {
                    s = "0" + s;
                }
                sWriteData += s.Substring(2,2)+s.Substring(0,2);
            }

            MessageBox.Show(sWriteData);
            //写入命令,1表示写入,1194表示D202这个地址的16进制,04表示D202,D203为4个BYTE,1194=(202*2)+4096的16进制数,至于用它表示D202的起始位置,三菱故意要这么麻烦了

     sWriteData = "1119404" + sWriteData + Chr(3);
            //chr(2)和chr(3)是构成命令的标志字符,然后加上校验和,命令组织完成
            sWriteData = Chr(2) + sWriteData + SumCheck(sWriteData);

            MessageBox.Show(sWriteData);
            //写入串口
            com.Write(sWriteData);
            //byte[] data = Encoding.ASCII.GetBytes(sWriteData); 
            //com.Write(data,0,data.Length);

        }

6:读PLC

 private void btnRead_Click(object sender, EventArgs e)
        {
            
            this.txtRead0.Clear();
            string sReadData = "";

            //在读PLC中的数据之前,需要先发个指令给它,让它将数据发送到串口,下面的字符串中,chr(2),chr(3)为PLC命令的格式标志,0119404中,0表示读,1194表示D202的起始地址,04表示读D202,D203两个字,共4个字节,66为0119404和chr(3)的校验和,向串口写入"读"命令,其实和向plc地址中写入数据是一样的,只是没有数据,用0表示读

            string sReadCmd = Chr(2) + "0119404" + Chr(3) + "66";
            com.Write(sReadCmd);
            //等待1秒钟
            System.Threading.Thread.Sleep(1000);
            // 从串口读数据
            byte[] data = new byte[1024];
            com.Read(data, 0, 1024);

           //如果首位为2,则表示数据有效.这里有个问题,在第二次读,第2位才为'2',第三次又是首位为2,需要再测试
            if (data[0]==2)
            {
                string sReceiveData = System.Text.Encoding.ASCII.GetString(data);
                //MessageBox.Show(sReceiveData);
               //解析命令,将读到的字符解析成数字,注意高低位的转换
                for (int i = 1; i < 8; i += 4)
                {
                    string sLow = sReceiveData.Substring(i,2);
                    string sHigh = sReceiveData.Substring(i + 2, 2);
                    //int res = Convert.ToInt32(sHigh)+ Convert.ToInt32(sLow);
                    int res = Convert.ToInt32(sHigh,16) + Convert.ToInt32(sLow,16);

                    this.txtRead0.Text += res.ToString() + ",";
                }               
                
            }

由于没有寄存器类型信息,所以地址的计算十分关键,如D100和M100分别对应哪个地址呢?下面就是三菱Fx系列PLC地址对应表:

Public Const PLC_D_Base_AddRess = 4096
Public Const PLC_D_Special_Base_AddRess = 3584
Public Const PLC_Y_Group_Base_AddRess = 160
Public Const PLC_PY_Group_Base_AddRess = 672
Public Const PLC_T_Group_Base_AddRess = 192
Public Const PLC_OT_Group_Base_AddRess = 704
Public Const PLC_RT_Group_Base_AddRess = 1216
Public Const PLC_M_SINGLE_Base_AddRess = 2048(命令为7或8时)
Public Const PLC_M_Group_Base_AddRess = 256
Public Const PLC_PM_Group_Base_AddRess = 768
Public Const PLC_S_Group_Base_AddRess = 0
Public Const PLC_X_Group_Base_AddRess = 128
Public Const PLC_C_Group_Base_AddRess = 448
Public Const PLC_OC_Group_Base_AddRess = 960
Public Const PLC_RC_Group_Base_AddRess = 1472
Public Const PLC_TV_Group_Base_AddRess = 2048
Public Const PLC_CV16_Group_Base_AddRess = 2560
Public Const PLC_CV32_Group_Base_AddRess = 3072 

当我们用DEVICE READ命令时,D100地址=100*2+4096;M100地址=100+256;不同的是D类型寄存器存放的是字,M寄存器存放的是位,同样是读两个字节,D100返回的就是PLC中D100地址的值,M类型寄存器返回的是M100到M116的值。所以当我们用FORCE ON 命令时,M100寄存器地址=100+2048;

这也没有什么复杂的,不是吗?可是三菱公司好像不甘于如此,FORCE ON/Off命令中地址排列与DEVICE READ/WRITE不同,是低位在前高位在后。如Y20,地址是0510H,代码中4个字节地址表示为:1005。(注意:Y寄存器为八进制,如Y20 地址=16+1280=0510H) 

其实一点技术含量都没有,就是拐了几个弯,偏偏很多时候又不都告诉你,让人浪费不少时间。

  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值