none
用serealport控件做modbus,与下位机通信。协议中判断帧的1.5字符和3.5字符不知道从哪里添加。请高手指点 RRS feed

  • 问题

  •         private void btn_ManualStart_Click(object sender, EventArgs e)//手动开始测量
            {
                serialPort.PortName = m_cworkPara.s_portName;
                serialPort.DataBits = m_cworkPara.i_dataBits;
                serialPort.ReadBufferSize = 1024;
                serialPort.ReadTimeout = 1;
                serialPort.BaudRate = m_cworkPara.i_bandRate;
                serialPort.RtsEnable = true;//设置RTS有效
                serialPort.DtrEnable = true;//设置DTR有效
                serialPort.DiscardNull = false;
                serialPort.Open();

                chart1.Series[0].Points.Clear();//清除绘图
                queue_result.Clear();
                btn_MeasuringRad.Visible = true;//点击“手动开始”出现“光源控制”界面
                btn_ActinicRad.Visible = true;
                btn_SaturatingRad.Visible = true;
                TimerCallback call = new TimerCallback(ExecuteTask);//定时执行发送modbus指令和接受返回帧
                s_objTimer = new System.Threading.Timer(call, null, 2000, m_cworkPara.i_autoInterval);

            }

            private void ExecuteTask(object param)//判断发送控制或者读取寄存器指令
            {
                if (b_Is_Send_Control_Data == true)
                {
                    Send_req_pduAndRecieve_rsp_pdu(b_control_pdu, 10);
                }
                else
                    Send_req_pduAndRecieve_rsp_pdu(b_readRegCode, 8);

            }

            private void Send_req_pduAndRecieve_rsp_pdu(byte[] req_pdu,int i_pduLength)//根据modbus协议,每发送一次命令,接收返回值
            {
                if (!serialPort.IsOpen)
                    serialPort.Open();
                serialPort.DiscardInBuffer();
                serialPort.DiscardOutBuffer();
                serialPort.Write(req_pdu, 0, i_pduLength);
                serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);//触发读取
             }

            private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)//读取串口数据,进入SWITCH,以帧字节跳转
            {
                int i_InNum;
                i_InNum = serialPort.BytesToRead;
                byte[] mb_rsp_pdu=new byte[i_InNum];
                serialPort.Read(mb_rsp_pdu,0,i_InNum);
                switch(i_InNum)
                {
                    case 8:
                        Checkifresend(mb_rsp_pdu);
                        break;
                    case 9:
                        AnalysisData(mb_rsp_pdu);
                        break;
                    default:
                        i_Wrongframe++;
                        break;
                }
                serialPort.DiscardInBuffer();
            }

    我现在固定时间发送一个读取寄存器指令或者控制指令。指令发送完成以后,开启serialPort.DataReceived 事件开始接收消息,通过serialPort.Read将接收到的消息读出来。modbus协议中有个判断帧的1.5字符和3.5字符的问题。我不知道从哪里判断如何接收到的一帧就是modbus协议帧。只能给整个接收的字节数提取出来,看是否是我需要的8个字节和9个字节。往往接收到错误的字节数非常多。有哪位大哥能给改改代码。

    2011年12月12日 11:48

全部回复

  • Hi 戴庞达,

    欢迎来到 MSDN 论坛!

    我认为,根据Modbus RTU 帧报文格式,我们应当考虑对数据进行接收以后,选择性地读取;而不是选择性的接收。

    您可以参考下面的两个链接:

    1. Simple Modbus Protocol
    http://www.codeproject.com/KB/trace/modbuscs.aspx

            #region Poll Function
            private void PollFunction()
            {
                //Update GUI:
                DoGUIClear();
                pollCount++;
                DoGUIStatus("Poll count: " + pollCount.ToString());
    
                //Create array to accept read values:
                short[] values = new short[Convert.ToInt32(txtRegisterQty.Text)];
                ushort pollStart;
                ushort pollLength;
    
                if (txtStartAddr.Text != "")
                    pollStart = Convert.ToUInt16(txtStartAddr.Text);
                else
                    pollStart = 0;
                if (txtRegisterQty.Text != "")
                    pollLength = Convert.ToUInt16(txtRegisterQty.Text);
                else
                    pollLength = 20;
    
                //Read registers and display data in desired format:
                try
                {
                    while (!mb.SendFc3(Convert.ToByte(txtSlaveID.Text), pollStart, pollLength, ref values)) ;
                }
                catch(Exception err)
                {
                    DoGUIStatus("Error in modbus read: " + err.Message);
                }
    
                string itemString;
    
                switch (dataType)
                {
                    case "Decimal":
                        for (int i = 0; i < pollLength; i++)
                        {
                            itemString = "[" + Convert.ToString(pollStart + i + 40001) + "] , MB[" +
                                Convert.ToString(pollStart + i) + "] = " + values[i].ToString();
                            DoGUIUpdate(itemString);
                        }
                        break;
                    case "Hexadecimal":
                        for (int i = 0; i < pollLength; i++)
                        {
                            itemString = "[" + Convert.ToString(pollStart + i + 40001) + "] , MB[" +
                                Convert.ToString(pollStart + i) + "] = " + values[i].ToString("X");
                            DoGUIUpdate(itemString);
                        }
                        break;
                    case "Float":
                        for (int i = 0; i < (pollLength / 2); i++)
                        {
                            int intValue = (int)values[2 * i];
                            intValue <<= 16;
                            intValue += (int)values[2 * i + 1];
                            itemString = "[" + Convert.ToString(pollStart + 2 * i + 40001) + "] , MB[" +
                                Convert.ToString(pollStart + 2 * i) + "] = " +
                                (BitConverter.ToSingle(BitConverter.GetBytes(intValue), 0)).ToString();
                            DoGUIUpdate(itemString);
                        }
                        break;
                    case "Reverse":
                        for (int i = 0; i < (pollLength / 2); i++)
                        {
                            int intValue = (int)values[2 * i + 1];
                            intValue <<= 16;
                            intValue += (int)values[2 * i];
                            itemString = "[" + Convert.ToString(pollStart + 2 * i + 40001) + "] , MB[" +
                                Convert.ToString(pollStart + 2 * i) + "] = " +
                                (BitConverter.ToSingle(BitConverter.GetBytes(intValue), 0)).ToString();
                            DoGUIUpdate(itemString);
                        }
                        break;
                }
            }
            #endregion
    
            #region Function 3 - Read Registers
            public bool SendFc3(byte address, ushort start, ushort registers, ref short[] values)
            {
                //Ensure port is open:
                if (sp.IsOpen)
                {
                    //Clear in/out buffers:
                    sp.DiscardOutBuffer();
                    sp.DiscardInBuffer();
                    //Function 3 request is always 8 bytes:
                    byte[] message = new byte[8];
                    //Function 3 response buffer:
                    byte[] response = new byte[5 + 2 * registers];
                    //Build outgoing modbus message:
                    BuildMessage(address, (byte)3, start, registers, ref message);
                    //Send modbus message to Serial Port:
                    try
                    {
                        sp.Write(message, 0, message.Length);
                        GetResponse(ref response);
                    }
                    catch (Exception err)
                    {
                        modbusStatus = "Error in read event: " + err.Message;
                        return false;
                    }
                    //Evaluate message:
                    if (CheckResponse(response))
                    {
                        //Return requested register values:
                        for (int i = 0; i < (response.Length - 5) / 2; i++)
                        {
                            values[i] = response[2 * i + 3];
                            values[i] <<= 8;
                            values[i] += response[2 * i + 4];
                        }
                        modbusStatus = "Read successful";
                        return true;
                    }
                    else
                    {
                        modbusStatus = "CRC error";
                        return false;
                    }
                }
                else
                {
                    modbusStatus = "Serial port not open";
                    return false;
                }
    
            }
            #endregion
    

     

    2. Modbus TCP class
    http://www.codeproject.com/KB/IP/Modbus_TCP_class.aspx

    希望对您有所帮助。

    祝,顺利!

     


    Yoyo Jiang[MSFT]
    MSDN Community Support | Feedback to us

    2011年12月14日 13:14
    版主