logo资料库

c# MODBUS 协议 通用代码.docx

第1页 / 共19页
第2页 / 共19页
第3页 / 共19页
第4页 / 共19页
第5页 / 共19页
第6页 / 共19页
第7页 / 共19页
第8页 / 共19页
资料共19页,剩余部分请下载后查看
/* * MODBUS 协议 * * * 介绍: * 此 modbus 上位机 协议类 具有较强的通用性 * 本协议类最主要的思想是 把所有向下位机发送的指令 先存放在缓冲区中(命名为管道) * 再将管道中的指令逐个发送出去。 * 管道遵守 FIFO 的模式。管道中所存放指令的个数 在全局变量中定义。 * 管道内主要分为两部分:1,定时循环发送指令。2,一次性发送指令。 * 定时循环发送指令:周期性间隔时间发送指令,一般针对“输入寄存器”或“输入线圈”等实时更新的变量。 * 这两部分的长度由用户所添加指令个数决定(所以自由性强)。 * 指令的最大发送次数,及管道中最大存放指令的个数在常量定义中 可进行设定。 * * 使用说明: * 1,首先对所定义的寄存器或线圈进行分组定义,并定义首地址。 * 2,在 MBDataTable 数组中添加寄存器或线圈所对应的地址。注意 寄存器:ob = new UInt16()。线圈:ob = new byte()。 * 3,对所定义的地址 用属性进行定义 以方便在类外进行访问及了解所对应地址的含义。 * 4,GetAddressValueLength 函数中 对使用说明的"第一步"分组 的元素个数进行指定。 * 5,在主程序中调用 MBConfig 进行协议初始化(初始化内容参考函数)。 * 6,在串口中断函数中调用 MBDataReceive()。 * 7,定时器调用 MBRefresh()。(10ms 以下) * * 8,在主程序初始化中添加固定实时发送的指令操作 用 MBAddRepeatCmd 函数。 * 9,在主程序运行过程中 根据需要添加 单个的指令操作(非固定重复发送的指令)用 MBAddCmd 函数。 * * * 作者:王宏强 * 时间:2012.7.2 * * * * * * */ 指令发送间隔时间等于实时器乘以 10。 例:定时器 5ms 调用一次 指令发送间隔为 50ms。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO.Ports;
namespace WindowsApplication1 { public class Modbus { #region 所用结构体 /// /// 地址对应表元素单元 /// public struct OPTable{ public volatile int addr; public volatile byte type; public volatile object ob; }; /// /// 当前的指令 /// public struct MBCmd { public volatile int addr; public volatile int stat; public volatile int len; public volatile int res; }; /// /// 当前操作的指令管道 /// public struct MBSci { //指令首地址 //功能码 //所操作的寄存器或线圈的个数 //返回码的状态, 0:无返回,1:正确返回 public volatile MBCmd[] cmd; public volatile int index; public volatile int count; public volatile int maxRepeatCount; public volatile int rtCount; //指令结构体 //当前索引 //当前功能码执行的次数 //最大发送次数 //实时读取的指令各数(无限间隔时间读取) }; #endregion #region 常量定义 public const byte MB_READ_COILS = 0x01; public const byte MB_READ_DISCRETE = 0x02; public const byte MB_READ_HOLD_REG = 0x03; public const byte MB_READ_INPUT_REG = 0x04; public const byte MB_WRITE_SINGLE_COIL = 0x05; public const byte MB_WRITE_SINGLE_REG = 0x06; public const byte MB_WRITE_MULTIPLE_COILS = 0x0f; public const byte MB_WRITE_MULTIPLE_REGS = 0x10; //读线圈寄存器 //读离散输入寄存器 //读保持寄存器 //读输入寄存器 //写单个线圈 //写单寄存器 //写多线圈 //写多寄存器 private const int MB_MAX_LENGTH = 120; private const int MB_SCI_MAX_COUNT = 15; //最大数据长度 //指令管道最大存放的指令各数
private const int MB_MAX_REPEAT_COUNT = 3; #endregion //指令最多发送次数 #region 全局变量 private static volatile bool sciLock = false; private static volatile byte[] buff = new byte[MB_MAX_LENGTH]; private static volatile int buffLen = 0; private static volatile byte[] rBuff = null; private static volatile byte[] wBuff = null; public static MBSci gMBSci = new MBSci() //调度器锁 true:加锁 false:解锁 //接收缓冲器 //正确接收缓冲器 //正确发送缓冲器 { cmd = new MBCmd[MB_SCI_MAX_COUNT], index = 0, maxRepeatCount = MB_MAX_REPEAT_COUNT, rtCount = 0, count = 0 }; private static SerialPort comm = null; private static int mbRefreshTime = 0; #endregion #region MODBUS 地址对应表 //modbus 寄存器和线圈分组 首地址定义 public const int D_DIO = 0x0000; public const int D_BASE = 0x0014; public const int D_RANGE = 0x0018; public const int D_PWM = 0x001A; public const int D_PID = 0x001E; /// /// 变量所对应的地址 在此位置 /// public static volatile OPTable[] MBDataTable = { //0 //6 //10 //12 new OPTable(){addr = D_DIO, type = MB_READ_INPUT_REG, ob = new UInt16()}, new OPTable(){addr = D_DIO + 1, new OPTable(){addr = D_DIO + 2, new OPTable(){addr = D_DIO + 3, new OPTable(){addr = D_DIO + 4, new OPTable(){addr = D_DIO + 5, type = MB_READ_INPUT_REG, type = MB_READ_INPUT_REG, type = MB_READ_INPUT_REG, type = MB_READ_INPUT_REG, type = MB_READ_INPUT_REG, ob = new UInt16()}, ob = new UInt16()}, ob = new UInt16()}, ob = new Int16()}, ob = new Int16()}, new OPTable(){addr = D_BASE, type = MB_READ_HOLD_REG, ob = new Int16()}, new OPTable(){addr = D_BASE + 1, new OPTable(){addr = D_BASE + 2, new OPTable(){addr = D_BASE + 3, type = MB_READ_HOLD_REG, type = MB_READ_HOLD_REG, type = MB_READ_HOLD_REG, ob = new Int16()}, ob = new Int16()}, ob = new Int16()}, new OPTable(){addr = D_RANGE, type = MB_READ_HOLD_REG, ob = new Int16()}, new OPTable(){addr = D_RANGE + 1, type = MB_READ_HOLD_REG, ob = new Int16()}, new OPTable(){addr = D_PWM, type = MB_READ_HOLD_REG, ob = new Int16()}, new OPTable(){addr = D_PWM + 1, type = MB_READ_HOLD_REG, ob = new Int16()},
new OPTable(){addr = D_PWM + 2, new OPTable(){addr = D_PWM + 3, type = MB_READ_HOLD_REG, type = MB_READ_HOLD_REG, ob = new Int16()}, ob = new Int16()}, new OPTable(){addr = D_PID, type = MB_READ_HOLD_REG, ob = new UInt16()}, new OPTable(){addr = D_PID + 1, new OPTable(){addr = D_PID + 2, new OPTable(){addr = D_PID + 3, new OPTable(){addr = D_PID + 4, new OPTable(){addr = D_PID + 5, type = MB_READ_HOLD_REG, type = MB_READ_HOLD_REG, type = MB_READ_HOLD_REG, type = MB_READ_HOLD_REG, type = MB_READ_HOLD_REG, ob = new UInt16()}, ob = new UInt16()}, ob = new UInt16()}, ob = new UInt16()}, ob = new UInt16()}, }; public static UInt16 gDioX { get { return Convert.ToUInt16(MBDataTable[0].ob); } set { MBDataTable[0].ob = public static UInt16 gDioY { get { return Convert.ToUInt16(MBDataTable[1].ob); } set { MBDataTable[1].ob = public static UInt16 gDioZ { get { return Convert.ToUInt16(MBDataTable[2].ob); } set { MBDataTable[2].ob = public static UInt16 gDioD { get { return Convert.ToUInt16(MBDataTable[3].ob); } set { MBDataTable[3].ob = public static Int16 gDioXx { get { return (Int16)Convert.ToInt32(MBDataTable[4].ob); } set { MBDataTable[4].ob = public static Int16 gDioXy { get { return (Int16)Convert.ToInt32(MBDataTable[5].ob); } set { MBDataTable[5].ob = public static Int16 gBaseF1 { get { return (Int16)Convert.ToInt32(MBDataTable[6].ob); } set { MBDataTable[6].ob = public static Int16 gBaseF2 { get { return (Int16)Convert.ToInt32(MBDataTable[7].ob); } set { MBDataTable[7].ob = public static Int16 gBaseF3 { get { return (Int16)Convert.ToInt32(MBDataTable[8].ob); } set { MBDataTable[8].ob = public static Int16 gBaseF4 { get { return (Int16)Convert.ToInt32(MBDataTable[9].ob); } set { MBDataTable[9].ob = //16 value; } } value; } } value; } } value; } } value; } } value; } } value; } } value; } } value; } } value; } } public static Int16 gRangeMax { get { MBDataTable[10].ob = value; } } Int16 { MBDataTable[11].ob = value; } } public static public public Int16 { MBDataTable[12].ob = value; } } Int16 { MBDataTable[13].ob = value; } } Int16 { MBDataTable[14].ob = value; } } Int16 { MBDataTable[15].ob = value; } } public public static static static static public static float gP gRangeMin { get gPwmF1 gPwmF2 gPwmF3 gPwmF4 { { { { get get get get { { { { { { return (Int16)Convert.ToInt32(MBDataTable[10].ob); return (Int16)Convert.ToInt32(MBDataTable[11].ob); return (Int16)Convert.ToInt32(MBDataTable[12].ob); return (Int16)Convert.ToInt32(MBDataTable[13].ob); return (Int16)Convert.ToInt32(MBDataTable[14].ob); return (Int16)Convert.ToInt32(MBDataTable[15].ob); } } } } } } set set set set set set
{ get { 0xFFFF) << 16); } set { } int tmp = (Convert.ToInt32(MBDataTable[16].ob) & 0xFFFF) | ((Convert.ToInt32(MBDataTable[17].ob) & byte[] arr = BitConverter.GetBytes(tmp); return BitConverter.ToSingle(arr, 0); byte[] val = BitConverter.GetBytes(value); MBDataTable[16].ob = BitConverter.ToUInt16(val, 0); MBDataTable[17].ob = BitConverter.ToUInt16(val, 2); } public static float gI { get { int tmp = (Convert.ToInt32(MBDataTable[18].ob) & 0xFFFF) | ((Convert.ToInt32(MBDataTable[19].ob) & 0xFFFF) << 16); byte[] arr = BitConverter.GetBytes(tmp); return BitConverter.ToSingle(arr, 0); } set { } byte[] val = BitConverter.GetBytes(value); MBDataTable[18].ob = BitConverter.ToUInt16(val, 0); MBDataTable[19].ob = BitConverter.ToUInt16(val, 2); } public static float gD { get { int tmp = (Convert.ToInt32(MBDataTable[20].ob) & 0xFFFF) | ((Convert.ToInt32(MBDataTable[21].ob) & 0xFFFF) << 16); byte[] arr = BitConverter.GetBytes(tmp); return BitConverter.ToSingle(arr, 0); } set { } } byte[] val = BitConverter.GetBytes(value); MBDataTable[20].ob = BitConverter.ToUInt16(val, 0); MBDataTable[21].ob = BitConverter.ToUInt16(val, 2); public static UInt16 gNode = 100;
public static UInt16 gBaud = 38400; /// /// 获取寄存器或线圈 分组后的成员各数 /// /// 首地址 /// 成员各数 private static int GetAddressValueLength(int addr) { int res = 0; switch (addr) { case D_DIO: res = 6; break; case D_BASE: res = 4; break; case D_RANGE: res = 2; break; case D_PWM: res = 4; break; case D_PID: res = 6; break; default: break; } return res; } /// /// 获取地址所对应的数据 /// /// 地址 /// 类型 /// 获取到的数据 private static object GetAddressValue(int addr, byte type) { switch (type) { //功能码类型判断 case MB_READ_COILS: case MB_READ_DISCRETE: case MB_READ_HOLD_REG: case MB_READ_INPUT_REG: break; case MB_WRITE_SINGLE_COIL: case MB_WRITE_MULTIPLE_COILS: type = MB_READ_DISCRETE; break; case MB_WRITE_SINGLE_REG: case MB_WRITE_MULTIPLE_REGS: type = MB_READ_HOLD_REG; break; default: return null; } for (int i = 0; i < MBDataTable.Length; i++) { if (MBDataTable[i].addr == addr) { if (MBDataTable[i].type == type) { return MBDataTable[i].ob; }
} } return null; } /// /// 设置地址所对应的数据 /// /// 地址 /// 类型 /// 数据 /// 是否成功 private static object SetAddressValue(int addr, byte type, object data) { for (int i = 0; i < MBDataTable.Length; i++) { if (MBDataTable[i].addr == addr) { if (MBDataTable[i].type == type) { MBDataTable[i].ob = data; return true; } } } return null; } /// /// 获取一连串数据 /// /// 首地址 /// 功能码 /// 长度 /// 转换后的字节数组 private static byte[] GetAddressValues(int addr, byte type, int len) { byte[] arr = null; object obj; byte temp; int temp2; switch (type) { case MB_WRITE_MULTIPLE_COILS: arr = new byte[(len % 8 == 0) ? (len / 8) : (len / 8 + 1)]; for (int i = 0; i < arr.Length; i++) { for (int j = 0; j < 8; j++) { //获取地址所对应的数据 并判断所读数据 是否被指定,有没被指定的数据 直接返 回 null
obj = GetAddressValue(addr + i * 8 + j, MB_READ_COILS); if (obj == null) return null; else temp = Convert.ToByte(obj); arr[i] |= (byte)((temp == 0? 0 : 1) << j); } } break; case MB_WRITE_MULTIPLE_REGS: arr = new byte[len * 2]; for (int i = 0; i < len; i++) { obj = GetAddressValue(addr + i, MB_READ_HOLD_REG); if (obj == null) return null; else temp2 = Convert.ToInt32(obj); arr[i * 2] = (byte)(temp2 >> 8); arr[i * 2 + 1] = (byte)(temp2 & 0xFF); } break; default: break; } return arr; } #endregion #region 校验 private static readonly byte[] aucCRCHi = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
分享到:
收藏