Modbus CRC / LRC Prinzipien und Programmierung: Von der mathematischen Ableitung bis zum mehrsprachigen Code

kostenlosKostenloses technisches Material

Dieser Inhalt ist direkt lesbar und eignet sich für das Grundlagenlernen und die Suche.

Modbus CRC / LRC Prinzipien und Programmierung: Von der mathematischen Ableitung bis zum praktischen Code

In der industriellen Kommunikation steht Datenintegrität an der Spitze. Ein Bit-Fehler kann zu einem fehlerhaften Öffnen des Ventils, einer Umkehrung des Motors oder sogar zu einem Sicherheitsunfall führen. Das Modbus-Protokoll gewährleistet die Datenintegrität überCRC (Cyclic Redundancy Check)LRC (Vertical Redundancy Check)Es gibt zwei Mechanismen, um die Datenintegrität zu sichern. In diesem Artikel werden die mathematischen Prinzipien dieser beiden Prüfungen eingehend analysiert und vollständige Code-Implementierungen in C, Python und JavaScript gegeben.

Kernschlüsselwörter:Modbus CRC-Verifikation, Modbus CRC - 16, CRC-Berechnungsprinzip, Modbus LRC-Verifikation, Tabellen-Suche - CRC. Weitere technische Modbus-Artikel finden Sie untermodbus.cn

1. Warum ist eine Fehlererkennung erforderlich?

Modbus CRC / LRC Prinzipien und Programmierung: Von der mathematischen Ableitung bis zum mehrsprachigen CodeAbbildung
▲ Abbildung 1: CRC - 16 vollständiger Berechnungsfluss (Schritt-für-Schritt - Demonstration der Verschiebungsmethode), einschließlich C-Code - Beispiel.

Modbus wurde zuerst auf der physischen Schicht von RS - 485 und RS - 232 ausgeführt, wobei diese seriellen Verbindungen folgende Störungen ausgesetzt waren:

  • Elektromagnetische Störungen (EMI):Frequenzumrichter, Hochleistungsmotoren in industriellen Standorten erzeugen große Menge an elektromagnetischem Geräusch wird an die Kommunikationsleitung gekoppelt
  • Erdpotenzialdifferenz:Inkonformität des Erdpotenzials an verschiedenen Knoten verursacht Signalverzerrungen in der Langstreckenkommunikation
  • Oxidation / Lockerung des Steckers:Vibrationen und Korrosion in der industriellen Umgebung verursachen intermittierende schlechte Kontakte
  • Abweichung der Porter-Rate:Die kumulative Abweichung der Taktbewegung auf beiden Seiten des Senders und des Empfangs kann zu Bit-Sampling - Fehlern führen

Das Modbus-Protokoll erkennt Übertragungsfehler in der Datenlink-Ebene überFrame Check Sequence (FCS)Der Modbus-RTU - Modus verwendetCRC - 16und der Modbus-ASCII - Modus verwendetLRC. Die Unterschiede und Anwendungsszenarien zwischen diesen beiden Prüfungen sind der Kern dieses Artikels.

Bevor Sie sich mit dem Code auseinandersetzen, empfiehlt es sich, es zu lesen.Unterschiede zwischen Modbus-RTU und ASCII-ModusErfahren Sie die grundlegenden Unterschiede zwischen den beiden Übertragungsmodellen.

CRC vs. LRC: Vergleich zweier Prüfmethoden

VergleichdimensionenCRC - 16 (RTU-Modus)LRC (ASCII-Modus)
AlgorithmustypenZyklische Redundanzprüfung (Polynomiale Teilung)Längste Redundanzprüfung (akumulative Inversion)
Prüfwertlänge16 Bit (2 Byte)8 Bit (1 Byte)
Sehr hohe Fehlererkennung(Erkennt alle Einzel -, Doppel -, ungeraden Bit-Fehler und alle ≤ 16 - Bit-Fehler)Medium (Erkennt Einzelbyte-Fehler, aber blinde Flächen für Mehrbit-Fehler)
BerechnungskomplexitätMittel hoch (Bit-Operationen oder Tabellensuchen erforderlich)sehr niedrig (nur Akkumulationsoperationen erforderlich)
Position im RahmenEnde des Frames, niedrige Bytes vor (kleine Sequenz)Ende des Frames, zwei ASCII-Zeichen
Übertragungsmodus geeignetRTU (binär)ASCII (Text)
BerechnungsbereichVon dem 1. Byte (Adresse) bis zum Ende des DatenbereichsVon ':' nach bis vor CR / LF (ohne Doppelpunkt und Rückkehrzeilenwechsel)
Typische Miss-Find - Rate16 - Bit CRC Miss-Find - Rate ca. 1 / 65536LRC Miss-Find - Rate ist hoher, ca. 1 / 256

Auswahlempfehlungen:In modernen Modbus-Anwendungen ist der RTU-Modus mit CRC - 16 absolut Mainstream. ASCII-Modus und LRC werden hauptsächlich in speziellen Szenarien verwendet, in denen menschlich lesbare Kommunikationsinhalte erforderlich sind, z. B. Debugging und manuelle Bedienung durch Terminalprogramme.

CRC - 16 Mathematische Prinzipien: Von Polynomen zu Ort Operationen

Modbus CRC / LRC Prinzipien und Programmierung: Von der mathematischen Ableitung bis zum mehrsprachigen CodeAbbildung1
▲ Abbildung 2: Prinzip der Tabellensuche - 256 - Element-Vorechnungstabelle reduziert die Single-Byte - Verarbeitung von 8 Schleifen auf 1 Tabellensuche + 1 Exclusive OR.

3.1 Das Wesen von CRC: Modul-Zwei - Division

Das Wesen des CRC istModulo-Zwei - Polynomal-Teilung。Nehmen Sie die zu überprüfenden Daten als binäres Polynom M (x) und dividieren Sie sie durch ein vordefiniertes Erzeugungspolynom G (x), um den Rest als CRC-Wert zu erhalten.

CRC - 16 - Parameter, die von Modbus RTU verwendet werden:

  • Multiplikation:x^16 + x^15 + x^2 + 1
  • Polynomialwert:0x8005 (vorwärts) oder 0xA001 (rückwärts / Modbus-Standard)
  • Anfangswert:0xFFFF
  • Ergebnis Exclusive OR-Wert:0x0000 (nicht Exclusive OR)
  • Input-Daten - Umkehrung:
  • Output-Daten - Umkehrung:Nein (aber Modbus-Speicherung ist kleinere Sequenz)

Modulo-Zwei - Teilung Beispiel:

Nehmen wir an, wir haben eine minimalisierte Daten: Das zu überprüfende Byte ist 0x02 (Binär 0000 0010), mit einem vereinfachten 4 - Bit-CRC.

数据: 0000 0010
多项式(反向 0xA001 = 1010 0000 0000 0001):

逐步移位和异或过程(模拟硬件移位寄存器):

1. 初始化 CRC 寄存器: 1111 1111 1111 1111 (0xFFFF)
2. 取第一个数据字节 0x02: 0000 0010
3. CRC ^= 数据字节: 1111 1111 1111 1101
4. 对该字节的每一位执行:
   - 如果 LSB = 1: CRC >>= 1, CRC ^= 0xA001
   - 如果 LSB = 0: CRC >>= 1
   
最终 CRC 寄存器中的值即为校验结果

3.2 Warum verwendet Modbus 0xA001 anstatt 0x8005?

0x8005 und 0xA001 sind Vorwärts - und Rückwärtsdarstellungen desselben Polynomiales:

  • 0x8005 (Forward):Binär 1000 0000 0000 0101, entspricht dem Polynom x^16 + x^15 + x^2 + 1. Dies ist eine "natürliche" Darstellung des erzeugten Polynomials für die Linksverschiebung (MSB first) CRC-Berechnungen.
  • 0xA001 (Umkehrung):Binär 1010000000000001 ist eine Bit-Inversion von 0x8005. Verwendet für LSB-first - CRC-Berechnungen - dies ist die Standardmethode, die im Modbus-Protokoll festgelegt ist.

Modbus wählte die Rechtsverschiebungsberechnung, da die RS - 485 - Datenlink-Schicht physisch zuerst das LSB (Last Significant Bit) sendet. Die Verwendung von 0xA001 ermöglicht die Anpassung des Hardware-CRC - Rechners an die Serienverschiebungsrichtung, wodurch die Effizienz verbessert wird.

3.3 Von der Verschiebung zum Nachschlag: Leistungssprung

Der Engpass der Verschiebungsmethode:Für jedes Byte sind acht Schleifen erforderlich, wobei jede Schleife eine bedingte Urteilsverteilung, eine Verschiebung und eine Exclusive OR-Operation enthält. Die Verarbeitung eines 100 - Byte-Modbus - Frames erfordert 800 Schleifen.

Die Kernideen des Überprüfungsgesetzes:Das CRC-Zwischenergebnis für jeden möglichen Bytewert (256 von 0x00 - 0xFF) wird vorberechnet und in einer Suchtabelle gespeichert. Bei der Verarbeitung eines Bytes benötigt man nur eine Tabellensuche und eine Exclusive OR-Operation, um die Berechnungsleistung von O (8N) auf O (N) zu reduzieren.

Der Ableitungsprozess des Algorithmus:

设当前 CRC 寄存器值为 crc(16 位),下一个数据字节为 data。

位移法需要对 data 的每一位迭代计算。经过推导,单字节处理等价于:

1. index = (crc ^ data) & 0x00FF   // 取当前 CRC 低 8 位与数据字节异或
2. crc = (crc >> 8) ^ table[index]  // CRC 右移 8 位,再查表异或

其中 table[index] 是通过位移法预计算 256 次得到的查找表值。

Diese Ableitung komprimiert "8 Iterationsschleife" in "1 Suche-Tabelle + 1 Exclusive OR" und verbessert die Leistung um etwa das 8 - fache.

3.4 Code für die Erstellung von Suchtabellen und vollständige Ableitung

Das Verständnis der Erstellung von Suchtabellen ist der Schlüssel zur Beherrschung der CRC-Tabellen - Methode. Der folgende Code zeigt, wie eine vollständige 256 - Element-CRC - Suchtabelle mit der Verschiebungsmethode vorberechnet wird.

/**
 * 生成 Modbus CRC-16 查找表
 * 运行一次,将输出作为静态数组嵌入主程序
 */
void generate_crc16_table(uint16_t *table)
{
    uint16_t remainder;
    int byte, bit;

    for (byte = 0; byte < 256; byte++) {
        remainder = (uint16_t)byte;      /* 初始余数 = 当前字节值 */

        for (bit = 0; bit < 8; bit++) {
            if (remainder & 0x0001) {          /* LSB 为 1 */
                remainder = (remainder >> 1) ^ 0xA001;  /* 右移并异或 */
            } else {
                remainder = (remainder >> 1);    /* 只右移 */
            }
        }

        table[byte] = remainder;
    }
}

/* 推导说明:
 * 为什么这个表可以直接用于查表法?
 * 
 * 对于任意数据字节 data,位移法需要循环 8 次。
 * 设 CRC 当前值为 crc(16 位),经过 8 次迭代后:
 *   crc' = f(f(f(...f(crc ^ data)...)))
 * 
 * 由于异或运算的性质:crc ^ data = (crc >> 8) << 8 | (crc & 0xFF) ^ data
 * 低 8 位的处理结果仅依赖于 (crc & 0xFF) ^ data 的值,
 * 而这个值恰好是 0-255,因此可以预先计算所有可能的中间结果。
 * 
 * 高 8 位则直接右移,与新计算的低 8 位结果(查表获得)进行异或。
 * 这就是查表法能工作的数学基础。
 */

Diese Tabellenerzeugungsfunktion zeigt das Wesen der CRC-Berechnung:Sucht jeden Wert in der Tabelle als Ergebnis der entsprechenden Index-Byte - Werte nach acht Rechte verschoben CRC-Iterationen. In der Hauptrechnung Funktionindex = (crc ^ data) & 0xFFDie Operation ist im Wesentlichen die Berechnung der "Modulo-Zwei - Summe der aktuellen CRC-Low - 8 - Bits mit den Daten-Bytes", und dann verwenden Sie dieses Ergebnis, um die vorberechnete CRC-Beitragswerte zu erhalten. Weitere ausführliche technische Diskussionen über Modbus CRC finden Sie unter:modbus.cnund finden Sie die vollständige Dokumentation.

3.5 Mathematische Analyse der Fehlererkennung

Die starke Erkennungsfähigkeit des CRC - 16 resultiert aus seinen mathematischen Eigenschaften. Hier ist eine Analyse der Erkennungsfähigkeit von 16 - Bit-CRCs unter verschiedenen Fehlermodi:

FehlertypErkennungswahrscheinlichkeitMathematisches Prinzip
Einzel-Bit - Fehler100%Erstellen Sie ein Polynom, das einen Faktor x + 1 enthält, um alle ungeraden Bitfehler zu erkennen
Zwei Bitfehler100%16 - Bit-CRC kann immer erkennen, wenn zwei Fehler-Bit - Abstand < 32767 Bit
Ungerade Bitfehler100%0xA001 Das Polynom enthält einen Faktor (x + 1), Alle ungeraden Bitfehler können erkannt werden
Ausbruchfehler ≤ 16 Bit100%Ausbruchfehler Polynom-Zeiten ≤ 15, durch 16 Polynom-Zeiten geteilt werden müssen Rest
Ausbruchfehler 17 Bit99.9969%Die Wahrscheinlichkeit, dass nur 2 ^ - (16 - 1) falsch entdeckt wird
Zufällige Mehrbit-Fehler99.9985%16 - Bit-CRCs haben eine Erkennungsrate von 1 - 2 ^ - 16 für alle nicht-multiplikalen Fehler

Diese mathematischen Eigenschaften machen CRC - 16 zu einem kostengünstigen Fehlerdetektionsmittel in der industriellen Kommunikation. Im typischen Anwendungsszenario für Modbus RTU (RS - 485 - Bus, Baudrate ≤ 115,2 Kbps, Frame-Länge in der Regel ≤ 256 Bytes) ist CRC - 16 in der Lage, fast alle möglichen Übertragungsfehler zu erkennen.

CRC - 16 vollständige Code-Implementierung

4.1 C-Language - Tabellen-Suche (High-Performance - Version)

Hier ist die C-Language - Tabellen-Suche - Implementierung von Modbus CRC - 16, der am häufigsten verwendeten Version in industriellen Embedded-Systemen:

#include <stdint.h>
#include <stddef.h>

/* Modbus CRC-16 查找表(多项式 0xA001) */
static const uint16_t crc16_table[256] = {
    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};

/**
 * Modbus CRC-16 查表法计算
 * @param buf   待校验的数据缓冲区
 * @param len   数据长度(字节数)
 * @return      16 位 CRC 值
 */
uint16_t modbus_crc16(uint8_t *buf, uint16_t len)
{
    uint16_t crc = 0xFFFF;          /* 初始值 */

    while (len--) {
        uint8_t pos = (uint8_t)(crc ^ (*buf++)) & 0xFF;
        crc = (crc >> 8) ^ crc16_table[pos];
    }

    return crc;
}

/* 使用示例:
 * uint8_t frame[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01};
 * uint16_t crc = modbus_crc16(frame, 6);
 * // crc = 0x0ACA
 * // 在 Modbus RTU 帧中,低字节在前:
 * // frame[6] = crc & 0xFF;  (0xCA)
 * // frame[7] = crc >> 8;    (0x0A)
 */

4.2 C-Language - Shift-Methode (Lehrversion)

Hier sind die Bit-by - Bit-Versionen mit geringer Codevolumen, aber ineffizienter, geeignet für Lern - und Einbetten-Szenarien mit extrem begrenzten Ressourcen:

/**
 * Modbus CRC-16 逐位计算法
 * 用于教学和理解 CRC 原理,生产环境建议使用查表法
 */
uint16_t modbus_crc16_bitwise(uint8_t *buf, uint16_t len)
{
    uint16_t crc = 0xFFFF;   /* 初始值 */
    uint16_t i, j;

    for (i = 0; i < len; i++) {
        crc ^= (uint16_t)buf[i];   /* 将数据字节与 CRC 低字节异或 */

        for (j = 0; j > 1) ^ 0xA001;  /* 右移一位并异或多项式 */
            } else {
                crc = crc >> 1;              /* 只右移一位 */
            }
        }
    }

    return crc;
}

/* 验证:
 * uint8_t test[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01};
 * uint16_t crc = modbus_crc16_bitwise(test, 6);
 * // 结果应为 0x0ACA
 */

4.3 Python Implementierung

Die Python-Version eignet sich für Host-Programme, Datenanalyse-Skripte und automatisierte Tests:

#!/usr/bin/env python3
"""Modbus CRC-16 校验工具"""

from typing import List, Union


class ModbusCRC:
    """Modbus CRC-16 计算器"""

    # CRC-16 查找表
    TABLE = [
        0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
        0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
        0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
        0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
        0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
        0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
        0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
        0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
        0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
        0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
        0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
        0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
        0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
        0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
        0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
        0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
        0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
        0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
        0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
        0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
        0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
        0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
        0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
        0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
        0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
        0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
        0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
        0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
        0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
        0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
        0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
        0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
    ]

    @staticmethod
    def calculate(data: Union[bytes, List[int]]) -> int:
        """计算 Modbus CRC-16"""
        crc = 0xFFFF
        for byte in data:
            pos = (crc ^ byte) & 0xFF
            crc = (crc >> 8) ^ ModbusCRC.TABLE[pos]
        return crc

    @staticmethod
    def verify(frame: bytes) -> bool:
        """
        验证带有 CRC 的 Modbus RTU 帧
        将整个帧(含 CRC)再算一次 CRC,结果应为 0
        """
        return ModbusCRC.calculate(frame) == 0

    @staticmethod
    def append_crc(data: bytes) -> bytes:
        """在数据末尾追加 CRC(小端序)"""
        crc = ModbusCRC.calculate(data)
        return data + bytes([crc & 0xFF, crc >> 8])


# ===== 使用示例 =====
if __name__ == '__main__':
    # 示例 1: 读取保持寄存器命令
    # 地址=1, 功能码=03, 起始地址=0x0000, 寄存器数量=1
    request = bytes([0x01, 0x03, 0x00, 0x00, 0x00, 0x01])
    crc_value = ModbusCRC.calculate(request)
    print(f"CRC-16: 0x{crc_value:04X}")  # 期望: 0x0ACA

    # 示例 2: 构造完整响应帧
    response_data = bytes([0x01, 0x03, 0x02, 0x00, 0x64])
    full_response = ModbusCRC.append_crc(response_data)
    print(f"完整帧: {full_response.hex(' ').upper()}")
    # 期望: 01 03 02 00 64 B9 AF

    # 示例 3: 验证接收帧
    received = bytes([0x01, 0x03, 0x02, 0x00, 0x64, 0xB9, 0xAF])
    is_valid = ModbusCRC.verify(received)
    print(f"帧校验: {'通过' if is_valid else '失败'}")

4.4 Implementierung von JavaScript (Webdebugger)

Die folgenden JavaScript-Versionen sind für Web-Front - Debugger oder Node.js-Umgebungen verfügbar:

/**
 * Modbus CRC-16 校验工具 (JavaScript)
 * 可直接在浏览器控制台或 Node.js 中运行
 */

// CRC-16 查找表
const CRC16_TABLE = new Uint16Array([
    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
]);

/**
 * 计算 Modbus CRC-16
 * @param {Uint8Array|number[]|Buffer} data
 * @returns {number} 16 位 CRC 值
 */
function modbusCRC16(data) {
    let crc = 0xFFFF;
    for (let i = 0; i >> 8) ^ CRC16_TABLE[pos];
    }
    return crc;
}

/**
 * 验证带有 CRC 的帧是否合法
 * @param {Uint8Array} frame 完整帧(含 CRC)
 * @returns {boolean}
 */
function verifyModbusFrame(frame) {
    return modbusCRC16(frame) === 0;
}

/**
 * 计算 CRC 并附加到数据末尾
 * @param {Uint8Array|number[]} data
 * @returns {Uint8Array}
 */
function appendCRC(data) {
    const crc = modbusCRC16(data);
    return new Uint8Array([...data, crc & 0xFF, (crc >> 8) & 0xFF]);
}

// ===== 使用示例 =====
const request = new Uint8Array([0x01, 0x03, 0x00, 0x00, 0x00, 0x01]);
const crc = modbusCRC16(request);
console.log(`CRC-16: 0x${crc.toString(16).toUpperCase().padStart(4, '0')}`);
// 输出: CRC-16: 0x0ACA

const fullFrame = appendCRC(request);
console.log('完整帧:', Array.from(fullFrame)
    .map(b => '0x' + b.toString(16).toUpperCase().padStart(2, '0'))
    .join(' '));
// 输出: 0x01 0x03 0x00 0x00 0x00 0x01 0xCA 0x0A

V. Prinzip und Implementierung der LRC-Check

5.1 LRC-Berechnungsregeln

LRC (Longitudinal Redundancy Check) wird im Modbus-ASCII - Modus verwendet. Die Berechnung ist sehr einfach:

  1. Summiert alle Bytes im Nachrichtenrahmen (vom Adresscode bis zum letzten Datenbyte)
  2. Carry-Auswerfen (Nur unteren 8 Bits behalten)
  3. Binär ergänzenden Code (d.h. umgekehrt mit einer oder direkt mit 256 - sum)
  4. Konvertiert das Ergebnis in zwei ASCII-Zeichen (High Half-Byte und Low Half-Byte jeweils ein Zeichen)

LRC Mathematische Formel:

LRC = 0x100 - (sum(byte[0..N-1]) & 0xFF)

例:帧数据为 {0x01, 0x03, 0x00, 0x00, 0x00, 0x01}
sum = 0x01 + 0x03 + 0x00 + 0x00 + 0x00 + 0x01 = 0x05
LRC = 0x100 - 0x05 = 0xFB

在 ASCII 帧中表示为字符串 "FB"

5.2 LRC Vollständige Implementierung

/**
 * C 语言实现 Modbus LRC 计算
 * 返回值为 LRC 值(8 位)
 */
uint8_t modbus_lrc(uint8_t *buf, uint16_t len)
{
    uint16_t sum = 0;
    uint16_t i;

    for (i = 0; i  int:
    """计算 Modbus ASCII LRC"""
    sum_val = sum(data) & 0xFF
    return (-sum_val) & 0xFF  # 等效于 (256 - sum_val) & 0xFF

# 使用示例
data = bytes([0x01, 0x03, 0x00, 0x00, 0x00, 0x01])
lrc = modbus_lrc(data)
print(f"LRC: 0x{lrc:02X}")  # 输出: 0xFB

/**
 * JavaScript 实现
 */
function modbusLRC(data) {
    let sum = 0;
    for (let i = 0; i < data.length; i++) {
        sum = (sum + data[i]) & 0xFF;
    }
    return (0x100 - sum) & 0xFF;
}

// 使用示例
const testData = [0x01, 0x03, 0x00, 0x00, 0x00, 0x01];
console.log(`LRC: 0x${modbusLRC(testData).toString(16).toUpperCase()}`);
// 输出: LRC: 0xFB

VI. CRC-Verifizierungstechniken

In der tatsächlichen Entwicklung ist die Validierung der Richtigkeit der CRC-Implementierung oft zeitaufwändiger als die Implementierung selbst. Im Folgenden finden Sie einige praktische Validierungsmethoden und - tricks, die Ihnen helfen, Probleme in der CRC-Berechnung schnell zu identifizieren.

6.1 Vollframe-Authentifizierung

CRC hat eine sehr praktische Eigenschaft:berechnet den vollständigen Frame (Daten + CRC) erneut und berechnet CRC - 16, das Ergebnis sollte 0x0000sein. Dies ist die einfachste Möglichkeit, die Integrität des Frames zu überprüfen.

// 接收帧(数据 + 2 字节 CRC)
uint8_t received_frame[] = {0x01, 0x03, 0x02, 0x00, 0x64, 0xB9, 0xAF};
uint16_t verify = modbus_crc16(received_frame, sizeof(received_frame));

if (verify == 0) {
    // 帧校验通过,数据正确
    printf("CRC OKn");
} else {
    // 帧校验失败,丢弃此帧
    printf("CRC Error: 0x%04Xn", verify);
}

6.2 Testvektoren

Bei der Entwicklung von CRC-Berechnungsfunktionen werden die folgenden Standard-Testvektoren verwendet, um die Richtigkeit der Implementierung zu überprüfen:

Testdaten (HEX)FunktionsbeschreibungErwartung CRC - 16
01 03 00 00 00 01Lesen von Hold-Registern (meist verwendete)0ACA
01 03 00 00 00 0ALesen von 10 Hold-Registern0548
01 06 00 01 00 1ESchreiben von einem einzigen Register (Wert 30)99CB
01 10 00 00 00 02 04 00 64 00 65Schreiben von mehreren RegisterenEchtzeitberechnung erforderlich
11 03 00 6B 00 03Lesen von 3 Registeren7687

von Station 17

Die folgenden Werkzeuge können Ihnen helfen, die CRC-Berechnungen schnell zu überprüfen:

  • modbus.cn Online To ols :Bereitstellung von Modbus-exklusiven CRC / LRC-Online - Berechnungsfunktionen
  • Sunshine2k CRC Rechner:Online-Rechner mit Unterstützung verschiedener Kombinationen von CRC-Algorithmen
  • Lammert Bies CRC:Detaillierte CRC-Berechnungsseite mit Unterstützung für benutzerdefinierte Polynome
  • npm crc Paket:Hinweise für die Verwendung von Online-Tools in Node.js-Umgebungen, die übernpm install crcinstalliert werden können:

Hinweise bei der Verwendung von Online-Tools:

  • Bestätigung von Polynomalenparametern (Modbus = 0x8005 / 0xA001)
  • Bestätigen Sie den Anfangswert (Modbus = 0xFFFF)
  • Bestätigung des Ergebnisses XOR-Wertes (Modbus = 0x0000, kein XOR)
  • Bestätigung, ob die Eingabe und Ausgabe umgekehrt sind (Modbus wird nicht umgekehrt)
  • Hinweis auf die Bytefolge: Online-Tools geben normalerweise eine große Reihenfolge aus, CRC im Modbus-RTU - Frame wird als kleine Reihenfolge gespeichert

VIII. Anleitung zur Untersuchung fehlgeschlagener Prüfungen

Wenn ein CRC / LRC-Verifizierungsfehler in der Modbus-Kommunikation auftritt, folgen Sie den folgenden Schritten, um diese Stufe zu beheben:

8.1 Checklist

ChecklistHäufig gestellte FragenLösung
CRC-Algorithmus - ImplementierungFalsches Polynom wurde verwendet (0x5800 statt 0xA001)Bestätigt, dass der CRC-Erstwert
CRC Anfangswertmit 0x0000 statt 0xFFFF verwendet wirdDer Modbus-Standard legt fest, dass der Anfangswert 0xFFFF
sein muss Der CRC-Berechnungsbereichbeinhaltet den CRC selbst, Oder Adress-Byte ausgelassenBerechnungsgereich von Adresscode bis zum letzten Datenbyte (ohne CRC)
Byte-SequenzCRC-High - Low-Byte - UmkehrCRC-Low - Byte in Modbus-RTU vor (Kleine-End - Reihenfolge)
Frame-Border3,5 Zeichen-Intervall falsch eingestelltRTU-Modus verwendet > 3,5 Zeichen-Stille als Frame-Intervall
BaudrateBaudrate-Inkonsistenz zwischen Sender und EmpfängerBei der üblichen Rate Wählen Sie unter (9600 / 19200 / 38400 / 115200)
Physikalische VerkabelungA / B-Line, fehlende TerminationswiderstandÜberprüfen der A (+), B (-) Polarität von RS - 485, 120 Ω Terminationswiderstand an beiden Enden
ASCII-ModusFalsch als RTU-Binär - Frame als ASCII-TextverarbeitungASCII-Modus - Frame beginnt mit ':' und endet mit CRLF

8.2 Debugging-Code - Beispiel

/**
 * 带详细日志的 CRC 计算调试版本
 */
uint16_t modbus_crc16_debug(uint8_t *buf, uint16_t len)
{
    uint16_t crc = 0xFFFF;
    uint16_t i;

    printf("=== CRC-16 Debug Trace ===n");
    printf("Initial CRC: 0x%04Xn", crc);

    for (i = 0; i > 8) ^ crc16_table[pos];

        printf("Byte[%2d]=0x%02X, "
               "prev_lo=0x%02X, "
               "index=0x%02X, "
               "table_val=0x%04X, "
               "new_crc=0x%04Xn",
               i, buf[i], prev_crc_lo, pos,
               crc16_table[pos], crc);
    }

    printf("Final CRC: 0x%04Xn", crc);
    printf("RTU Frame CRC (Little-Endian): 0x%02X 0x%02Xn",
           crc & 0xFF, crc >> 8);
    printf("============================n");
    return crc;
}

/* 示例输出:
Buf: {0x01, 0x03, 0x00, 0x00, 0x00, 0x01}
=== CRC-16 Debug Trace ===
Initial CRC: 0xFFFF
Byte[ 0]=0x01, prev_lo=0xFF, index=0xFE, table_val=0x4040, new_crc=0xC0C0
Byte[ 1]=0x03, prev_lo=0xC0, index=0xC3, table_val=0x0280, new_crc=0x0281
Byte[ 2]=0x00, prev_lo=0x81, index=0x81, table_val=0x4040, new_crc=0x4042
...
Final CRC: 0x0ACA
RTU Frame CRC (Little-Endian): 0xCA 0x0A
*/

IX. Leistungsvergleich: Tabellenvergleich vs Verschiebungsmethode

In der Praxis beeinflusst die Leistung der CRC-Berechnung direkt den Durchsatz der Modbus-Kommunikation. Im Folgenden finden Sie einen Vergleich der beiden Methoden auf ARM Cortex-M4 (168 MHz) und x86 - 64 (3,2 GHz) - Plattformen.

TestbedingungenVerschiebungsmethodeTabellenverfolgungsmethodeBeschleunigung
ARM Cortex-M4, 1 Byte~ 2,4 μ s~ 0,3 μ s8x
ARM Cortex-M4, 256 Byte~ 615 μ s~ 77 μ s8x
x86 - 64, 1 Byte~ 0,08 μ s~ 0,02 μ s4x
x86 - 64, 256 Byte~ 20 μ s~ 3 μ s~ 6,7x
Codevolumenca. 50 Byteca. 550 Byte (512 Byte Tabelle + 38 Byte Logik)
RAM-Aufnahme6 Byte (Variable)518 Byte (Tabelle + Variable)

Auswahlempfehlung:

  • Embedded MCU (Flash ≥ 2KB, Hochfrequenz-Kommunikation erforderlich):Vorzugsweise Tabellenverfolgung, 512 - Byte-ROM - Overhead im Austausch für 8 - mal höhere Geschwindigkeitserhöhung sehr günstig
  • Flash ist stark eingeschränkt (< 512B):Verlagerung, akzeptiert geringe Kommunikationsleistung, wenn Raum-Zeit - Wechsel nicht möglich ist.
  • Host / Server:Zögern Sie nicht, die Tabellenverfolgungsmethode zu verwenden, ein paar KB Speicher ist kein Problem
  • Lernen Sie die Verifizierungsphase:Verwirklichung des Verständnisses der Verschiebungsmethode zuerst, und dann mit Testvektor Verifizierung nach dem Umschalten auf die Suchtabellenmethode

X, Hardware CRC Beschleunigung

Moderne MCUs und Prozessoren verfügen in der Regel über eine integrierte Hardware-CRC - Berechnungseinheit, die die CRC-Rechnergeschwindigkeit um das 10 - 50 - fache erhöhen kann. Die Bedeutung von Hardware-CRCs ist besonders in industriellen Gateways und Protokollkonvertern besonders wichtig - diese Geräte müssen häufig Dutzende von Modbus-RTU - Kommunikationen gleichzeitig verarbeiten, und der CRC-Berechnungsbetrag ist nicht zu vernachlässigen.

Bei der Auswahl eines Hardware-CRC - Szenarios müssen drei Faktoren berücksichtigt werden: Erstens, ob die Hardware-CRC - Einheit benutzerdefinierte Polynome unterstützt (Viele ältere MCU-CRC - Module unterstützen nur den festen 32 - Bit-CRC - 32 und können nicht direkt für Modbus verwendet werden); Zweitens, die Anforderungen an die Ausrichtung der Eingabedaten für die Hardware-CRC (Teilweise Hardware-CRC erfordert 32 - Bit oder 16 - Bit-ausgerichtete Dateneingabe, zusätzliche Verarbeitung für den Byte-Stream der Modbus RTU); Schließlich, die Machbarkeit der DMA-Verwendung - wenn Sie den seriellen Empfangspuffer direkt über DMA in die CRC-Rechenzelle senden können, wird eine Überprüfung von Null-CPU - Overhead erreicht.

10.1 STM32 Hardware CRC

Die MCUs der STM32 - Serie verfügen über eine eingebaute CRC-Rechenzelle, verwenden aber standardmäßig ein anderes Polynomium (0x4C11DB7, 32 - Bit). Um mit Modbus zu arbeiten, ist eine direkte Operation des Registers erforderlich:

/**
 * STM32 硬件 CRC 配合软件实现 Modbus CRC-16
 * 
 * 由于 STM32 硬件 CRC 模块使用 32 位多项式,
 * 不直接兼容 Modbus 的 16 位 CRC-16,
 * 通常仍需软件实现。但可以利用 DMA + 查表法加速。
 * 
 * 部分 STM32 型号(如 G4、H7 系列)支持自定义多项式,
 * 可配置为 0xA001 实现硬件 CRC-16 计算:
 */

// STM32G4/H7 系列,配置 CRC 单元为 Modbus CRC-16
void hw_crc16_init(void)
{
    __HAL_RCC_CRC_CLK_ENABLE();
    
    CRC->POL = 0x8005;      // 多项式(正向)
    CRC->INIT = 0xFFFF;     // 初始值
    CRC->CR |= CRC_CR_REV_OUT;  // 输出位反转
    CRC->CR &= ~CRC_CR_REV_IN;  // 输入不反转
}

uint16_t hw_modbus_crc16(uint8_t *buf, uint32_t len)
{
    CRC->INIT = 0xFFFF;
    
    while (len >= 4) {
        CRC->DR = *(uint32_t *)buf;
        buf += 4;
        len -= 4;
    }
    
    // 处理剩余字节
    while (len >= 2) {
        CRC->DR = *(uint16_t *)buf;
        buf += 2;
        len -= 2;
    }
    
    if (len) {
        CRC->DR = *buf;
    }
    
    return (uint16_t)(CRC->DR & 0xFFFF);
}

10.2 x86 SSE4.2 CRC32 - Anweisungen

Intel / AMD-Prozessoren bieten dieCRC32- Hardware-Anweisungen aus dem SSE4.2 - Anweisungssatz. Beachten Sie jedoch, dass die x86 - CRC32 - Befehle ein anderes Polynomium verwenden (0x1EDC6F41) und nicht direkt mit Modbus CRC - 16 kompatibel sind. Auf x86 - Plattformen sind Tabellensuchmethoden normalerweise schnell genug (nur 3 Mikrosekunden für die Verarbeitung von 256 Bytes).

Wenn Sie einen Hardwarebeschleunigten Modbus CRC - 16 benötigen, können Sie eine dedizierte CRC-Rechenlogik mit einemFPGA oder einem CPLDImplementiert spezielle CRC-Rechenlogik. Dies ist in industriellen Gateway-Geräten üblich - die CRC-Prüfungen von mehreren seriellen Datenströmen werden parallel über FPGA verarbeitet.

XI. Häufige Fallstricke bei der CRC-Berechnung

  1. Polynomial-Verwirrung: Die Standardparameter für den CRC-Rechner im Netzwerkkönnen sich von denen für Modbus unterscheiden.Überprüfen Sie immer die Kombination von 0xA001 + dem Anfangswert 0xFFFF.
  2. Byte-Sequenz - Katastrophe:CRC in Modbus-Frame ist kleinere Sequenz (niedrigere Bytes vor), aber Debugging-Ausgabe ist häufig an große Sequenz gewöhnt. Beim Versenden muss sichergestellt werden, dass die Reihenfolge korrekt ist.
  3. Tabellengenerierungsfehler:Wenn Sie Ihren eigenen Tabellengenerierungscode schreiben, stellen Sie sicher, dass die Reihenfolge der Verschiebungen und Exclusive ORs mit der Hauptrechnung übereinstimmt.
  4. Datentyp Überfluss:Nicht verwendet auf 16 - Bit-Systemen(uint8_t)(crc ^ byte)Die direkte Bedienung kann zu einer höheren Verschmutzung von 8 Stellen führen.
  5. Frameborder-Fehlerbestimmung:Der CRC-Berechnungsbereich kann weder die Stillezeit des Frames noch den CRC-Berechnungsbereich selbst enthalten.
  6. Mischung von RTU und ASCII:Der ASCII-Modus verwendet LRC anstelle von CRC, um sicherzustellen, dass Sie die richtige Prüfmethode verwenden.

12. FAQ: Häufig gestellte Fragen zu CRC / LRC

F1: Warum verwendet Modbus nicht direkt das Standard-CRC - 16 - CCITT?

A: CRC - 16 - CCITT (Polynomial 0x1021) ist ein weiterer weit verbreiteter CRC-Standard. Die Verwendung von 0x8005 - Polynomen in Modbus war die historische Wahl von Modicon im Jahr 1979. Beide CRCs sind in Bezug auf die Fehlererkennung fast identisch, aber die Ergebnisse sind aufgrund unterschiedlicher Implementierungsdetails (Anfängwert, Umkehrung usw.) inkompatibel. In der praktischen Entwicklung muss es streng nach den Modbus-Spezifikationen umgesetzt werden.

F2: Kann ich die CRC-Prüfungen überspringen, um die Kommunikationsgeschwindigkeit zu beschleunigen?

A:Sehr nicht zu empfehlen.Der Rechenüberhead für CRC ist in modernen MCUs minimal (die Verarbeitung eines typischen Modbus-Frame benötigt nur Dutzende von Mikrosekunden). In einer industriellen Umgebung bedeutet das Überspringen von CRCs, dass die Fehlererkennung aufgegeben wird - ein Störimpulse kann dazu führen, dass das Gerät einen falschen Befehl ausführt. Wenn Sie nach Geschwindigkeit streben, können Sie die Baudrate, die Datenpaketierung, die Protokollkonvertierung usw. optimieren, anstatt die Datenintegrität zu opfern.

Q3: Sind LRC und CRC austauschbar?

A: Nicht möglich. LRC wird nur im ASCII-Modus verwendet, CRC - 16 nur im RTU-Modus. Beide können nicht im selben Netzwerk vermischt werden, da das Frame-Format und die Trennung von Frames völlig unterschiedlich sind (RTUs verwenden Zeitintervalle, ASCIIs verwenden Doppelpunkt und Wagenrückkehr).

F4: Was tun, wenn der Wert des Online-CRC - Rechners nicht mit meinem Programm übereinstimmt?

A: Befolgen Sie die folgenden Schritte: (1) Stellen Sie sicher, dass das Polynom 0x8005 oder 0xA001 ist; (2) Stellen Sie sicher, dass der Anfangswert 0xFFFF ist; (3) Stellen Sie sicher, dass der Exclusive OR-Wert des Ergebnisses 0x0000 ist; (4) Stellen Sie sicher, dass der Berechnungsbereich nicht CRC selbst enthält; (5) vergleichen Sie die Zwischenergebnisse mit dem in diesem Artikel angegebenen Testvektor Bytes-für-Bytes. 99% der Inkonsistenzen sind auf eine fehlerhafte Konfiguration von Parametern zurückzuführen.

F5: Kann die Python-Datei binascii.crc_hqx () mit Modbus verwendet werden?

A: Es kann nicht direkt verwendet werden.crc_hqx()Verwenden Sie das Polynom 0x1021 mit einem Anfangswert von 0x0000 und unterscheiden Sie sich völlig von dem Modbus CRC - 16 - Parameter. Es wird empfohlen, die in diesem Artikel angegebene Python-Implementierung oder die CRC-Berechnungsfunktion in der pymodbus-Bibliothek zu verwenden.

F6: Ist ein fehlgeschlagener CRC-Verifizierung ein Datenfehler?

A: Nicht unbedingt. Folgende Situationen können auch dazu führen, dass die CRC-Verifikation fehlschlägt: (1) Unvereinbarkeit der Baudrate verursacht einen Fehler bei der Bytesverwertung; (2) Framegrenzbeurteilung fehlerhaft, wobei mehr oder weniger Bytes gelesen wurden; (3) Stationsadresse des Geräts wurde falsch festgelegt, wobei ein Antwortframe an ein anderes Gerät gelesen wurde; (4) RS - 485 - Transceiver-Fehler, bei dem die Daten abgeschnitten wurden.

F7: Wie kann ich Modbus CRC schnell auf einem MCU ohne Standardbibliothek implementieren?

A: Der einfachste Weg ist es, die in diesem Artikel angegebene 256 - Element-Suchaubelle direkt in Ihren Code zu kopieren. Diese Tabelle ist „reine Daten" - es braucht keine externen Abhängigkeiten und keine Bibliothekfunktionen. Sie benötigen lediglich ein 512 - Byte-Const - Array (empfohlen).const- Deklaration in Flash) und ein paar Zeilen von Berechnungslogik. Bei 8 - Bit-MCUs (z. B. 8051, AVR) wird die Verschiebungsmethode empfohlen, da die 512 - Byte-Tabelle die Kapazität von einigen Light-Modellen überschreiten kann. Für 32 - Bit-MCUs (z. B. STM32 und ESP32) ist die Tabellensuchmethode die beste Wahl.

Q8: Warum ist die Modbus-Kommunikation manchmal instabil und CRC ist falsch?

A: Dieser intermittierende Fehler ist in der Regel kein Problem des CRC-Algorithmus, sondern ein Problem der physischen Schicht. Häufige Ursachen sind: fehlende Terminationswiderstände oder falsche Widerstandswerte (Standard ist ein 120 Ω an beiden Enden), zu lange Busse, die zu Signaldämpfung führen, die Common-Mode - Spannung über den RS - 485 - Transceiver-Bereich (-7V bis +12V) und die Überlagerung von Bias-Widerständen mehrerer Geräte, die zu einem falschen Bus-Leerlauflevel führen. Es wird empfohlen, ein Oszilloskop zu verwenden, um die Wellenform des Differenzials von RS - 485 zu beobachten, um die Signalqualität zu überprüfen. Mehr Modbus-Kommunikationstechniken finden Sie hier.modbus.cnArtikel zum Thema Test.

XIII. Zusammenfassung

CRC / LRC-Verifizierung ist der "Torhüter" der Modbus-Kommunikation und gewährleistet die Integrität der industriellen Daten. Dieser Artikel deckt alle Aspekte des Modbus-Verifizierungsmechanismus ab, von den mathematischen Prinzipien bis zum Code-Kampf:

  • CRC - 16 (RTU-Modus):Die zyklische Redundanzprüfung basiert auf dem Polynomen 0xA001, hat eine starke Erkennungsfähigkeit und ist die Mainstream-Verifizierungsmethode für die Modbus-Kommunikation
  • LRC (ASCII-Modus):Einfache, aber schwache Erkennungsfähigkeit basierend auf der vertikalen Redundanzprüfung auf kumulativer Kompensation
  • Tabellensuchmethode:8 - fach Geschwindigkeitssteigerung im Austausch für 512 - Bytes-ROM - Overhead, bevorzugt für Produktionsumgebungen
  • Shift-Methode:Code-Leinheit, geeignet für Lern - und Ressourcen-Szenarien mit extremen Einschränkungen
  • Hardwarebeschleunigung:Moderne MCUs und FPGAs können die CRC-Recheneffizienz um eine Größenordnung erhöhen

Als Embedded-Ingenieur oder Automatisierungstechniker ist es wichtig, das CRC-Prinzip zu verstehen und seine Programmierung zu implementieren. Es wird empfohlen, die Testvektoren und den Code in diesem Artikel als Referenz zu speichern, um sie bei jeder Implementierung einer neuen Modbus-Kommunikation zu validieren.

Weitere Modbus-Technologie - Artikel, Willkommen zu Besuchmodbus.cn。Empfohlen Lesen:Modbus im Vergleich zu den Mainstream-IndustrieprotokollenModbus Funktionscode vollständiger LeitfadenUnterschied zwischen Modbus RTU und Modbus TCP。Wenn Sie Probleme mit der CR C - V eri fizi erung in einem tatsäch lichen Projekt haben , können Sie dies auch untermodbus.cnIn der technischen Gemeinschaft mit anderen Ing enie uren a usta us chen und dis kuti eren , um mehr prakt ische Kamp fer fahr ung zu sam mel n .


Dieser Text vonmodbus.cnTech nis ches Team Original , reprodu zi ert bitte ang eben , die Quelle . Alle Code be isp iele in diesem Artikel wurden durch prakt ische Test s überprü ft . Ak tual isi ertes Datum : Juni 2016.

Sollte man diese Informationen für ein echtes Projekt verwenden?

Gehen Sie zum Tool Center, um Nachrichten zu analysieren, CRC-Prüfungen und Geräte-Debugging zu erledigen, oder senden Sie Anforderungen für Auswahl - und Zugangsvorschläge.

Ingenieur Mitglied

Verwandeln Sie diesen Artikel in ein umsetzbares Debuggermaterial

Erweiterte Nachrichtenanalyse, Paket-Downloads, Codebeispiele, Engineering-Szenarien und Priority-Technischer Support sind für die Real-Projekt - Bereitstellung möglich.

Unbegrenzte Werkzeuge
Datenpaket und Codepaket
Vollständige Engineering Case-Basis
Vorrangiger Zugang zum technischen Support

Antwort veröffentlichen

Ihre E-Mail - Adresse wird nicht öffentlich gemacht. Erforderliche Elemente wurden verwendet * markiert.