ModbusClass

namespace ModbusDemo
{
internal class BaseDataRequest
{
public string provinceId { get; set; }
}
}
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
namespace ModbusDemo
{
internal class CertificateTools
{
public static List GetSoftCerts(string pinPassword)
{
List result = new List();
//string strFileFullPath = Application.StartupPath + @"\necc.crt";
//X509Certificate cer = new X509Certificate(strFileFullPath, pinPassword);
//result.Add(cer);
return result;
}
}
}
namespace ModbusDemo
{
internal class FetchServerResponse
{
///
/// 返回码
///
public string responseCode { get; set; }

    /// <summary>
    /// 状态提示
    /// </summary>
    public string responseMessage { get; set; }

    /// <summary>
    /// 设备序列号 GUID 
    /// </summary>
    public string provinceId { get; set; }

    /// <summary>
    /// 基础数据下载地址
    /// </summary>
    public string loadConfigURL { get; set; }

    /// <summary>
    /// 平台版本下载地址
    /// </summary>
    public string loadDicVersionURL { get; set; }

    /// <summary>
    /// 用能单位基础信息配置上传地址
    /// </summary>
    public string centerInfoURL { get; set; }

    /// <summary>
    /// 采集数据上传地址
    /// </summary>
    public string centerDataURL { get; set; }

    /// <summary>
    /// 用能单位基础信息配置下载地址
    /// </summary>
    public string centerInfoDownloadURL { get; set; }

    /// <summary>
    /// 采集数据下载地址
    /// </summary>
    public string centerDataDownloadURL { get; set; }

    /// <summary>
    /// 上报时间点
    /// </summary>
    public string uploadTime { get; set; }

}

}
using System;
using System.Collections.Generic;
using System.Text;

namespace ModbusDemo.Modbus
{
class Info
{
/*
设备通信 modbus 格式 能干啥
环境下 涉及到 数据传输格式 数组 每个字节代表什么意思 基本的报文解析
来自于模拟器 相关模拟器来学习
C#代码进行组装实战
上位机开发的常用协议 通信协议五花八门 常见的的协议入手 Modbus
深入了解Modbus协议结构
报文的组装与请求响应
C#语法基础 基础语法 多线程
2通信组件:Socket\ Socket(网口TcpClient,UdpClient)\SerialPort(串口通信)
电脑串口 公共机定制的 家用的开发电脑 没有串口 USB转接线
深入理解 协议结构 怎么样转接线
应用 应用
SocketClient连接 SocketTcp服务
Encoding.UTF-8.GetBytes(“Hello”); 从相关设备获取数据发送指令 保证数据的准确性
信息有多长
协议代码实战,报文组装与收发
录屏->视频 代码跑不下来啊 QQ
一键三连
工业电子 数字工厂 工业现场 通信协议 modbus协议 接触的机会非常多
Modbus特点 不需要钱 支持多种电气接口:各种介质传输
格式简单、紧凑、通俗易懂、容易上手
字节转换成0101
协议:数据传输格式:byte->0101001000100100100010101
能不能解析 最多的电接口
针对不同的电接口 通信协议一定在接口上用 应用层协议
modbus协议 支持多种电气接口:各种介质传输
串口:232,422,485 网口RJ485
ModBus协议分类
串口:ModbusRTU,ModbusAscii
网口:ModbusTCP,ModbusUDP RTU Over TCP
远程终端单元(Remote Terminal Unit,RTU),一种针对通信距离较长和工业现场环境恶劣儿设计的具有
模块化结构的、特殊的计算机测控单元
远程终端单元(Remote Terminal Unit,RTU)
远程终端单元(Remote Terminal Unit,RTU)
远程终端单元(Remote Terminal Unit,RTU)
缩略语
ADU 应用数据单元
HDLC 高级数据链路控制
HMI 人机界面
IETF 因特网工程工作组
I/O 输入/输出设备
IP 互联网协议
MAC 介质访问控制
MB ModBus协议
Mbap Modbus协议
Pdu 协议数据单元
Plc 可编程逻辑控制
串口上的COM口,COM口即串行通讯端口。微机上的com口多为9帧,最大速率115200bps.通常用于连接鼠标
(串口)及通讯设备(如连接外置式Modem进行数据通讯)等。但目前主流的主板一般都只带一个串口
甚至不带
机箱后面,梯形的、两排、一排5个口,一排4个口
一般有两个,就是com1,com2 背板上应该都标明的
反正要么上1下2,要么左1右1
2设备上的Serial口
专为广域网设计,它可以做ISDN,PPP,帧中继等网络类型的连接可以接很多网络类型
要使用它必须设置时钟频率(DCE,DTE),路由表的算法也在此接口上形成,。以太网口是对局域网内的
它只拥有局域网所需要的所有功能。没有广域网接口所需要的功能,而广域网串口也没有局域网以外网口接口的功能
所以两个接口是不能对调的
1路由器连接路由器就要用路由器上的Serial端口连接,不过现在的路由器都没有这些,都用光口代替了
2ethernet口:以太网口,现在可以说是百兆口,交换机间连在一起用的
3以太口(eth)是接RJ45水晶头的,串口(ser)是远距离连接使用的!可以是电缆也可以是光纤
4串口是串行口通讯协议,以太网口是以太网协议
1位、字节、字符
2设备地址
3常用地址(需要设备进行相关响应的标记)1,2,3,4,5,6,15,16 1-127 0111
4寄存器
最小单位是字节
C#里面 byte[] datas = new byte[10];最小处理byte 一个byte就是8个位
ToSingle(Stirng,IFormatProvider) 使用指定的区域性特定格式设置信息,将数字的指定字符串表示形式转换为
等效的单精度浮点数
ToSingle(Object,IFormatProvider)使用指定的区域性特定
常用功能码(需要设备进行相关响应的标记)1(读线圈状态)2(读输入线圈)3读保持型寄存器
4读输入寄存器 5,6,15,16
3读保持型寄存器 3读保持型寄存器 3读保持型寄存器 3读保持型寄存器3读保持型寄存器
3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器
3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器
3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器
3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器3读保持型寄存器
3读保持型寄存器3读保持型寄存器
ID 名称 数值 单位 读 指令 写 区块 地址 数量 位偏移 位数 系数 范围 批量读 批量写
1 测试数据BIT1 – – 读 – 写 线圈状态(RW) 100 1 0 1 1 – 已选择 未选择
11 寄存器位数据1 – – 读 – 写 离散输入RO 200 1 0 1 1 – 已选择 未选择

    01 03 4E A5 C5 83 81 C0 60 06 00 D1 FF
    01 03 11 A3 00 06 30 D6
    01 03 4E A9 EB 4B 60 01 00 C0 1C 00 45
    01 03 11 A3 00 06 30 D6
    01 6B AD AD ED 05 00 60 60 06 00 DE FF
  输入需要解析的报文PDU(功能码+数据)
    1
    01 03 04 01 10 01 BA 7A 29
    01 03 11 A3 00 06 30 D6
    modbus查表法
    CRC简单函数如下
    unsigned short CRC16(puchMsg,usDataLen)
    unsigned char *puchMsg;/*要进行CRC校验的消息*
    unsigned short usDataLen;/消息中字节数/
    {
      unsigned char uchCRCHi = 0xFF高CRC字节初始化
      unsigned char uchCRCLp = 0xFF;低CRC字节初始化
    unsinged uIndex;CRC循环中的索引
    while(usDataLen--)传输消息缓冲区
    {
    uIndex = uchCRCHi^*pushMsgg++;计算CRC
    uuchCRCHi = uchCRCLo^auchCRCHi[uIndex];
    uchCRCLo = auchCRCLo[uIndex];
    }
    return (uchCRCHI<<8 uchCRCLo);
    CRC高位字节值表
    static unsigned char auchCRCHi[] = 
    {
     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,x040,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,x000,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,
    0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,x001,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
    }
    CRC低位字节值表
    static char auchCRCLo[] = {
    0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,
    0x07,0xC7,0x05,0xC5,0xC4,0x04,0xCC,0x0C,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,ox7C,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
    }
     
     */
}

}
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;

namespace ModbusDemo
{
public static class ModbusStudy
{
public static void Test_0x10()
{
ushort startAddr = 2;
ushort writeLen = 4;
float[] values = new float[] { 123.45f, 14.3f };

        //请求
        //byte[] 需要指定长度;不支持Linq
        List<byte> command = new List<byte>();
        command.Add(0x01);//1号从站
        command.Add(0x10);//功能码:写三个保持型寄存器

        //写入地址
        command.Add(BitConverter.GetBytes(startAddr)[1]);
        command.Add(BitConverter.GetBytes(startAddr)[0]);
        //写入数量
        command.Add(BitConverter.GetBytes(writeLen)[1]);
        command.Add(BitConverter.GetBytes(writeLen)[0]);

        //获取数值的byte[]
        List<byte> valueBytes = new List<byte>();
        for (int i = 0; i < values.Length; i++)
        {
            List<byte> temp = new List<byte>(BitConverter.GetBytes(values[i]));
            temp.Reverse();//调整字节序
            valueBytes.AddRange(temp);
        }

        //字节数
        command.Add((byte)valueBytes.Count);
        command.AddRange(valueBytes);

        //CRC 
        command = CRC16(command);

        //报文组装完成
        //发送-》SerialPort
        SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
        //打开串口
        serialPort.Open();

        serialPort.Write(command.ToArray(), 0, command.Count);
    }

    static List<byte> CRC16(List<byte> value, ushort poly = 0xA001, ushort crcInit = 0xFFFF)
    {
        if (value == null || !value.Any())
        {
            throw new ArgumentException("");
        }
        //运算
        ushort crc = crcInit;
        for (int i = 0; i < value.Count; i++)
        {
            crc = (ushort)(crc ^ (value[i]));
            for (int j = 0; j < 8; j++)
            {
                crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ poly) : (ushort)(crc >> 1);
            }
        }

        byte hi = (byte)((crc & 0xFF00) >> 8);//高位置
        byte lo = (byte)(crc & 0x00FF);//低位置
        List<byte> buffer = new List<byte>();
        buffer.AddRange(value);
        buffer.Add(lo);
        buffer.Add(hi);
        return buffer;

    }

    /*
     数据结构:
    数组*Array
    栈*Stack集装箱栈顶元素可以操作
    队列*Queue多线程阻塞队列管理
    链表*Linked List
    散列表*Hash
    堆*Heap
    树*Tree
    串口通讯,9600波特率数据格式是8,N1,请问疫苗可传输多少个字节的数据9600,n,8,1
    实际上,在发送一个字节的时候,除了需要发送8Bit数据外,还需要发送1bit开始位,1bit停止位,1bit的校验
    加起来发送一个字节就是11bit
    因此1秒发送字节=9600/8+1+1+1 = 872
    串口通信最重要的参数是波特率、数据位、停止位和奇偶校验,对于两个进行通行的端口
    这些参数必须匹配波特率
    停止位
    用于表示单个包的最后一位。典型值为1,1.5和2位。由于数据实在传输线上定时的,并且每一个设备有其自己的始终,很可能在通信中两台设备
    键出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多
    不同始终同步的容忍程度越大,但是数据传输率同时也圆满
    奇偶校验位
    在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于奇偶校验情况,串口哦会
    设置校验位(数据位后面的一位),用一个值确保传输的数据由偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0
    保证逻辑搞得位数是偶数个
    这样使得接收设备能够知道一个位的状态,有机会判断是否由噪声高饶勒通信或者是否传输和接收数据是否不同步
    每秒位数。该参数表示每秒传输的比特数。例如,对于发送端,2400波特率表示每秒发送2400bit;对于接收端而言,2400波特率意味着串口通信在数据线上的
    采样率为2400Hz.由于波特率和距离之间成反比,距离相隔很近的设备间才可以实现高波特率通信
    数据位
    表示通信中实际数据位的参数。在计算机发送的数据包中,实际的数据往往不会是8位。在串口通信中,可以选择5,6,7或8位
    如果6.14所示。设定数据位主要考虑要传输的数据内容。如果要传输的是标准ASCII码,由于ASCII码的范围是0~127,因此使用7位就可以了
    如果要传输的是扩展ASCII码,其范围是0~255,必须使用8位。当然,7位或8位数据位不仅仅是胡数据,还包括开始、停止位、数据位以及
    奇偶校验位等

     */
}

public class UnitModel<T> where T : new()
{
    public int startAdr { get; set; }//起地址
    public int index { get; set; }//位号
    public int length { get; set; }//字节长度

    public string order { get; set; }//顺序"ABCD",
    public string type { get; set; }//类型
    public string codetype { get; set; }//编码格式
    public T value { get; set; }

    /*
     我们的串口程序,除了通用的,进行串口监听收发的简单工具,大多都和下位机有关,这就需要关系我们的通信协议如何缓存
    分析以及通知界面
    我们先说一下通讯协议。通讯协议就是通讯双方共同遵循一套规则,定义协议的原则是尽可能的简单以提高传输率,尽可能地具有
    安全性保证数据传输完整正确基于2点规则,通讯协议应该是这样的:头+数据长度+数据正文+校验
    例如: AA 44 05 01 02 03 05 05 EA
     */
}

}

namespace ModbusDemo
{
internal class PublicClass
{
private static object m_lockObj = new object();
private static PublicClass m_public;

    public static PublicClass CreateInstance() 
    {
        if (m_public == null)
        {
            m_public = new PublicClass();
        }
        return m_public;
    }

    public FetchServerResponse _para;

    public FetchServerResponse FetchPara 
    {
        get 
        {
            return _para;
        }
        set { }
    }
}

}
//using System;
//using System.Collections.Generic;
//using System.IO.Ports;
//using System.Text;

//namespace ModbusDemo.Modbus
//{
// public class RTU
// {
// public Action<int, List> ResponseData;

// private static RTU _instance;
// private static SerialInfo _serialInfo;

// SerialPort _serialPort;
// bool _isBuding = false;

// int _currentSlave;
// int _funcCode;
// int _wordLen;
// int _startAddr;

// private RTU(SerialInfo serialInfo)
// {
// _serialPort = new SerialPort();
// _serialInfo = new SerialInfo();
// }

// public static RTU GetInstance(SerialInfo serialInfo)
// {
// lock (“rtu”)
// {
// if (_instance == null)
// {
// _instance = new RTU(serialInfo);
// return _instance;
// }
// }
// }

// public bool Connection()
// {
// try
// {
// if (_serialPort.IsOpen)
// {
// _serialPort.Close();
// }
// _serialPort.PortName = _serialPort.PortName;
// _serialPort.BaudRate = _serialPort.BaudRate;
// _serialPort.DataBits = _serialPort.DataBits;
// _serialPort.Parity = _serialPort.Parity;
// _serialPort.StopBits = _serialPort.StopBits;

// _serialPort.ReceivedBytesThreshold = 1;
// _serialPort.DataReceived += _serialPort_DataReceived;
// }
// catch (Exception)
// {

// return false;
// }
// }

// byte[] _byteBuffer = new byte[512];
// private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
// {
// byte _receiveBites;
// while (_serialPort.BytesToRead > 0)
// {
// _receiveBites = (byte)_serialPort.ReadByte();
// //_byteBuffer
// }
// }
// }
//}
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;

namespace ModbusDemo
{
public class SerialInfo
{
public string PortName { get; set; } = “COM1”;
public int BaudRate { get; set; } = 9600;
public int DataBit { get; set; } = 8;
public Parity Parity { get; set; } = Parity.None;

    public StopBits StopBits { get; set; } = StopBits.One;
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值