Esempio n. 1
0
        /// <summary>
        /// 写多个线圈和寄存器
        /// </summary>
        /// <param name="devType">地址类型</param>
        /// <param name="regAddr">开始地址</param>
        /// <param name="wVal">多个值</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Write(int devAddr, int regAddr, int[] wVal, out string er)
        {
            er = string.Empty;

            try
            {
                int N = wVal.Length; //单写多个值

                int rLen = 8;

                int wLen = N * 2;

                string wData = string.Empty;
                for (int i = 0; i < N; i++)
                {
                    wData += wVal[i].ToString("X4");
                }

                string wCmd = devAddr.ToString("X2");

                wCmd += "11";                   //寄存器功能码为0x10 -不保存EPROM 0x11->保存EPROM
                wCmd += regAddr.ToString("X4"); //开始地址
                wCmd += N.ToString("X4");       //读地址长度
                wCmd += wLen.ToString("X2");    //写入字节数
                wCmd += wData;                  //写入数据
                wCmd += CCRC.Crc16(wCmd);

                //CRC16 低位前,高位后
                rLen = 8;

                if (devAddr == 0)
                {
                    rLen = 0;
                }

                string rData = string.Empty;

                if (!com.send(wCmd, rLen, out rData, out er))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                    return(false);
                }

                return(true);
            }
            catch (Exception e)
            {
                er = e.ToString();
                return(false);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// 检查CRC
        /// </summary>
        /// <param name="wCmd"></param>
        /// <returns></returns>
        private bool checkCRC(string wCmd)
        {
            string crc = CCRC.Crc16(wCmd.Substring(0, wCmd.Length - 4));

            if (crc != wCmd.Substring(wCmd.Length - 4, 4))
            {
                return(false);
            }
            return(true);
        }
Esempio n. 3
0
        /// <summary>
        /// 单写线圈和寄存器值
        /// 从机地址(1Byte)+功能码(1Byte)+寄存器地址(2Byte)+地址数量(2Byte)+字节数(1Byte)+数据+CRC检验(2Byte)
        /// </summary>
        /// <param name="devType">地址类型</param>
        /// <param name="regAddr">开始地址</param>
        /// <param name="wVal">单个值</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Write(int devAddr, ERegType regType, int regAddr, int wVal, out string er)
        {
            er = string.Empty;

            try
            {
                int    N     = 1; //单写1个值
                string wCmd  = devAddr.ToString("X2");
                int    rLen  = 0;
                int    wLen  = 0;
                string wData = string.Empty;
                if (regType != ERegType.D)
                {
                    wCmd += "0F";        //线圈功能码为15
                    wLen  = (7 + N) / 8; //写入字节数
                    rLen  = 8;           //回读长度
                    wData = wVal.ToString("X" + wLen * 2);
                }
                else
                {
                    wCmd += "10";     //寄存器功能码为16
                    wLen  = N * 2;    //写入字节数
                    rLen  = 8;        //回读长度
                    wData = wVal.ToString("X" + wLen * 2);
                }
                wCmd += regAddr.ToString("X4"); //开始地址
                wCmd += N.ToString("X4");       //读地址长度
                wCmd += wLen.ToString("X2");    //写入字节数
                wCmd += wData;                  //写入数据
                wCmd += CCRC.Crc16(wCmd);       //CRC16 低位前,高位后

                string rData = string.Empty;

                rLen = 4;

                if (!com.send(wCmd, rLen, out rData, out er))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                    return(false);
                }

                return(true);
            }
            catch (Exception e)
            {
                er = e.ToString();
                return(false);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// 读线圈
        /// 从机地址(1Byte)+功能码(1Byte)+寄存器地址(2Byte)+地址数量(2Byte)+CRC检验(2Byte)
        /// </summary>
        /// <param name="devType">地址类型</param>
        /// <param name="regAddr">开始地址</param>
        /// <param name="N">地址长度</param>
        /// <param name="rData">16进制字符:数据值高位在前,低位在后</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Read(int devAddr, int regAddr, int N, out string rData, out string er)
        {
            rData = string.Empty;

            er = string.Empty;

            try
            {
                int rLen = N * 2;

                string wCmd = devAddr.ToString("X2");

                wCmd += "03";                   //寄存器功能码为03

                wCmd += regAddr.ToString("X4"); //开始地址

                wCmd += N.ToString("X4");       //读地址长度---1Byte

                wCmd += CCRC.Crc16(wCmd);       //CRC16 低位前,高位后

                if (!com.send(wCmd, 5 + rLen, out rData, out er))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                    return(false);
                }

                string temp = rData.Substring(6, rLen * 2);

                rData = temp; //2个字节为寄存器值,高在前,低位在后,寄存器小排最前面;

                //转换为寄存器小排最后

                rData = string.Empty;

                for (int i = 0; i < temp.Length / 4; i++)
                {
                    rData = temp.Substring(i * 4, 4) + rData;
                }

                return(true);
            }
            catch (Exception e)
            {
                er = e.ToString();
                return(false);
            }
        }
Esempio n. 5
0
 /// <summary>
 /// 协议格式
 /// </summary>
 /// <param name="wAddr"></param>
 /// <param name="wCmd"></param>
 /// <param name="wData"></param>
 /// <returns></returns>
 private string CalDataFromELCmd(int wAddr, string wCmd, string wData)
 {
     try
     {
         string cmd  = string.Empty;
         int    nLen = 1 + 1 + 2 + 1 + wData.Length / 2;
         cmd  = SOI + wAddr.ToString("X2") + wCmd + nLen.ToString("X2") + wData;
         cmd += CCRC.Crc16(cmd);
         return(cmd);
     }
     catch (Exception ex)
     {
         return(ex.ToString());
     }
 }
Esempio n. 6
0
        /// <summary>
        /// 单写线圈和寄存器值
        /// 从机地址(1Byte)+功能码(1Byte)+寄存器地址(2Byte)+地址数量(2Byte)+字节数(1Byte)+数据+CRC检验(2Byte)
        /// </summary>
        /// <param name="devType">地址类型</param>
        /// <param name="regAddr">开始地址</param>
        /// <param name="wVal">单个值</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Write(int devAddr, int regAddr, int wVal, out string er)
        {
            er = string.Empty;

            try
            {
                int N = 1;        //单写1个值

                int wLen = N * 2; //写入字节数

                string wData = wVal.ToString("X" + wLen * 2);

                int rLen = 4;         //回读长度

                string wCmd = string.Empty;

                wCmd  = devAddr.ToString("X2");     //设备地址
                wCmd += "10";                       //寄存器功能码为16
                wCmd += regAddr.ToString("X4");     //开始地址
                wCmd += N.ToString("X4");           //地址长度
                wCmd += wLen.ToString("X2");        //写入字节数
                wCmd += wData;                      //写入数据
                wCmd += CCRC.Crc16(wCmd);           //CRC16 低位前,高位后

                string rData = string.Empty;

                if (!com.send(wCmd, rLen, out rData, out er, _TimeOut))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                    return(false);
                }

                return(true);
            }
            catch (Exception e)
            {
                er = e.ToString();
                return(false);
            }
        }
Esempio n. 7
0
        /// <summary>
        /// 单写线圈和寄存器值
        /// 从机地址(1Byte)+功能码(1Byte)+寄存器地址(2Byte)+地址数量(2Byte)+字节数(1Byte)+数据+CRC检验(2Byte)
        /// </summary>
        /// <param name="devType">地址类型</param>
        /// <param name="regAddr">开始地址</param>
        /// <param name="wVal">单个值</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Write(int devAddr, int regAddr, int wVal, out string er)
        {
            er = string.Empty;

            try
            {
                int N = 1;    //单写1个值

                int rLen = 8; //回读长度

                int wLen = N * 2;

                string wData = string.Empty;

                wData = wVal.ToString("X" + wLen * 2);

                string wCmd = devAddr.ToString("X2"); //设备地址
                wCmd += "07";                         //寄存器功能码0x6 -不保存 EPROM 0x07->保存EPROM
                wCmd += regAddr.ToString("X4");       //开始地址
                wCmd += wData;                        //写入数据
                wCmd += CCRC.Crc16(wCmd);             //CRC16 低位前,高位后

                string rData = string.Empty;

                if (!com.send(wCmd, rLen, out rData, out er))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                    return(false);
                }

                return(true);
            }
            catch (Exception e)
            {
                er = e.ToString();
                return(false);
            }
        }
Esempio n. 8
0
        /// <summary>
        /// 检验和
        /// </summary>
        /// <param name="wData"></param>
        /// <param name="er"></param>
        /// <returns></returns>
        private bool EL_CheckSum(string wData, out string er)
        {
            er = string.Empty;

            try
            {
                if (wData.Substring(0, 2) != SOI)
                {
                    er = "数据桢头错误:" + wData;
                    return(false);
                }
                if (wData.Length / 2 < 6)
                {
                    er = "数据长度小于6:" + wData;
                    return(false);
                }
                int rLen = System.Convert.ToInt16(wData.Substring(4, 2), 16);
                if ((wData.Length / 2) != (rLen + 2))
                {
                    er = "数据长度错误:" + wData;
                    return(false);
                }
                string chkStr = wData.Substring(0, rLen * 2);
                string chkSum = wData.Substring(rLen * 2, 4);
                if (chkSum != CCRC.Crc16(chkStr))
                {
                    er = "数据CheckSum错误:" + wData;
                    return(false);
                }
                if (wData.Substring(6, 2) != "01")
                {
                    er = "返回数据确认FAIL:" + wData;
                    return(false);
                }
                return(true);
            }
            catch (Exception ex)
            {
                er = ex.ToString();
                return(false);
            }
        }
Esempio n. 9
0
        /// <summary>
        /// 复位机组并消音
        /// </summary>
        /// <param name="devAddr"></param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Reset(int devAddr, out string er)
        {
            er = string.Empty;

            try
            {
                string wCmd = devAddr.ToString("X2");

                string rData = string.Empty;

                int regAddr = 8;

                int rLen = 8;

                wCmd += "05";                    //寄存器功能码为05

                wCmd += regAddr.ToString("X4");  //复位命令0008

                wCmd += "FF00";                  //有效命令FF00 无效命令0000

                wCmd += CCRC.Crc16(wCmd);        //CRC16 低位前,高位后

                if (!com.send(wCmd, rLen, out rData, out er))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = "crc16检验和错误:" + rData;
                    return(false);
                }

                return(true);
            }
            catch (Exception ex)
            {
                er = ex.ToString();
                return(false);
            }
        }
Esempio n. 10
0
        /// <summary>
        /// 复位机组并消音
        /// </summary>
        /// <param name="devAddr"></param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Reset(int devAddr, out string er)
        {
            er = string.Empty;

            try
            {
                string wCmd = devAddr.ToString("X2");

                string rData = string.Empty;

                int rLen = 8;

                wCmd += "0F";                  //寄存器功能码为0F

                wCmd += "00010002";            //开始地址

                wCmd += "0103";                //命令

                wCmd += CCRC.Crc16(wCmd);      //CRC16 低位前,高位后

                if (!com.send(wCmd, rLen, out rData, out er))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = "crc16检验和错误:" + rData;
                    return(false);
                }

                return(true);
            }
            catch (Exception ex)
            {
                er = ex.ToString();
                return(false);
            }
        }
Esempio n. 11
0
        /// <summary>
        /// 单写寄存器值
        /// 从机地址(1Byte)+功能码(1Byte)+寄存器地址(2Byte)+地址数量(2Byte)+字节数(1Byte)+数据+CRC检验(2Byte)
        /// </summary>
        /// <param name="devType">地址类型</param>
        /// <param name="startAddr">开始地址</param>
        /// <param name="wVal">单个值</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool write(int devAddr, int startAddr, int wVal, out string er)
        {
            er = string.Empty;

            try
            {
                int    N     = 1; //单写1个值
                string wCmd  = devAddr.ToString("X2");
                int    rLen  = 0;
                int    wLen  = 0;
                string wData = string.Empty;
                wCmd += "10";                     //寄存器功能码为16
                wLen  = N * 2;                    //写入字节数
                rLen  = 8;                        //回读长度
                wData = wVal.ToString("X" + wLen * 2);
                wCmd += formatDevAddr(startAddr); //开始地址
                wCmd += N.ToString("X4");         //读地址长度
                wCmd += wLen.ToString("X2");      //写入字节数
                wCmd += wData;                    //写入数据
                wCmd += CCRC.Crc16(wCmd);         //CRC16 低位前,高位后
                string rData = string.Empty;
                if (!com.send(wCmd, rLen, out rData, out er))
                {
                    return(false);
                }
                if (!checkCRC(rData))
                {
                    er = "crc16检验和错误:" + rData;
                    return(false);
                }
                return(true);
            }
            catch (Exception e)
            {
                er = e.ToString();
                return(false);
            }
        }
Esempio n. 12
0
        /// <summary>
        /// 写多个线圈和寄存器
        /// </summary>
        /// <param name="devType">地址类型</param>
        /// <param name="regAddr">开始地址</param>
        /// <param name="wVal">多个值</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Write(int devAddr, ERegType regType, int regAddr, int[] wVal, out string er)
        {
            er = string.Empty;

            try
            {
                int    N     = wVal.Length; //单写多个值
                string wCmd  = devAddr.ToString("X2");
                int    rLen  = 0;
                int    wLen  = 0;
                string wData = string.Empty;
                if (regType != ERegType.D)
                {
                    wCmd += "0F";        //线圈功能码为15
                    wLen  = (7 + N) / 8; //写入字节数
                    rLen  = 8;           //回读长度
                    for (int i = 0; i < wLen; i++)
                    {
                        int val = 0;
                        for (int j = 0; j < 8; j++)
                        {
                            if (i * 8 + j < N)
                            {
                                int bit = (wVal[i * 8 + j] & 0x1) << j;
                                val += bit;
                            }
                        }
                        wData += val.ToString("X2");
                    }
                }
                else
                {
                    wCmd += "10";     //寄存器功能码为16
                    wLen  = N * 2;    //写入字节数
                    rLen  = 8;        //回读长度
                    for (int i = 0; i < N; i++)
                    {
                        wData += wVal[i].ToString("X4");
                    }
                }
                wCmd += regAddr.ToString("X4"); //开始地址
                wCmd += N.ToString("X4");       //读地址长度
                wCmd += wLen.ToString("X2");    //写入字节数
                wCmd += wData;                  //写入数据
                wCmd += CCRC.Crc16(wCmd);       //CRC16 低位前,高位后
                rLen  = 4;
                string rData = string.Empty;
                if (!com.send(wCmd, rLen, out rData, out er))
                {
                    return(false);
                }
                if (!checkCRC(rData))
                {
                    er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                    return(false);
                }
                return(true);
            }
            catch (Exception e)
            {
                er = e.ToString();
                return(false);
            }
        }
Esempio n. 13
0
        /// <summary>
        /// 读线圈
        /// 从机地址(1Byte)+功能码(1Byte)+寄存器地址(2Byte)+地址数量(2Byte)+CRC检验(2Byte)
        /// </summary>
        /// <param name="devType">地址类型</param>
        /// <param name="regAddr">开始地址</param>
        /// <param name="N">地址长度</param>
        /// <param name="rData">16进制字符:数据值高位在前,低位在后</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Read(int devAddr, ERegType regType, int regAddr, int N, out string rData, out string er)
        {
            rData = string.Empty;

            er = string.Empty;

            try
            {
                string wCmd = devAddr.ToString("X2");
                int    rLen = 0;

                if (regType != ERegType.D)
                {
                    wCmd += "01";        //线圈功能码为01
                    rLen  = (N + 7) / 8; //8个线圈为1Byte:前8个线圈存第1字节,最小线圈存最低位
                }
                else
                {
                    wCmd += "03";   //寄存器功能码为03
                    rLen  = N * 2;
                }
                wCmd += regAddr.ToString("X4"); //开始地址
                wCmd += N.ToString("X2");       //读地址长度---1Byte

                wCmd += CCRC.Crc16(wCmd);       //CRC16 低位前,高位后

                if (!com.send(wCmd, 5 + rLen, out rData, out er))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                    return(false);
                }
                string temp = rData.Substring(6, rLen * 2);

                if (regType != ERegType.D)
                {
                    //转化线圈数据为 Mn,Mn-1..M1,M0(高位在前,低位在后)
                    string coil_HL = string.Empty;
                    int    coilLen = temp.Length / 2;
                    for (int i = 0; i < coilLen; i++)
                    {
                        coil_HL += temp.Substring(temp.Length - (i + 1) * 2, 2);
                    }
                    rData = coil_HL;
                }
                else
                {
                    rData = temp;  //2个字节为寄存器值,高在前,低位在后,寄存器小排最前面;
                    //转换为寄存器小排最后
                    rData = string.Empty;
                    for (int i = 0; i < temp.Length / 4; i++)
                    {
                        rData = temp.Substring(i * 4, 4) + rData;
                    }
                }
                return(true);
            }
            catch (Exception e)
            {
                er = e.ToString();
                return(false);
            }
        }
Esempio n. 14
0
        /// <summary>
        /// 写多线圈和寄存器值
        /// </summary>
        /// <param name="plcAddr">PLC地址</param>
        /// <param name="regType">寄存器类型</param>
        /// <param name="startAddr">开始地址</param>
        /// <param name="N">双字节(FFFF)为1个长度</param>
        /// <param name="strHex">16进制字符格式:FFFF FFFF(N=2) 高4位在前,低4位在后</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Write(int plcAddr, ERegType regType, int startAddr, int N, string strHexVal, out string er)
        {
            lock (_sync)
            {
                try
                {
                    //N:单写1个值 --->双字节0xFFFF --->word字节0xFFFFFFFF
                    string wCmd  = plcAddr.ToString("X2");
                    int    rLen  = 0;
                    int    wLen  = 0;
                    string wData = string.Empty;
                    if (regType != ERegType.D)
                    {
                        wCmd += "0F";        //线圈功能码为15
                        wLen  = (7 + N) / 8; //写入字节数
                        rLen  = 8;           //回读长度
                    }
                    else
                    {
                        wCmd += "10";     //寄存器功能码为16
                        wLen  = N * 2;    //写入字节数
                        rLen  = 8;        //回读长度
                    }
                    //反转:低位在前,高位在后
                    for (int i = 0; i < N; i++)
                    {
                        wData += "0000";
                    }

                    string temp = string.Empty;

                    for (int i = 0; i < strHexVal.Length / 4; i++)
                    {
                        temp = strHexVal.Substring(i * 4, 4) + temp;
                    }

                    wData = wData + temp;

                    wData = wData.Substring(wData.Length - wLen * 2, wLen * 2);
                    wCmd += formatDevAddr(regType, startAddr); //开始地址
                    wCmd += N.ToString("X4");                  //读地址长度
                    wCmd += wLen.ToString("X2");               //写入字节数
                    wCmd += wData;                             //写入数据
                    wCmd += CCRC.Crc16(wCmd);                  //CRC16 低位前,高位后
                    string rData = string.Empty;
                    if (!com.send(wCmd, rLen, out rData, out er))
                    {
                        return(false);
                    }
                    if (!checkCRC(rData))
                    {
                        er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                        return(false);
                    }
                    return(true);
                }
                catch (Exception e)
                {
                    er = e.ToString();
                    return(false);
                }
            }
        }
Esempio n. 15
0
        /// <summary>
        /// 空调温度
        /// </summary>
        /// <param name="devAddr"></param>
        /// <param name="rData"></param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool AirTemp(int devAddr, out double[] rTemp, out string er)
        {
            er = string.Empty;

            rTemp = new double[2];

            bool bSta = true;

            try
            {
                for (int i = 0; i < 2; i++)
                {
                    string wCmd = devAddr.ToString("X2");

                    string rData = string.Empty;

                    long regAddr = 0x170A + i;

                    int rLen = 7;

                    wCmd += "04";                    //寄存器功能码为04

                    wCmd += Convert.ToString(regAddr, 16);

                    wCmd += "0001";

                    wCmd += CCRC.Crc16(wCmd);                  //CRC16 低位前,高位后

                    if (!com.send(wCmd, rLen, out rData, out er))
                    {
                        return(false);
                    }

                    if (!checkCRC(rData))
                    {
                        er = "crc16检验和错误:" + rData;
                        return(false);
                    }
                    rData = rData.Substring(6, 4);

                    switch (rData)
                    {
                    case "8041":
                        rData = string.Empty;
                        er   += "探头[" + (i + 1).ToString() + "]短路;";
                        break;

                    case "8042":
                        rData = string.Empty;
                        er   += "探头[" + (i + 1).ToString() + "]断路;";
                        break;

                    case "8043":
                        rData = string.Empty;
                        er   += "探头[" + (i + 1).ToString() + "]故障;";
                        break;

                    case "8044":
                        rData = string.Empty;
                        er   += "探头[" + (i + 1).ToString() + "]不存在;";
                        break;

                    default:
                        rTemp[i] = (double)Convert.ToInt32(rData, 16) / 10;
                        break;
                    }
                    if (rData == "")
                    {
                        bSta = false;
                    }
                }
                return(bSta);
            }
            catch (Exception ex)
            {
                er = ex.ToString();
                return(false);
            }
        }
Esempio n. 16
0
        /// <summary>
        ///  运行状态
        /// </summary>
        /// <param name="devAddr"></param>
        /// <param name="rData">0:待机 1:启动中 2:运行中 3:停机中 4:严重故障 5:防冻</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool RunState(int devAddr, out string rData, out string er)
        {
            er = string.Empty;

            rData = string.Empty;

            try
            {
                string wCmd = devAddr.ToString("X2");

                int rLen = 7;

                wCmd += "04";                    //寄存器功能码为05

                wCmd += "17000001";

                wCmd += CCRC.Crc16(wCmd);                  //CRC16 低位前,高位后

                if (!com.send(wCmd, rLen, out rData, out er))
                {
                    return(false);
                }

                if (!checkCRC(rData))
                {
                    er = "crc16检验和错误:" + rData;
                    return(false);
                }

                rData = rData.Substring(6, 4);

                switch (rData)
                {
                case "0000":
                    rData = "待机中";
                    break;

                case "0001":
                    rData = "启动中";
                    break;

                case "0002":
                    rData = "运行中";
                    break;

                case "0003":
                    rData = "停机中";
                    break;

                case "0004":
                    rData = "严重故障";
                    break;

                case "0005":
                    rData = "防冻";
                    break;

                default:
                    break;
                }

                return(true);
            }
            catch (Exception ex)
            {
                er = ex.ToString();
                return(false);
            }
        }
Esempio n. 17
0
        /// <summary>
        /// 单写线圈和寄存器值
        /// </summary>
        /// <param name="plcAddr">PLC地址</param>
        /// <param name="regType">寄存器类型</param>
        /// <param name="startAddr">开始地址</param>
        /// <param name="startBin">0</param>
        /// <param name="wVal">数据值</param>
        /// <param name="er"></param>
        /// <returns></returns>
        public bool Write(int plcAddr, ERegType regType, int startAddr, int startBit, int wVal, out string er)
        {
            lock (_sync)
            {
                er = string.Empty;

                try
                {
                    int N = 1; //单写1个值
                    if (startBit > 0)
                    {
                        N = startBit;
                    }
                    string wCmd  = plcAddr.ToString("X2");
                    int    rLen  = 0;
                    int    wLen  = 0;
                    string wData = string.Empty;
                    if (regType != ERegType.D)
                    {
                        wCmd += "0F";        //线圈功能码为15
                        wLen  = (7 + N) / 8; //写入字节数
                        rLen  = 8;           //回读长度
                        wData = wVal.ToString("X" + wLen * 2);
                    }
                    else
                    {
                        wCmd += "10";     //寄存器功能码为16
                        wLen  = N * 2;    //写入字节数
                        rLen  = 8;        //回读长度
                        wData = wVal.ToString("X" + wLen * 2);
                        string temp = wData;
                        wData = string.Empty;
                        for (int i = 0; i < temp.Length / 4; i++)
                        {
                            wData = temp.Substring(i * 4, 4) + wData;
                        }
                    }
                    wCmd += formatDevAddr(regType, startAddr); //开始地址
                    wCmd += N.ToString("X4");                  //读地址长度
                    wCmd += wLen.ToString("X2");               //写入字节数
                    wCmd += wData;                             //写入数据
                    wCmd += CCRC.Crc16(wCmd);                  //CRC16 低位前,高位后
                    string rData = string.Empty;
                    if (!com.send(wCmd, rLen, out rData, out er))
                    {
                        return(false);
                    }
                    if (!checkCRC(rData))
                    {
                        er = CLanguage.Lan("crc16检验和错误") + ":" + rData;
                        return(false);
                    }
                    return(true);
                }
                catch (Exception e)
                {
                    er = e.ToString();
                    return(false);
                }
            }
        }