燒寫Flash小工具資料包:
0.png (37.9 KB, 下載次數: 121)
下載附件
2018-7-12 18:39 上傳
0.png (37.32 KB, 下載次數: 109)
下載附件
2018-7-12 18:39 上傳
燒寫Flash小工具上位機運行界面:
0.png (6.33 KB, 下載次數: 105)
下載附件
2018-7-12 18:40 上傳
全部資料51hei下載地址:
燒寫Flash小工具.rar
(5.09 MB, 下載次數: 116)
2018-7-12 11:56 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
C#源碼:
- /*
- * MODBUS協議
- *
- * 介紹:
- * 此modbus上位機 協議類 具有較強的通用性
- * 本協議類最主要的思想是 把所有向下位機發送的指令 先存放在緩沖區中(命名為管道)
- * 再將管道中的指令逐個發送出去。
- * 管道遵守FIFO的模式。管道中所存放指令的個數 在全局變量中定義。
- * 管道內主要分為兩部分:1,定時循環發送指令。2,一次性發送指令。
- * 定時循環發送指令:周期性間隔時間發送指令,一般針對“輸入寄存器”或“輸入線圈”等實時更新的變量。
- * 這兩部分的長度由用戶所添加指令個數決定(所以自由性強)。
- * 指令的最大發送次數,及管道中最大存放指令的個數在常量定義中 可進行設定。
- *
- * 使用說明:
- * 1,首先對所定義的寄存器或線圈進行分組定義,并定義首地址。
- * 2,在MBDataTable數組中添加寄存器或線圈所對應的地址。 注意 寄存器:ob = new UInt16()。線圈:ob = new byte()。
- * 3,對所定義的地址 用屬性進行定義 以方便在類外進行訪問及了解所對應地址的含義。
- * 4,GetAddressValueLength函數中 對使用說明的"第一步"分組 的元素個數進行指定。
- * 5,在主程序中調用MBConfig進行協議初始化(初始化內容參考函數)。
- * 6,在串口中斷函數中調用MBDataReceive()。
- * 7,定時器調用MBRefresh()。(10ms以下)
- * 指令發送間隔時間等于實時器乘以10。 例:定時器5ms調用一次 指令發送間隔為50ms。
- * 8,在主程序初始化中添加固定實時發送的指令操作 用MBAddRepeatCmd函數。
- * 9,在主程序運行過程中 根據需要添加 單個的指令操作(非固定重復發送的指令)用MBAddCmd函數。
- *
- *
- * 作者:王宏強
- * 時間:2012.7.2
- *
- *
- *
- * 修正2012.1.1 修正只有一次性指令,發送最大次數不正常問題
- *
- *
- */
-
- 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 上位機
- {
- public class Modbus : Form
- {
- #region 所用結構體
- /// <summary>
- /// 地址對應表元素單元
- /// </summary>
- public struct OPTable{
- public volatile int addr;
- public volatile byte type;
- public volatile object ob;
- };
- /// <summary>
- /// 當前的指令
- /// </summary>
- public struct MBCmd
- {
- public volatile int addr; //指令首地址
- public volatile int stat; //功能碼
- public volatile int len; //所操作的寄存器或線圈的個數
- public volatile int res; //返回碼的狀態, 0:無返回,1:正確返回
- };
- /// <summary>
- /// 當前操作的指令管道
- /// </summary>
- public struct MBSci
- {
- 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 = 1200; //最大數據長度
- private const int MB_SCI_MAX_COUNT = 15; //指令管道最大存放的指令各數
- private const int MB_MAX_REPEAT_COUNT = 3; //指令最多發送次數
- #endregion
-
- #region 全局變量
- private static volatile bool sciLock = false; //調度器鎖 true:加鎖 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() { 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;
-
- /// <summary>
- /// 變量所對應的地址 在此位置
- /// </summary>
- public static volatile OPTable[] MBDataTable = new OPTable[1028];
- public static OPTable[] gDio { get { return MBDataTable; } set { MBDataTable = value; } }
- public static UInt16 gNode = 100;
- public static int gBaud = 38400;
- /// <summary>
- /// 獲取寄存器或線圈 分組后的成員各數
- /// </summary>
- /// <param name="addr">首地址</param>
- /// <returns>成員各數</returns>
- private static int GetAddressValueLength(int addr)
- {
- int res = 0;
- switch (addr)
- {
- case D_DIO: res = 514; break;
- default: break;
- }
- return res;
- }
- /// <summary>
- /// 獲取地址所對應的數據
- /// </summary>
- /// <param name="addr">地址</param>
- /// <param name="type">類型</param>
- /// <returns>獲取到的數據</returns>
- 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;
- }
- /// <summary>
- /// 設置地址所對應的數據
- /// </summary>
- /// <param name="addr">地址</param>
- /// <param name="type">類型</param>
- /// <param name="data">數據</param>
- /// <returns>是否成功</returns>
- 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;
- }
- /// <summary>
- /// 獲取一連串數據
- /// </summary>
- /// <param name="addr">首地址</param>
- /// <param name="type">功能碼</param>
- /// <param name="len">長度</param>
- /// <returns>轉換后的字節數組</returns>
- 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,
- 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
- };
- private static readonly byte[] aucCRCLo = {
- 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
- 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
- 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
- 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
- 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
- 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
- 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
- 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
- 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
- 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
- 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
- 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
- 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
- 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
- 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
- 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
- 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
- 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
- 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
- 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
- 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
- 0x41, 0x81, 0x80, 0x40
- };
- /// <summary>
- /// CRC效驗
- /// </summary>
- /// <param name="pucFrame">效驗數據</param>
- /// <param name="usLen">數據長度</param>
- /// <returns>效驗結果</returns>
- public static int Crc16(byte[] pucFrame, int usLen)
- {
- int i = 0;
- byte ucCRCHi = 0xFF;
- byte ucCRCLo = 0xFF;
- UInt16 iIndex = 0x0000;
-
- while (usLen-- > 0)
- {
- iIndex = (UInt16)(ucCRCLo ^ pucFrame[i++]);
- ucCRCLo = (byte)(ucCRCHi ^ aucCRCHi[iIndex]);
- ucCRCHi = aucCRCLo[iIndex];
- }
- return (ucCRCHi << 8 | ucCRCLo);
- }
-
- #endregion
-
- #region 發送指命操作
- /// <summary>
- /// 首部分數據 node:節點
- /// </summary>
- /// <param name="addr">寄存器地址</param>
- /// <param name="len">數據長度,或單個數據</param>
- /// <param name="stat"></param>
- /// <returns></returns>
- private static byte[] SendTrainHead(int node, int addr, int len, byte stat)
- {
- byte[] head = new byte[6];
-
- head[0] = Convert.ToByte(node);
- head[1] = stat;
- head[2] = (byte)(addr >> 8);
- head[3] = (byte)(addr & 0xFF);
- head[4] = (byte)(len >> 8);
- head[5] = (byte)(len & 0xFF);
-
- return head;
- }
- /// <summary>
- /// 計算數據長度 并在0x0f,0x10功能下 加載字節數
- /// </summary>
- /// <param name="arr"></param>
- /// <param name="len"></param>
- /// <param name="stat"></param>
- /// <returns></returns>
- private static byte[] SendTrainBytes(byte[] arr, ref int len, byte stat)
- {
- byte[] res;
- switch (stat)
- {
- default: len = 0; break;
-
- case MB_READ_COILS:
- case MB_READ_DISCRETE:
- case MB_READ_HOLD_REG:
- case MB_READ_INPUT_REG:
- case MB_WRITE_SINGLE_COIL:
- case MB_WRITE_SINGLE_REG:
- len = 0;
- break;
-
- case MB_WRITE_MULTIPLE_COILS:
- len = (len % 8 == 0) ? (len / 8) : (len / 8 + 1);
- res = new byte[arr.Length + 1];
- arr.CopyTo(res, 0);
- res[arr.Length] = (byte)(len);
- arr = res;
- break;
-
- case MB_WRITE_MULTIPLE_REGS:
- len *= 2;
- res = new byte[arr.Length + 1];
- arr.CopyTo(res, 0);
- res[arr.Length] = (byte)len; //把字節寫入數據最后位置
- arr = res;
- break;
-
- }
- return arr;
- }
- /// <summary>
- /// 主控方式 發送指令模板
- /// </summary>
- /// <param name="node">節點</param>
- /// <param name="data">數據</param>
- /// <param name="addr">地址</param>
- /// <param name="con">變量各數</param>
- /// <param name="stat">功能碼</param>
- /// <returns></returns>
- private static byte[] SendTrainCyclostyle(int node, byte[] data, int addr, int con, byte stat)
- {
- int crcVal = 0;
- byte[] headData = SendTrainHead(node, addr, con, stat); //寫首部分數據
- byte[] headDataLen = SendTrainBytes(headData, ref con, stat); //計算數據的長度,有字節則寫入。
- byte[] res = new byte[headDataLen.Length + con + 2];
-
- headDataLen.CopyTo(res, 0);
-
- if ((stat == MB_WRITE_MULTIPLE_REGS) || (stat == MB_WRITE_MULTIPLE_COILS))
- Array.Copy(data, 0, res, headDataLen.Length, con); //把數據復制到數據中
-
- crcVal = Crc16(res, res.Length - 2);
- res[res.Length - 2] = (byte)(crcVal & 0xFF);
- res[res.Length - 1] = (byte)(crcVal >> 8);
-
- return res;
- }
- /// <summary>
- /// 封裝發送數據幀
- /// </summary>
- /// <param name="node">從機地址</param>
- /// <param name="cmd">指令信息</param>
- /// <returns></returns>
- private static byte[] SendPduPack(int node, MBCmd cmd)
- {
- byte[] res = null;
- switch (cmd.stat)
- {
- case MB_READ_COILS:
- case MB_READ_DISCRETE:
- case MB_READ_HOLD_REG:
- case MB_READ_INPUT_REG:
- case MB_WRITE_SINGLE_COIL:
- case MB_WRITE_SINGLE_REG:
- res = SendTrainCyclostyle(node, null, cmd.addr, cmd.len, (byte)cmd.stat); break;
-
- case MB_WRITE_MULTIPLE_COILS:
- case MB_WRITE_MULTIPLE_REGS:
- byte[] data = GetAddressValues(cmd.addr, (byte)cmd.stat, cmd.len);
- res = SendTrainCyclostyle(node, data, cmd.addr, cmd.len, (byte)cmd.stat); break;
- }
- return res;
- }
- #endregion
-
- #region 回傳數據操作
- /// <summary>
- /// 存儲回傳的線圈
- /// </summary>
- /// <param name="data">回傳的數組</param>
- /// <param name="addr">首地址</param>
- /// <returns>存儲是否正確</returns>
- private static bool ReadDiscrete(byte[] data, int addr)
- {
- bool res = true;
- int len = data[2];
-
- if (len != (data.Length - 5)) //數據長度不正確 直接退出
- return false;
-
- for (int i = 0; i < len; i++)
- {
- for (int j = 0; j < 8; j++)
- {
- if (SetAddressValue(addr + i * 8 + j, data[1], data[i + 3] & (0x01 << j)) == null)
- {
- return false;
- }
- }
- }
- return res;
- }
- /// <summary>
- /// 讀回傳的寄存器
- /// </summary>
- /// <param name="data">回傳的數組</param>
- /// <param name="addr">首地址</param>
- /// <returns>存儲是否正確</returns>
- private static bool ReadReg(byte[] data, int addr)
- {
- bool res = true;
- int len = data[2];
-
- if (len != (data.Length - 5)) //數據長度不正確 直接退出
- return false;
-
- for (int i = 0; i < len; i += 2)
- {
- if (SetAddressValue(addr + i / 2, data[1], (data[i + 3] << 8) | data[i + 4]) == null)
- {
- res = false;
- break;
- }
- }
- return res;
- }
- /// <summary>
- /// 回傳的數據處理
- /// </summary>
- /// <param name="buff">回傳的整幀數據</param>
- /// <param name="addr">當前所操作的首地址</param>
- /// <returns></returns>
- private static bool ReceiveDataProcess(byte[] buff, int addr)
- {
- if (buff == null)
- return false;
- if (buff.Length < 5) //回傳的數據 地址+功能碼+長度+2效驗 = 5字節
- return false;
-
- bool res = true;
- switch (buff[1])
- {
- case MB_READ_COILS: ReadDiscrete(buff, addr); break;
- case MB_READ_DISCRETE: ReadDiscrete(buff, addr); break;
- case MB_READ_HOLD_REG: ReadReg(buff, addr); break;
- case MB_READ_INPUT_REG: ReadReg(buff, addr); break;
- case MB_WRITE_SINGLE_COIL:
- case MB_WRITE_SINGLE_REG:
- case MB_WRITE_MULTIPLE_COILS:
- case MB_WRITE_MULTIPLE_REGS: break;
- default: res = false; break;
- }
- return res;
- }
- #endregion
-
- #region 收發調度
- /// <summary>
- /// 添加重復操作指令
- /// </summary>
- /// <param name="sci">待發送的指命管道</param>
- /// <param name="addr">所添加指令的首地址</param>
- /// <param name="len">所添加指令的寄存器或線圈個數</param>
- /// <param name="stat">所添加指令的功能碼</param>
- private static void SciAddRepeatCmd(ref MBSci sci, int addr, int len, int stat)
- {
- if (sci.rtCount >= MB_SCI_MAX_COUNT - 1) //超出指令管道最大長度 直接退出
- return;
- if (len == 0) //地址的數據長度為空 直接退出
- return;
-
- sci.cmd[sci.rtCount].addr = addr;
- sci.cmd[sci.rtCount].len = len;
- sci.cmd[sci.rtCount].stat = stat;
- sci.cmd[sci.rtCount].res = 0;
- sci.rtCount++;
- }
- /// <summary>
- /// 添加一次性操作指令
- /// </summary>
- /// <param name="sci">待發送的指命管道</param>
- /// <param name="addr">所添加指令的首地址</param>
- /// <param name="len">所添加指令的寄存器或線圈個數</param>
- /// <param name="stat">所添加指令的功能碼</param>
- private static void SciAddCmd(ref MBSci sci, int addr, int len, int stat)
- {
- if (len == 0) //地址的數據長度為空 直接退出
- return;
-
- for (int i = sci.rtCount; i < MB_SCI_MAX_COUNT; i++)
- {
- if (sci.cmd[i].addr == -1) //把指令載入到空的管道指令上
- {
- sci.cmd[i].addr = addr;
- sci.cmd[i].len = len;
- sci.cmd[i].stat = stat;
- sci.cmd[i].res = 0;
- break;
- }
- }
- }
- /// <summary>
- /// 清空重復讀取指令集
- /// </summary>
- /// <param name="sci">待發送的指命管道</param>
- private static void SciClearRepeatCmd(ref MBSci sci)
- {
- sci.rtCount = 0;
- }
- /// <summary>
- /// 清空一次性讀取指令集
- /// </summary>
- /// <param name="sci">待發送的指命管道</param>
- private static void SciClearCmd(ref MBSci sci)
- {
- for (int i = sci.rtCount; i < MB_SCI_MAX_COUNT; i++)
- {
- sci.cmd[i].addr = -1;
- sci.cmd[i].len = 0;
- sci.cmd[i].res = 0;
- }
- }
- /// <summary>
- /// 跳到下一個操作指令
- /// </summary>
- /// <param name="sci">待發送的指命管道</param>
- private static void SciJumbNext(ref MBSci sci)
- {
- if (sci.index >= sci.rtCount) //非實時讀取地址會被清除
- {
- sci.cmd[sci.index].addr = -1;
- sci.cmd[sci.index].len = 0;
- sci.cmd[sci.index].stat = 0;
- }
-
- do{
- sci.index++;
- if (sci.index >= MB_SCI_MAX_COUNT) //超出指令最大范圍
- {
- sci.index = 0;
- if (sci.rtCount == 0) //如果固定實時讀取 為空 直接跳出
- break;
- }
-
- } while (sci.cmd[sci.index].addr == -1);
- sci.cmd[sci.index].res = 0; //本次返回狀態清零
- }
- /// <summary>
- /// 發送指令調度鎖定
- /// </summary>
- public static void SciSchedulingLock()
- {
- sciLock = true;
- }
- /// <summary>
- /// 發送指令調度解鎖
- /// </summary>
- public static void SciSchedulingUnlock()
- {
- sciLock = false;
- }
- /// <summary>
- /// 待發送的指令管道調度
- /// </summary>
- /// <param name="sci">待發送的指命管道</param>
- /// <param name="rBuf">收到正確的回傳數據</param>
- /// <param name="wBuf">準備發送的指令數據</param>
- private static void SciScheduling(ref MBSci sci, ref byte[] rBuf, ref byte[] wBuf)
- {
- if (sciLock) //如果被加鎖 直接退出
- return;
- if (sci.cmd[0].addr == -1)
- return;
-
- if ((sci.cmd[sci.index].res != 0) || (sci.count >= sci.maxRepeatCount))
- {
- sci.count = 0; //發送次數清零
- if (sci.cmd[sci.index].res != 0) //如果收到了正常返回
- {
- ReceiveDataProcess(rBuf, sci.cmd[sci.index].addr); //保存數據
- rBuf = null; //清空當前接收緩沖區的內容, 以防下次重復讀取
- }
- else
- {
- //參數操作失敗
- }
-
- SciJumbNext(ref sci);
- }
- wBuf = SendPduPack((int)gNode, sci.cmd[sci.index]); //發送指令操作
- sci.count++; //發送次數加1
- }
- /// <summary>
- /// 快速刷新 處理接收到的數據 建議:10ms以下
- /// </summary>
- /// <returns>所正確回傳數據的功能碼, null:回傳不正確</returns>
- private static int MBQuickRefresh()
- {
- int res = -1;
- if (rBuff != null)
- {
- SciSchedulingLock();
- if (ReceiveDataProcess(rBuff, gMBSci.cmd[gMBSci.index].addr) == true)
- {
- gMBSci.cmd[gMBSci.index].res = 1; //標記 所接收到的數據正確
- res = gMBSci.cmd[gMBSci.index].stat;
- }
- rBuff = null;
- SciSchedulingUnlock();
- }
- return res;
- }
- /// <summary>
- /// 調度間隔時間刷新 建議:50ms以上
- /// </summary>
- /// <returns>封裝好的協議幀</returns>
- private static void MBSchedRefresh()
- {
- SciScheduling(ref gMBSci, ref rBuff, ref wBuff);
- if (wBuff != null)
- comm.Write(wBuff, 0, wBuff.Length);
- }
-
- #endregion
-
- #region 接口函數
- /// <summary>
- /// 清空存放一次性的指令空間
- /// </summary>
- public static void MBClearCmd()
- {
- SciClearCmd(ref gMBSci);
- }
- /// <summary>
- /// 添加固定刷新(重復) 操作指令
- /// </summary>
- /// <param name="addr">地址</param>
- /// <param name="stat">功能碼</param>
- public static void MBAddRepeatCmd(int addr, byte stat)
- {
- for (int i = 0; i < GetAddressValueLength(addr); i++ )
- if (GetAddressValue(addr, stat) == null) //如果所添加的指令沒有在MODBUS對應表中定義 直接退出
- return;
- SciAddRepeatCmd(ref gMBSci, addr, GetAddressValueLength(addr), stat);
- }
- /// <summary>
- /// 添加一次性 操作指令
- /// </summary>
- /// <param name="addr"></param>
- /// <param name="stat"></param>
- public static void MBAddCmd(int addr, byte stat)
- {
- for (int i = 0; i < GetAddressValueLength(addr); i++)
- if (GetAddressValue(addr, stat) == null) //如果所添加的指令沒有在MODBUS對應表中定義 直接退出
- return;
- SciAddCmd(ref gMBSci, addr, GetAddressValueLength(addr), stat);
- }
- /// <summary>
- /// 串口參數配置
- /// </summary>
- /// <param name="commx">所用到的串口</param>
- /// <param name="node"></param>
- /// <param name="baud"></param>
- public static void MBConfig(SerialPort commx, UInt16 node, int baud)
- {
- gBaud = baud;
- gNode = node;
- comm = commx;
- SciClearRepeatCmd(ref gMBSci);
- SciClearCmd(ref gMBSci);
- }
- /// <summary>
- /// 讀取串口中接收到的數據
- /// </summary>
- /// <param name="comm">所用到的串口</param>
- public static void MBDataReceive()
- {
- if (comm == null) //如果串口沒有被初始化直接退出
- return;
- SciSchedulingLock();
- System.Threading.Thread.Sleep(10); //等待緩沖器滿
- if (!comm.IsOpen)
- return;
-
- buffLen = comm.BytesToRead; //獲取緩沖區字節長度
- if (buffLen > MB_MAX_LENGTH) //如果長度超出范圍 直接退出
- {
- SciSchedulingUnlock();
- return;
- }
- comm.Read(buff, 0, buffLen); //讀取數據
- if (gMBSci.cmd[gMBSci.index].stat == buff[1])
- {
- if (Crc16(buff, buffLen) == 0)
- {
- rBuff = new byte[buffLen];
- Array.Copy(buff, rBuff, buffLen);
- }
- }
- SciSchedulingUnlock();
- }
- /// <summary>
- /// MODBUS的實時刷新任務,在定時器在實時調用此函數
- /// 指令發送間隔時間等于實時器乘以10。 例:定時器5ms調用一次 指令發送間隔為50ms。
- /// </summary>
- /// <returns>返回當前功能讀取指令回傳 的功能碼</returns>
- public static int MBRefresh()
- {
- if (sciLock) //如果被加鎖 直接退出
- return 0;
-
- mbRefreshTime++;
- if (mbRefreshTime > 10)
- {
- mbRefreshTime = 0;
- MBSchedRefresh();
- }
- return MBQuickRefresh();
- }
- #endregion
-
-
- }
-
- }
復制代碼
|