.
在ASCII(AmericanStandard Code for Information Interchange)傳輸模式下,封包以英文冒號(:,ASCII3A Hex)開始,以回車和換行(CRLF,ASCII 0D and 0A Hex)符號結束,允許的傳輸的字元集為十六進位的0~9和A~F;網路中的從設備監視傳輸通路上是否有英文冒號(:),如果有的話,就對封包進行解碼,查看封包中的ID是否與自己的ID相同,如果相同的話,就接收其中的資料;如果不同的話,則不予理會。
在ASCII模式下,每個8位元的位元組被拆分成兩個ASCII字元進行發送,例如十六進位數0xCA ,會被分解成ASCII字元C和A進行發送,發送的字元量比RTU增加一倍。ASCII模式的好處是允許兩個字元之間間隔的時間長達1s而不引發通信故障,該模式採用縱向冗餘校驗(LongitudinalRedundancy Check ,LRC) 的方法來檢驗錯誤
如果使用的是 ModBUS RTU
Modbus ASCII 傳輸格式
Header |
ID |
function |
Data |
LRC |
Delimiter |
1byte |
2bytes |
2bytes |
2N bytes |
2bytes |
2bytes |
本篇主要說明 Modbus ASCII 中 LRC的計算方式
LRC 錯誤檢查碼生成步驟如下
1. 將所有資料(不包含Header 和 Delimiter )轉成 16進位格式(Hex Code)
2. 將步驟一所產生的資料全部相加
3. 相加結果進行2補數運算 (將位元全部相反後 + 1)
4. 存入長度8 bit的變數中
5. 將16進位格式轉成 ASCII CODE (2bytes) 即為 LRC
最後附上實作程式碼
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Linq;
- using System.Text;
- using System.Windows.Forms;
-
- namespace Modbus_ASCII_LRF_calculator
- {
- public partial class Form1 : Form
- {
- byte[] send_command;
- int command_lenth; // 不包含 header delimiter
-
- public Form1()
- {
- InitializeComponent();
- }
-
- private byte HexToByte(string hex)
- {
- if (hex.Length > 2 || hex.Length <= 0)
- throw new ArgumentException("hex must be 1 or 2 characters in length");
- byte newByte = byte.Parse(hex,
- System.Globalization.NumberStyles.HexNumber);
- return newByte;
- }
-
- // byte array to ASCII & combine Hex string
- //EX 0x32 0x46 -> 2F
- public static string ConvertHex(String hexString)
- {
- try
- {
- string ascii = string.Empty;
-
- for (int i = 0; i < hexString.Length; i += 2)
- {
- String hs = string.Empty;
- hs = hexString.Substring(i, 2);
- uint decval = System.Convert.ToUInt32(hs, 16);
- char character = System.Convert.ToChar(decval);
- ascii += character;
- }
-
- return ascii;
- }
- catch (Exception ex) { MessageBox.Show(ex.Message); }
-
- return string.Empty;
- }
-
- private void aquaButton1_Click(object sender, EventArgs e)
- {
- String[] sp_str = textBox1.Text.Split(new char[] { ',' });
- command_lenth = sp_str.Length;
- send_command = new byte[command_lenth];
-
- for (int i = 0; i < send_command.Length; i++)
- {
- //textBox1.Text += "0x" +send_command[i].ToString("X")+ " ";
- send_command[i] = HexToByte(sp_str[i]);
- }
-
- //convert all data to Hex
- string hex = BitConverter.ToString(send_command).Replace("-",
- string.Empty);
- String result = ConvertHex(hex);
- int sum = 0;
- int index = 0;
- string temp_str = string.Empty;
-
- for (int i = 0; i < command_lenth / 2; i++)
- {
- temp_str += result[index];
- temp_str += result[++index];
- int value = Convert.ToInt32(temp_str, 16); // 16進位加法
- sum += value;
- ++index;
- temp_str = string.Empty;
- }
-
- // 2's complement
- sum = ~sum;
- sum = sum + 1;
- // convert to uint8 將轉換結果存入8bit變數中
- sbyte LRC_origin = (sbyte)sum;
- string hexValue = LRC_origin.ToString("X");
-
- byte[] LRCArray = null;
- String LRC = string.Empty;
- System.Text.StringBuilder hexNumbers = new System.Text.StringBuilder();
- //Convert to ASCII LRF store in byteArray
- LRCArray = System.Text.ASCIIEncoding.ASCII.GetBytes(hexValue);
- for (int i = 0; i <= LRCArray.Length - 1; i++)
- {
- LRC += "0x" + LRCArray[i].ToString("x") + " ";
- }
-
- for (int i = 0; i < LRCArray.Length; i++)
- {
- if (i < LRCArray.Length - 1)
- {
- textBox2.Text = LRCArray[i].ToString("X");
- }
- else
- {
- textBox3.Text = LRCArray[i].ToString("X");
- }
- }
- }
- }
- }
執行結果
輸入其他長度資料測試
![]()