⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 slave_test.cpp

📁 实现工业上常用的modbus slave从站的功能 测试通过
💻 CPP
字号:
using System;
using Microsoft.SPOT;
using System.Threading;
using Microsoft.SPOT.Hardware;

namespace MFModbus
{
    public class ModbusRtu
    {
        private Thread m_worker;
        private bool m_RunFlag;

        private byte bytRtuDataFlag=0;
        private byte bytRtuDataIdx;
        private byte[] bytRtuData = new byte[8];

        //设备地址,默认为1    
        private byte ModbusAddr = 1;
        //数据区(注意,Modbus读写是以字(双字节)为单位的)
        private byte[] DataBuff = new byte[128];

        SerialPort serial = null;

        InputPort[] input = new InputPort[5];
        Cpu.Pin[] pin = new Cpu.Pin[5] { (Cpu.Pin)0, (Cpu.Pin)1, (Cpu.Pin)2, (Cpu.Pin)5, (Cpu.Pin)6 };

        public ModbusRtu(byte mModbusAddr)
        {
            ModbusAddr=mModbusAddr;
            for (int i = 0; i < 5; i++)
            {
                input[i] = new InputPort(pin[i], false, Port.ResistorMode.PullUp);
            }
        }

        ~ModbusRtu()
        {
            Stop();
        }

        //CRC16校验
        private UInt16 GetCheckCode(byte[] buf, int nEnd)
        {
            UInt16 crc = (UInt16)0xffff;
            int i, j;
            for (i = 0; i < nEnd; i++)
            {
                crc ^= (UInt16)buf[i];
                for (j = 0; j < 8; j++)
                {
                    if ((crc & 1) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                        crc >>= 1;
                }
            }
            return crc;
        }

        //启动Modbus服务
    &nb
sp;   public void Run()
        {
            try
            {
                //仅有波特率选项,竟然没有奇偶校验控制
                serial = new SerialPort(new SerialPort.Configuration(Serial.COM1, BaudRate.Baud9600, false));
                Debug.Print("Open Serial OK");
                m_worker = new Thread(new ThreadStart(this.ModbusThreadProc));
                m_RunFlag = true;
                m_worker.Start();
            }
            catch
            {
                Debug.Print("Serial Error");
            }           
        }

        //停止Modbus服务
        public void Stop()
        {
            m_RunFlag = false;
            if (serial != null)
                serial.Dispose();
        }

        //Modbus Slave服务
        private void ModbusThreadProc()
        {
            Debug.Print("Start Modbus Slave");
            byte[] bytData=new byte[1];
            while (m_RunFlag)
            {
                serial.Read(bytData, 0, bytData.Length, Timeout.Infinite);
                RtuSlave(bytData[0]);
            }
        }
        //串口数据处理
        private void RtuSlave(byte bytData)
        {
            //Debug.Print(bytRtuDataIdx.ToString() + " - " + bytData.ToString());
            if (bytRtuDataFlag == 0)
            {
                //如果数据为首地址
                if (bytData == ModbusAddr)
                {
                    bytRtuDataFlag = 1;
                    bytRtuDataIdx = 0;
                    bytRtuData[bytRtuDataIdx++] = bytData;
                }
            }
            else
            {
                bytRtuData[bytRtuDataIdx++] = bytData;
                if (bytRtuDataIdx >= 8)
                {
                    //信息处理
                    UInt16 intCRC16 = GetCheckCode(bytRtuData, 8 - 2);
//Debug.Print("CRC:" + bytRtuData[8 - 2].ToString() + " " + ((byte)(intCRC16 & 0xFF)).ToString() +"|" + bytRtuData[8 - 1].ToString() + " " + ((byte)((intCRC16 >> 8) & 0xff)).ToString());
                    //CRC16校验检验
                    if (bytRtuData[8 - 2] == (intCRC16 & 0xFF) && bytRtuData[8 - 1] == ((intCRC16 >> 8) & 0xff))
                    {
                        byte[] bytSendData = new byte[255];
                        byte bytErrorFlag = 0;
                        byte bytErrorNo = 1;

                        //Debug.Print("CRC OK");
                        //读数据
                        if (bytRtuData[1] == 3)
                        {
                            UInt16 lngDataAddr = bytRtuData[2];
                            lngDataAddr = (UInt16)((lngDataAddr << 8) + bytRtuData[3]);  //地址
                            UInt16 lngDataNum = bytRtuData[4];
                            lngDataNum = (UInt16)((lngDataNum << 8) + bytRtuData[5]);    //数量

                            if (lngDataAddr * 2 + lngDataNum * 2 > 1024 || lngDataNum > 120)
                            {
                                bytErrorNo = 2;
                                bytErrorFlag = 0;
                            }
                            else
                            {
                                bytSendData[0] = bytRtuData[0];
                                bytSendData[1] = bytRtuData[1];
                                bytSendData[2] = (byte)(lngDataNum * 2);

                                //读GPIO信号
                                DataBuff[0] 
									;= 0;
                                DataBuff[1] = (byte)((input[0].Read() ? 1 : 0) | (input[1].Read() ? 2 : 0) | (input[2].Read() ? 4 : 0) | (input[3].Read() ? 8 : 0) | (input[4].Read() ? 16 : 0));
                                
                                for (int i = 0; i < bytSendData[2]; i++)
                                {
                                    bytSendData[3 + i] = DataBuff[lngDataAddr * 2 + i];
                                }
                                intCRC16 = GetCheckCode(bytSendData, 3 + lngDataNum * 2);
                                bytSendData[3 + lngDataNum * 2] = (byte)(intCRC16 & 0xFF);                    //CRC校验低位
                                bytSendData[4 + lngDataNum * 2] = (byte)((intCRC16 >> 8) & 0xff);             //CRC校验高位                  

                                //发送数据
                                int intRet=serial.Write(bytSendData, 0, 5 + lngDataNum * 2);

                                //Debug.Print("SendData OK " + intRet.ToString() );
                                bytErrorFlag = 1;
                            }
                        }

                        if (bytErrorFlag == 0)
                        {
                            //协议不支持
                            bytSendData[0] = bytRtuData[0];
                            bytSendData[1] = (byte)(bytRtuData[1] | 0x80);
                            bytSendData[2] = bytErrorNo;

                            intCRC16 = GetCheckCode(bytSendData, 3);
                            bytSendData[3] = (byte)(intCRC16 & 0xFF);       &n
bsp;               //CRC校验低位
                            bytSendData[4] = (byte)((intCRC16 >> 8) & 0xff);                //CRC校验高位

                            //发送数据
                            serial.Write(bytSendData, 0, 5);
                        }
                    }
                    bytRtuDataFlag = 0;
                }
            }
            return;
        }

        //串口号
        public static class Serial
        {
            public const SerialPort.Serial COM1 = (SerialPort.Serial)0;
            public const SerialPort.Serial COM2 = (SerialPort.Serial)1;
        }

        //串口波特率
        public static class BaudRate
        {
            public const SerialPort.BaudRate Baud4800 = (SerialPort.BaudRate)4800;
            public const SerialPort.BaudRate Baud9600 = (SerialPort.BaudRate)9600;
            public const SerialPort.BaudRate Baud19200 = (SerialPort.BaudRate)19200;
            public const SerialPort.BaudRate Baud38400 = (SerialPort.BaudRate)38400;
            public const SerialPort.BaudRate Baud57600 = (SerialPort.BaudRate)57600;
            public const SerialPort.BaudRate Baud115200 = (SerialPort.BaudRate)115200;
            public const SerialPort.BaudRate Baud230400 = (SerialPort.BaudRate)230400;
        }
    }
}






⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -