前言
前面我們介紹了ModBusTcp協議,今天我們接著來介紹ModBusRtu協議,和ModBusTcp不同的是ModBusRtu基于串口通信,ModBusTcp是基于Tcp以太網通信,
所以我們在講解ModBusRtu協議之前會先介紹下串口通信,
串口通信
串口出現在1980年前后,當初主要目的是用來做電腦外設設備的連接,如滑鼠、鍵盤等,現在最新的電腦慢慢的取消了原始的串口介面,不過依然廣泛用于工控和測量等設備,
串口通信引數
串口通信指的是串口按位(bit)發送和接收位元組,串口通信引數主要有波特率、資料位、停止位、校驗位,
波特率
波特率表達的是串口通信的速率,一秒鐘內傳送的信號單元(碼元)個數,信號單元一般包含10位(7個資料位、1個校驗位、1到2個停止位),注意:波特率和距離成反比
資料位
通信中實際的資料,有效值為6、7和8,
停止位
用來表示單個包的最后一位,有效值為1、1.5和2,停止位可用來表示傳輸的結束和校正時鐘同步,注意:停止位的位數越多,時鐘同步的容忍程度越大,但是資料傳輸率會越慢,
校驗位
奇偶校驗作為通信中的檢錯方式,如果發現錯誤則重新發送,
| 示例資料 | 偶校驗位 | 奇校驗位 |
|---|---|---|
| 0000000 | 00000000 | 00000001 |
| 1010001 | 10100011 | 10100010 |
| 1101001 | 11010010 | 11010011 |
| 1111111 | 11111111 | 11111110 |
從上可以看出奇偶校驗就是在資料最后加一位,使資料中的1的數量保持偶數或奇數,
波特率和位元率 (擴展知識)
位元率是我們常用來表達寬帶速率的一種方法,看上去和波特率很像,如果波特率的信號碼元只傳1位元(bit),那么它們之間是相等的,如果波特率的信號碼元傳10位元,那么波特率是位元率的10倍,所以,波特率和位元率表達的意義是不一樣的,不要搞混了,
寬帶位元率的實際下載速度 (擴展知識)
Mbps和Mbit/s等效、kbit/s和kbps等效、bps和bit/s等效
1Mbps(Mbit/s) = 11024kbit(kbit/s) = 11024*1024bps(bit/s),注意他們的單位都是bit(位元),而不是byte(位元組),所以實際下載速度要除以八,1024 / 8 = 128 kb/s,
CRC16校驗
CRC,Cyclic Redundancy Check回圈冗余檢驗,是基于資料計算一組效驗碼,用于核對資料傳輸程序中是否被更改或傳輸錯誤,而ModBusRtu用到的是其中的CRC16校驗,
其計算原理,可參考 1、2、3
以下是CRC16反向演算法,經測驗可用于ModBusRtu的CRC計算,
public class CRC16
{
/// <summary>
/// 驗證CRC16校驗碼
/// </summary>
/// <param name="value">校驗資料</param>
/// <param name="poly">多項式碼</param>
/// <param name="crcInit">校驗碼初始值</param>
/// <returns></returns>
public static bool CheckCRC16(byte[] value, ushort poly = 0xA001, ushort crcInit = 0xFFFF)
{
if (value =https://www.cnblogs.com/zhaopei/p/= null || !value.Any())
throw new ArgumentException("生成CRC16的入參有誤");
var crc16 = GetCRC16(value, poly, crcInit);
if (crc16[crc16.Length - 2] == crc16[crc16.Length - 1] && crc16[crc16.Length - 1] == 0)
return true;
return false;
}
///
/// 計算CRC16校驗碼
///
/// 校驗資料
/// 多項式碼
/// 校驗碼初始值
///
public static byte[] GetCRC16(byte[] value, ushort poly = 0xA001, ushort crcInit = 0xFFFF)
{
if (value == null || !value.Any())
throw new ArgumentException("生成CRC16的入參有誤");
//運算
ushort crc = crcInit;
for (int i = 0; i < value.Length; 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); //低位置
byte[] buffer = new byte[value.Length + 2];
value.CopyTo(buffer, 0);
buffer[buffer.Length - 1] = hi;
buffer[buffer.Length - 2] = lo;
return buffer;
}
}
協議報文分析
資料【讀取-請求報文】:01 03 00 04 00 01 C5 CB
- 01 站號
- 03 功能碼
- 00 04 讀取的暫存器的起始地址
- 00 01 讀取暫存器的個數
- C5 CB 為CRC16的校驗碼【使用上面的CRC16類進行的計算結果,CRC16.GetCRC16([01,03,00,04,00,01])】
資料【讀取-回應報文】:01 03 02 00 21 78 5C
- 01 站號
- 03 功能碼
- 02 資料的位元組長度
- 00 21 資料
- 78 5C 為CRC16的校驗碼
資料【寫入-請求報文】:01 10 00 04 00 01 02 00 21 67 CC
- 01 站號
- 10 功能碼
- 00 04 寫入的暫存器的起始地址
- 00 01 寫入暫存器的個數
- 02 寫位元組的個數
- 00 21 要寫的資料
- 67 CC 為CRC16的校驗碼
資料【寫入-回應報文】:01 10 00 04 00 01 40 08
- 01 站號
- 10 功能碼
- 00 04 寫入的暫存器的起始地址
- 00 01 寫入暫存器的個數
- 40 08 為CRC16的校驗碼
有了報文的分析,具體的協議實作也就不難了,完整實作可參考https://github.com/zhaopeiym/IoTClient/blob/master/IoTClient/Clients/ModBus/ModBusRtuClient.cs
IoTClient中ModBusRtu協議的使用
安裝
Nuget安裝 Install-Package IoTClient
或圖形化安裝

使用
//1、實體化客戶端 - [COM埠名稱,波特率,資料位,停止位,奇偶校驗]
ModBusRtuClient client = new ModBusRtuClient("COM3", 9600, 8, StopBits.One, Parity.None);
//2、寫操作 - 引數依次是:地址 、值 、站號 、功能碼
client.Write("4", (short)33, 2, 16);
client.Write("4", (short)3344, 2, 16);
//3、讀操作 - 引數依次是:地址 、站號 、功能碼
var value = https://www.cnblogs.com/zhaopei/p/client.ReadInt16("4", 2, 3).Value;
var value2 = client.ReadInt32("4", 2, 3).Value;
//4、如果沒有主動Open,則會每次讀寫操作的時候自動打開自動和關閉連接,這樣會使讀寫效率大大減低,所以建議手動Open和Close,
client.Open();
//5、讀寫操作都會回傳操作結果物件Result
var result = client.ReadInt16("4", 2, 3);
//5.1 讀取是否成功(true或false)
var isSucceed = result.IsSucceed;
//5.2 讀取失敗的例外資訊
var errMsg = result.Err;
//5.3 讀取操作實際發送的請求報文
var requst = result.Requst;
//5.4 讀取操作服務端回應的報文
var response = result.Response;
//5.5 讀取到的值
var value3 = result.Value;
參考
- 同步至索引目錄:《物聯網基礎組件IoTClient開發系列》
- https://baike.baidu.com/item/串口通信
- https://baike.baidu.com/item/位元率/1022775
- https://zh.wikipedia.org/wiki/奇偶校驗位
- https://www.cnblogs.com/esestt/archive/2007/08/09/848856.html
- https://zh.wikipedia.org/wiki/循環冗餘校驗
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/81946.html
標籤:.NET Core
