找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6703|回复: 4
打印 上一主题 下一主题
收起左侧

烧写Flash小工具C#上位机源码

[复制链接]
跳转到指定楼层
楼主
烧写Flash小工具资料包:


烧写Flash小工具上位机运行界面:


全部资料51hei下载地址:
烧写Flash小工具.rar (5.09 MB, 下载次数: 112)


C#源码:
  1. /*
  2.   * MODBUS协议
  3.   *
  4.   * 介绍:
  5.   * 此modbus上位机 协议类 具有较强的通用性
  6.   * 本协议类最主要的思想是 把所有向下位机发送的指令 先存放在缓冲区中(命名为管道)
  7.   * 再将管道中的指令逐个发送出去。
  8.   * 管道遵守FIFO的模式。管道中所存放指令的个数 在全局变量中定义。
  9.   * 管道内主要分为两部分:1,定时循环发送指令。2,一次性发送指令。
  10.   * 定时循环发送指令:周期性间隔时间发送指令,一般针对“输入寄存器”或“输入线圈”等实时更新的变量。
  11.   * 这两部分的长度由用户所添加指令个数决定(所以自由性强)。
  12.   * 指令的最大发送次数,及管道中最大存放指令的个数在常量定义中 可进行设定。
  13.   *
  14.   * 使用说明:
  15.   * 1,首先对所定义的寄存器或线圈进行分组定义,并定义首地址。
  16.   * 2,在MBDataTable数组中添加寄存器或线圈所对应的地址。 注意 寄存器:ob = new UInt16()。线圈:ob = new byte()。
  17.   * 3,对所定义的地址 用属性进行定义 以方便在类外进行访问及了解所对应地址的含义。
  18.   * 4,GetAddressValueLength函数中 对使用说明的"第一步"分组 的元素个数进行指定。
  19.   * 5,在主程序中调用MBConfig进行协议初始化(初始化内容参考函数)。
  20.   * 6,在串口中断函数中调用MBDataReceive()。
  21.   * 7,定时器调用MBRefresh()。(10ms以下)
  22.   *    指令发送间隔时间等于实时器乘以10。 例:定时器5ms调用一次  指令发送间隔为50ms。
  23.   * 8,在主程序初始化中添加固定实时发送的指令操作 用MBAddRepeatCmd函数。
  24.   * 9,在主程序运行过程中 根据需要添加 单个的指令操作(非固定重复发送的指令)用MBAddCmd函数。
  25.   *
  26.   *
  27.   * 作者:王宏强
  28.   * 时间:2012.7.2
  29.   *
  30.   *
  31.   *
  32.   * 修正2012.1.1 修正只有一次性指令,发送最大次数不正常问题
  33.   *
  34.   *
  35. */

  36. using System;
  37. using System.Collections.Generic;
  38. using System.ComponentModel;
  39. using System.Data;
  40. using System.Drawing;
  41. using System.Text;
  42. using System.Windows.Forms;
  43. using System.IO.Ports;

  44. namespace 上位机
  45. {

  46.     public class Modbus : Form
  47.      {
  48.          #region 所用结构体
  49.          /// <summary>
  50.          /// 地址对应表元素单元
  51.          /// </summary>
  52.          public struct OPTable{
  53.              public volatile int addr;
  54.              public volatile byte type;
  55.              public volatile object ob;
  56.          };
  57.          /// <summary>
  58.          /// 当前的指令
  59.          /// </summary>
  60.          public struct MBCmd
  61.          {
  62.              public volatile int addr;           //指令首地址
  63.              public volatile int stat;           //功能码
  64.              public volatile int len;            //所操作的寄存器或线圈的个数
  65.              public volatile int res;            //返回码的状态, 0:无返回,1:正确返回
  66.          };
  67.          /// <summary>
  68.          /// 当前操作的指令管道
  69.          /// </summary>
  70.          public struct MBSci
  71.          {
  72.              public volatile MBCmd[] cmd;             //指令结构体
  73.              public volatile int index;               //当前索引
  74.              public volatile int count;               //当前功能码执行的次数
  75.              public volatile int maxRepeatCount;      //最大发送次数
  76.              public volatile int rtCount;             //实时读取的指令各数(无限间隔时间读取)
  77.          };
  78.          #endregion

  79.          #region 常量定义
  80.          public const byte MB_READ_COILS = 0x01;             //读线圈寄存器
  81.          public const byte MB_READ_DISCRETE = 0x02;          //读离散输入寄存器
  82.          public const byte MB_READ_HOLD_REG = 0x03;          //读保持寄存器
  83.          public const byte MB_READ_INPUT_REG = 0x04;         //读输入寄存器
  84.          public const byte MB_WRITE_SINGLE_COIL = 0x05;      //写单个线圈
  85.          public const byte MB_WRITE_SINGLE_REG = 0x06;       //写单寄存器
  86.          public const byte MB_WRITE_MULTIPLE_COILS = 0x0f;   //写多线圈
  87.          public const byte MB_WRITE_MULTIPLE_REGS = 0x10;    //写多寄存器

  88.          private const int MB_MAX_LENGTH = 1200;               //最大数据长度
  89.          private const int MB_SCI_MAX_COUNT = 15;             //指令管道最大存放的指令各数
  90.          private const int MB_MAX_REPEAT_COUNT = 3;           //指令最多发送次数
  91.          #endregion

  92.          #region 全局变量
  93.          private static volatile bool sciLock = false;                       //调度器锁 true:加锁  false:解锁
  94.          private static volatile byte[] buff = new byte[MB_MAX_LENGTH];      //接收缓冲器
  95.          private static volatile int buffLen = 0;
  96.          private static volatile byte[] rBuff = null;                  //正确接收缓冲器
  97.          private static volatile byte[] wBuff = null;                     //正确发送缓冲器
  98.          public static MBSci gMBSci = new MBSci() { cmd = new MBCmd[MB_SCI_MAX_COUNT], index = 0, maxRepeatCount = MB_MAX_REPEAT_COUNT, rtCount = 0, count = 0 };
  99.          private static SerialPort comm = null;
  100.          private static int mbRefreshTime = 0;
  101.          #endregion

  102.          #region MODBUS 地址对应表
  103.          //modbus寄存器和线圈分组 首地址定义
  104.          public const int D_DIO = 0x0000;


  105.          /// <summary>
  106.          /// 变量所对应的地址 在此位置
  107.          /// </summary>
  108.          public static volatile OPTable[] MBDataTable = new OPTable[1028];

  109.          public static OPTable[] gDio { get { return MBDataTable; } set { MBDataTable = value; } }

  110.          public static UInt16 gNode = 100;
  111.          public static int gBaud = 38400;
  112.          /// <summary>
  113.          /// 获取寄存器或线圈 分组后的成员各数
  114.          /// </summary>
  115.          /// <param name="addr">首地址</param>
  116.          /// <returns>成员各数</returns>
  117.          private static int GetAddressValueLength(int addr)
  118.          {
  119.              int res = 0;
  120.              switch (addr)
  121.              {
  122.                  case D_DIO: res = 514; break;
  123.                  default: break;
  124.              }
  125.              return res;
  126.          }
  127.          /// <summary>
  128.          /// 获取地址所对应的数据
  129.          /// </summary>
  130.          /// <param name="addr">地址</param>
  131.          /// <param name="type">类型</param>
  132.          /// <returns>获取到的数据</returns>
  133.          private static object GetAddressValue(int addr, byte type)
  134.          {
  135.              switch (type)       //功能码类型判断
  136.              {
  137.                  case MB_READ_COILS:
  138.                  case MB_READ_DISCRETE:
  139.                  case MB_READ_HOLD_REG:
  140.                  case MB_READ_INPUT_REG: break;
  141.                  case MB_WRITE_SINGLE_COIL:
  142.                  case MB_WRITE_MULTIPLE_COILS: type = MB_READ_DISCRETE; break;
  143.                  case MB_WRITE_SINGLE_REG:
  144.                  case MB_WRITE_MULTIPLE_REGS: type = MB_READ_HOLD_REG; break;
  145.                  default: return null;
  146.              }

  147.              for (int i = 0; i < MBDataTable.Length; i++)
  148.              {
  149.                  if (MBDataTable[i].addr == addr)
  150.                  {
  151.                      if (MBDataTable[i].type == type)
  152.                      {
  153.                          return MBDataTable[i].ob;
  154.                      }
  155.                  }
  156.              }
  157.              return null;
  158.          }
  159.          /// <summary>
  160.          /// 设置地址所对应的数据
  161.          /// </summary>
  162.          /// <param name="addr">地址</param>
  163.          /// <param name="type">类型</param>
  164.          /// <param name="data">数据</param>
  165.          /// <returns>是否成功</returns>
  166.          private static object SetAddressValue(int addr, byte type, object data)
  167.          {
  168.              for (int i = 0; i < MBDataTable.Length; i++)
  169.              {
  170.                  if (MBDataTable[i].addr == addr)
  171.                  {
  172.                      if (MBDataTable[i].type == type)
  173.                      {
  174.                          MBDataTable[i].ob = data;
  175.                          return true;
  176.                      }
  177.                  }
  178.              }
  179.              return null;
  180.          }
  181.          /// <summary>
  182.          /// 获取一连串数据
  183.          /// </summary>
  184.          /// <param name="addr">首地址</param>
  185.          /// <param name="type">功能码</param>
  186.          /// <param name="len">长度</param>
  187.          /// <returns>转换后的字节数组</returns>
  188.          private static byte[] GetAddressValues(int addr, byte type, int len)
  189.          {
  190.              byte[] arr = null;
  191.              object obj;
  192.              byte temp;
  193.              int temp2;

  194.              switch (type)
  195.              {
  196.                  case MB_WRITE_MULTIPLE_COILS:
  197.                      arr = new byte[(len % 8 == 0) ? (len / 8) : (len / 8 + 1)];
  198.                      for (int i = 0; i < arr.Length; i++)
  199.                      {
  200.                          for (int j = 0; j < 8; j++)
  201.                          {   //获取地址所对应的数据 并判断所读数据 是否被指定,有没被指定的数据 直接返回null
  202.                              obj = GetAddressValue(addr + i * 8 + j, MB_READ_COILS);
  203.                              if (obj == null)
  204.                                  return null;
  205.                              else
  206.                                  temp = Convert.ToByte(obj);
  207.                              arr[i] |=  (byte)((temp == 0? 0 : 1) << j);
  208.                          }
  209.                      }
  210.                      break;
  211.                  case MB_WRITE_MULTIPLE_REGS:
  212.                      arr = new byte[len * 2];
  213.                      for (int i = 0; i < len; i++)
  214.                      {
  215.                          obj = GetAddressValue(addr + i, MB_READ_HOLD_REG);
  216.                          if (obj == null)
  217.                              return null;
  218.                          else
  219.                              temp2 = Convert.ToInt32(obj);
  220.                          arr[i * 2] = (byte)(temp2 >> 8);
  221.                          arr[i * 2 + 1] = (byte)(temp2 & 0xFF);
  222.                      }
  223.                      break;
  224.                  default: break;
  225.              }
  226.              return arr;
  227.          }
  228.          #endregion

  229.          #region 校验
  230.          private static readonly byte[] aucCRCHi = {
  231.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  232.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  233.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  234.              0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  235.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  236.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  237.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  238.              0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  239.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  240.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  241.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  242.              0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  243.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  244.              0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  245.              0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  246.              0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  247.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  248.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  249.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  250.              0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  251.              0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  252.              0x00, 0xC1, 0x81, 0x40
  253.          };
  254.          private static readonly byte[] aucCRCLo = {
  255.              0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
  256.              0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
  257.              0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
  258.              0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
  259.              0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
  260.              0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
  261.              0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
  262.              0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
  263.              0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
  264.              0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
  265.              0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
  266.              0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
  267.              0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
  268.              0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
  269.              0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
  270.              0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
  271.              0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
  272.              0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
  273.              0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
  274.              0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
  275.              0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
  276.              0x41, 0x81, 0x80, 0x40
  277.          };
  278.          /// <summary>
  279.          /// CRC效验
  280.          /// </summary>
  281.          /// <param name="pucFrame">效验数据</param>
  282.          /// <param name="usLen">数据长度</param>
  283.          /// <returns>效验结果</returns>
  284.          public static int Crc16(byte[] pucFrame, int usLen)
  285.          {
  286.              int i = 0;
  287.              byte ucCRCHi = 0xFF;
  288.              byte ucCRCLo = 0xFF;
  289.              UInt16 iIndex = 0x0000;

  290.              while (usLen-- > 0)
  291.              {
  292.                  iIndex = (UInt16)(ucCRCLo ^ pucFrame[i++]);
  293.                  ucCRCLo = (byte)(ucCRCHi ^ aucCRCHi[iIndex]);
  294.                  ucCRCHi = aucCRCLo[iIndex];
  295.              }
  296.              return (ucCRCHi << 8 | ucCRCLo);
  297.          }

  298.          #endregion

  299.          #region 发送指命操作
  300.          /// <summary>
  301.          /// 首部分数据 node:节点
  302.          /// </summary>
  303.          /// <param name="addr">寄存器地址</param>
  304.          /// <param name="len">数据长度,或单个数据</param>
  305.          /// <param name="stat"></param>
  306.          /// <returns></returns>
  307.          private static byte[] SendTrainHead(int node, int addr, int len, byte stat)
  308.          {
  309.              byte[] head = new byte[6];

  310.              head[0] = Convert.ToByte(node);
  311.              head[1] = stat;
  312.              head[2] = (byte)(addr >> 8);
  313.              head[3] = (byte)(addr & 0xFF);
  314.              head[4] = (byte)(len >> 8);
  315.              head[5] = (byte)(len & 0xFF);

  316.              return head;
  317.          }
  318.          /// <summary>
  319.          /// 计算数据长度 并在0x0f,0x10功能下 加载字节数
  320.          /// </summary>
  321.          /// <param name="arr"></param>
  322.          /// <param name="len"></param>
  323.          /// <param name="stat"></param>
  324.          /// <returns></returns>
  325.          private static byte[] SendTrainBytes(byte[] arr, ref int len, byte stat)
  326.          {
  327.              byte[] res;
  328.              switch (stat)
  329.              {
  330.                  default: len = 0; break;

  331.                  case MB_READ_COILS:
  332.                  case MB_READ_DISCRETE:
  333.                  case MB_READ_HOLD_REG:
  334.                  case MB_READ_INPUT_REG:
  335.                  case MB_WRITE_SINGLE_COIL:
  336.                  case MB_WRITE_SINGLE_REG:
  337.                      len = 0;
  338.                      break;

  339.                  case MB_WRITE_MULTIPLE_COILS:
  340.                      len = (len % 8 == 0) ? (len / 8) : (len / 8 + 1);
  341.                      res = new byte[arr.Length + 1];
  342.                      arr.CopyTo(res, 0);
  343.                      res[arr.Length] = (byte)(len);
  344.                      arr = res;
  345.                      break;

  346.                  case MB_WRITE_MULTIPLE_REGS:
  347.                      len *= 2;
  348.                      res = new byte[arr.Length + 1];
  349.                      arr.CopyTo(res, 0);
  350.                      res[arr.Length] = (byte)len;      //把字节写入数据最后位置
  351.                      arr = res;
  352.                      break;

  353.              }
  354.              return arr;
  355.          }
  356.          /// <summary>
  357.          /// 主控方式  发送指令模板
  358.          /// </summary>
  359.          /// <param name="node">节点</param>
  360.          /// <param name="data">数据</param>
  361.          /// <param name="addr">地址</param>
  362.          /// <param name="con">变量各数</param>
  363.          /// <param name="stat">功能码</param>
  364.          /// <returns></returns>
  365.          private static byte[] SendTrainCyclostyle(int node, byte[] data, int addr, int con, byte stat)
  366.          {
  367.              int crcVal = 0;
  368.              byte[] headData = SendTrainHead(node, addr, con, stat);                   //写首部分数据
  369.              byte[] headDataLen = SendTrainBytes(headData, ref con, stat);       //计算数据的长度,有字节则写入。
  370.              byte[] res = new byte[headDataLen.Length + con + 2];

  371.              headDataLen.CopyTo(res, 0);

  372.              if ((stat == MB_WRITE_MULTIPLE_REGS) || (stat == MB_WRITE_MULTIPLE_COILS))
  373.                  Array.Copy(data, 0, res, headDataLen.Length, con);                   //把数据复制到数据中

  374.              crcVal = Crc16(res, res.Length - 2);
  375.              res[res.Length - 2] = (byte)(crcVal & 0xFF);
  376.              res[res.Length - 1] = (byte)(crcVal >> 8);

  377.              return res;
  378.          }
  379.          /// <summary>
  380.          /// 封装发送数据帧
  381.          /// </summary>
  382.          /// <param name="node">从机地址</param>
  383.          /// <param name="cmd">指令信息</param>
  384.          /// <returns></returns>
  385.          private static byte[] SendPduPack(int node, MBCmd cmd)
  386.          {
  387.              byte[] res = null;
  388.              switch (cmd.stat)
  389.              {
  390.                  case MB_READ_COILS:
  391.                  case MB_READ_DISCRETE:
  392.                  case MB_READ_HOLD_REG:
  393.                  case MB_READ_INPUT_REG:
  394.                  case MB_WRITE_SINGLE_COIL:
  395.                  case MB_WRITE_SINGLE_REG:
  396.                      res = SendTrainCyclostyle(node, null, cmd.addr, cmd.len, (byte)cmd.stat); break;

  397.                  case MB_WRITE_MULTIPLE_COILS:
  398.                  case MB_WRITE_MULTIPLE_REGS:
  399.                      byte[] data = GetAddressValues(cmd.addr, (byte)cmd.stat, cmd.len);
  400.                      res = SendTrainCyclostyle(node, data, cmd.addr, cmd.len, (byte)cmd.stat); break;
  401.              }
  402.              return res;
  403.          }
  404.          #endregion

  405.          #region 回传数据操作
  406.          /// <summary>
  407.          /// 存储回传的线圈
  408.          /// </summary>
  409.          /// <param name="data">回传的数组</param>
  410.          /// <param name="addr">首地址</param>
  411.          /// <returns>存储是否正确</returns>
  412.          private static bool ReadDiscrete(byte[] data, int addr)
  413.          {
  414.              bool res = true;
  415.              int len = data[2];

  416.              if (len != (data.Length - 5))  //数据长度不正确 直接退出
  417.                  return false;

  418.              for (int i = 0; i < len; i++)
  419.              {
  420.                  for (int j = 0; j < 8; j++)
  421.                  {
  422.                      if (SetAddressValue(addr + i * 8 + j, data[1], data[i + 3] & (0x01 << j)) == null)
  423.                      {
  424.                          return false;
  425.                      }
  426.                  }
  427.              }
  428.              return res;
  429.          }
  430.          /// <summary>
  431.          /// 读回传的寄存器
  432.          /// </summary>
  433.          /// <param name="data">回传的数组</param>
  434.          /// <param name="addr">首地址</param>
  435.          /// <returns>存储是否正确</returns>
  436.          private static bool ReadReg(byte[] data, int addr)
  437.          {
  438.              bool res = true;
  439.              int len = data[2];

  440.              if (len != (data.Length - 5))  //数据长度不正确 直接退出
  441.                  return false;

  442.              for (int i = 0; i < len; i += 2)
  443.              {
  444.                  if (SetAddressValue(addr + i / 2, data[1], (data[i + 3] << 8) | data[i + 4]) == null)
  445.                  {
  446.                      res = false;
  447.                      break;
  448.                  }
  449.              }
  450.              return res;
  451.          }
  452.          /// <summary>
  453.          /// 回传的数据处理
  454.          /// </summary>
  455.          /// <param name="buff">回传的整帧数据</param>
  456.          /// <param name="addr">当前所操作的首地址</param>
  457.          /// <returns></returns>
  458.          private static bool ReceiveDataProcess(byte[] buff, int addr)
  459.          {
  460.              if (buff == null)
  461.                  return false;
  462.              if (buff.Length < 5)    //回传的数据 地址+功能码+长度+2效验 = 5字节
  463.                  return false;

  464.              bool res = true;
  465.              switch (buff[1])
  466.              {
  467.                  case MB_READ_COILS: ReadDiscrete(buff, addr); break;
  468.                  case MB_READ_DISCRETE: ReadDiscrete(buff, addr); break;
  469.                  case MB_READ_HOLD_REG: ReadReg(buff, addr); break;
  470.                  case MB_READ_INPUT_REG: ReadReg(buff, addr); break;
  471.                  case MB_WRITE_SINGLE_COIL:
  472.                  case MB_WRITE_SINGLE_REG:
  473.                  case MB_WRITE_MULTIPLE_COILS:
  474.                  case MB_WRITE_MULTIPLE_REGS: break;
  475.                  default: res = false; break;
  476.              }
  477.              return res;
  478.          }
  479.          #endregion

  480.          #region 收发调度
  481.          /// <summary>
  482.          /// 添加重复操作指令
  483.          /// </summary>
  484.          /// <param name="sci">待发送的指命管道</param>
  485.          /// <param name="addr">所添加指令的首地址</param>
  486.          /// <param name="len">所添加指令的寄存器或线圈个数</param>
  487.          /// <param name="stat">所添加指令的功能码</param>
  488.          private static void SciAddRepeatCmd(ref MBSci sci, int addr, int len, int stat)
  489.          {
  490.              if (sci.rtCount >= MB_SCI_MAX_COUNT - 1)  //超出指令管道最大长度 直接退出
  491.                  return;
  492.              if (len == 0)                               //地址的数据长度为空 直接退出
  493.                  return;

  494.              sci.cmd[sci.rtCount].addr = addr;
  495.              sci.cmd[sci.rtCount].len = len;
  496.              sci.cmd[sci.rtCount].stat = stat;
  497.              sci.cmd[sci.rtCount].res = 0;
  498.              sci.rtCount++;
  499.          }
  500.          /// <summary>
  501.          /// 添加一次性操作指令
  502.          /// </summary>
  503.          /// <param name="sci">待发送的指命管道</param>
  504.          /// <param name="addr">所添加指令的首地址</param>
  505.          /// <param name="len">所添加指令的寄存器或线圈个数</param>
  506.          /// <param name="stat">所添加指令的功能码</param>
  507.          private static void SciAddCmd(ref MBSci sci, int addr, int len, int stat)
  508.          {
  509.              if (len == 0)                               //地址的数据长度为空 直接退出
  510.                  return;

  511.              for (int i = sci.rtCount; i < MB_SCI_MAX_COUNT; i++)
  512.              {
  513.                  if (sci.cmd[i].addr == -1)      //把指令载入到空的管道指令上
  514.                  {
  515.                      sci.cmd[i].addr = addr;
  516.                      sci.cmd[i].len = len;
  517.                      sci.cmd[i].stat = stat;
  518.                      sci.cmd[i].res = 0;
  519.                      break;
  520.                  }
  521.              }
  522.          }
  523.          /// <summary>
  524.          /// 清空重复读取指令集
  525.          /// </summary>
  526.          /// <param name="sci">待发送的指命管道</param>
  527.          private static void SciClearRepeatCmd(ref MBSci sci)
  528.          {
  529.              sci.rtCount = 0;
  530.          }
  531.          /// <summary>
  532.          /// 清空一次性读取指令集
  533.          /// </summary>
  534.          /// <param name="sci">待发送的指命管道</param>
  535.          private static void SciClearCmd(ref MBSci sci)
  536.          {
  537.              for (int i = sci.rtCount; i < MB_SCI_MAX_COUNT; i++)
  538.              {
  539.                  sci.cmd[i].addr = -1;
  540.                  sci.cmd[i].len = 0;
  541.                  sci.cmd[i].res = 0;
  542.              }
  543.          }
  544.          /// <summary>
  545.          /// 跳到下一个操作指令
  546.          /// </summary>
  547.          /// <param name="sci">待发送的指命管道</param>
  548.          private static void SciJumbNext(ref MBSci sci)
  549.          {
  550.              if (sci.index >= sci.rtCount)           //非实时读取地址会被清除
  551.              {
  552.                  sci.cmd[sci.index].addr = -1;
  553.                  sci.cmd[sci.index].len = 0;
  554.                  sci.cmd[sci.index].stat = 0;
  555.              }

  556.              do{
  557.                  sci.index++;
  558.                  if (sci.index >= MB_SCI_MAX_COUNT)    //超出指令最大范围
  559.                  {
  560.                      sci.index = 0;
  561.                      if (sci.rtCount == 0)               //如果固定实时读取 为空 直接跳出
  562.                          break;
  563.                  }

  564.              } while (sci.cmd[sci.index].addr == -1);
  565.              sci.cmd[sci.index].res = 0;             //本次返回状态清零
  566.          }
  567.          /// <summary>
  568.          /// 发送指令调度锁定
  569.          /// </summary>
  570.          public static void SciSchedulingLock()
  571.          {
  572.              sciLock = true;
  573.          }
  574.          /// <summary>
  575.          /// 发送指令调度解锁
  576.          /// </summary>
  577.          public static void SciSchedulingUnlock()
  578.          {
  579.              sciLock = false;
  580.          }
  581.          /// <summary>
  582.          /// 待发送的指令管道调度
  583.          /// </summary>
  584.          /// <param name="sci">待发送的指命管道</param>
  585.          /// <param name="rBuf">收到正确的回传数据</param>
  586.          /// <param name="wBuf">准备发送的指令数据</param>
  587.          private static void SciScheduling(ref MBSci sci, ref byte[] rBuf, ref byte[] wBuf)
  588.          {
  589.              if (sciLock)   //如果被加锁 直接退出
  590.                  return;

  591.              if (sci.cmd[0].addr == -1)
  592.                  return;

  593.              if ((sci.cmd[sci.index].res != 0) || (sci.count >= sci.maxRepeatCount))
  594.              {
  595.                  sci.count = 0;       //发送次数清零
  596.                  if (sci.cmd[sci.index].res != 0)    //如果收到了正常返回
  597.                  {
  598.                      ReceiveDataProcess(rBuf, sci.cmd[sci.index].addr);     //保存数据
  599.                      rBuf = null;        //清空当前接收缓冲区的内容, 以防下次重复读取
  600.                  }
  601.                  else
  602.                  {
  603.                      //参数操作失败
  604.                  }

  605.                  SciJumbNext(ref sci);
  606.              }
  607.              wBuf = SendPduPack((int)gNode, sci.cmd[sci.index]);     //发送指令操作
  608.              sci.count++;                            //发送次数加1
  609.          }
  610.          /// <summary>
  611.          /// 快速刷新 处理接收到的数据   建议:10ms以下
  612.          /// </summary>
  613.          /// <returns>所正确回传数据的功能码, null:回传不正确</returns>
  614.          private static int MBQuickRefresh()
  615.          {
  616.              int res = -1;
  617.              if (rBuff != null)
  618.              {
  619.                  SciSchedulingLock();
  620.                  if (ReceiveDataProcess(rBuff, gMBSci.cmd[gMBSci.index].addr) == true)
  621.                  {
  622.                      gMBSci.cmd[gMBSci.index].res = 1;   //标记 所接收到的数据正确
  623.                      res = gMBSci.cmd[gMBSci.index].stat;
  624.                  }
  625.                  rBuff = null;
  626.                  SciSchedulingUnlock();
  627.              }
  628.              return res;
  629.          }
  630.          /// <summary>
  631.          /// 调度间隔时间刷新        建议:50ms以上
  632.          /// </summary>
  633.          /// <returns>封装好的协议帧</returns>
  634.          private static void MBSchedRefresh()
  635.          {
  636.              SciScheduling(ref gMBSci, ref rBuff, ref wBuff);
  637.              if (wBuff != null)
  638.                  comm.Write(wBuff, 0, wBuff.Length);
  639.          }

  640.          #endregion

  641.          #region 接口函数
  642.          /// <summary>
  643.          /// 清空存放一次性的指令空间
  644.          /// </summary>
  645.          public static void MBClearCmd()
  646.          {
  647.              SciClearCmd(ref gMBSci);
  648.          }
  649.          /// <summary>
  650.          /// 添加固定刷新(重复) 操作指令
  651.          /// </summary>
  652.          /// <param name="addr">地址</param>
  653.          /// <param name="stat">功能码</param>
  654.          public static void MBAddRepeatCmd(int addr, byte stat)
  655.          {
  656.              for (int i = 0; i < GetAddressValueLength(addr); i++ )
  657.                  if (GetAddressValue(addr, stat) == null)        //如果所添加的指令没有在MODBUS对应表中定义 直接退出
  658.                      return;
  659.              SciAddRepeatCmd(ref gMBSci, addr, GetAddressValueLength(addr), stat);
  660.          }
  661.          /// <summary>
  662.          /// 添加一次性 操作指令
  663.          /// </summary>
  664.          /// <param name="addr"></param>
  665.          /// <param name="stat"></param>
  666.          public static void MBAddCmd(int addr, byte stat)
  667.          {
  668.              for (int i = 0; i < GetAddressValueLength(addr); i++)
  669.                  if (GetAddressValue(addr, stat) == null)        //如果所添加的指令没有在MODBUS对应表中定义 直接退出
  670.                      return;
  671.              SciAddCmd(ref gMBSci, addr, GetAddressValueLength(addr), stat);
  672.          }
  673.          /// <summary>
  674.          /// 串口参数配置
  675.          /// </summary>
  676.          /// <param name="commx">所用到的串口</param>
  677.          /// <param name="node"></param>
  678.          /// <param name="baud"></param>
  679.          public static void MBConfig(SerialPort commx, UInt16 node, int baud)
  680.          {
  681.              gBaud = baud;
  682.              gNode = node;
  683.              comm = commx;
  684.              SciClearRepeatCmd(ref gMBSci);
  685.              SciClearCmd(ref gMBSci);
  686.          }
  687.          /// <summary>
  688.          /// 读取串口中接收到的数据
  689.          /// </summary>
  690.          /// <param name="comm">所用到的串口</param>
  691.          public static void MBDataReceive()
  692.          {
  693.              if (comm == null)                       //如果串口没有被初始化直接退出
  694.                  return;
  695.              SciSchedulingLock();
  696.              System.Threading.Thread.Sleep(10);      //等待缓冲器满
  697.              if (!comm.IsOpen)
  698.                  return;

  699.              buffLen = comm.BytesToRead;          //获取缓冲区字节长度
  700.              if (buffLen > MB_MAX_LENGTH)            //如果长度超出范围 直接退出
  701.              {
  702.                  SciSchedulingUnlock();
  703.                  return;
  704.              }
  705.              comm.Read(buff, 0, buffLen);            //读取数据
  706.              if (gMBSci.cmd[gMBSci.index].stat == buff[1])
  707.              {
  708.                  if (Crc16(buff, buffLen) == 0)
  709.                  {
  710.                      rBuff = new byte[buffLen];
  711.                      Array.Copy(buff, rBuff, buffLen);
  712.                  }
  713.              }
  714.              SciSchedulingUnlock();
  715.          }
  716.          /// <summary>
  717.          /// MODBUS的实时刷新任务,在定时器在实时调用此函数
  718.          /// 指令发送间隔时间等于实时器乘以10。 例:定时器5ms调用一次  指令发送间隔为50ms。
  719.          /// </summary>
  720.          /// <returns>返回当前功能读取指令回传 的功能码</returns>
  721.          public static int MBRefresh()
  722.          {
  723.              if (sciLock)   //如果被加锁 直接退出
  724.                  return 0;

  725.              mbRefreshTime++;
  726.              if (mbRefreshTime > 10)
  727.              {
  728.                  mbRefreshTime = 0;
  729.                  MBSchedRefresh();
  730.              }
  731.              return MBQuickRefresh();
  732.          }
  733.          #endregion


  734.      }

  735. }
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:625650 发表于 2019-10-17 15:19 | 只看该作者
学习学习哈,这个什么烧写器都适用吗
回复

使用道具 举报

板凳
ID:779899 发表于 2020-10-21 18:10 | 只看该作者

学习学习哈,这个什么烧写器都适用吗
回复

使用道具 举报

地板
ID:654797 发表于 2022-3-1 22:04 | 只看该作者
这是烧写什么芯片的呀
回复

使用道具 举报

5#
ID:87000 发表于 2022-7-28 09:20 | 只看该作者
vscos 发表于 2022-3-1 22:04
这是烧写什么芯片的呀

这只是上位机串口工具,还需你自己去实现下位机来执行烧写过程
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表