BCC 校驗碼是將序列訊框中某個特定範圍內的每個位元組進行 XOR 運算後所產生的一個單一位元組。這個縮寫代表「區塊檢查字元」(Block Check Character),其公式非常簡短,僅需一行即可寫完:從 0x00 開始,然後對每個資料位元組執行 accumulator = accumulator XOR byte,最後將這個 0x00 到 0xFF 的值與訊框一同傳送。由於 XOR 運算具有交換律,且不涉及進位,因此位元組的順序並不會影響結果,而且這個演算法不需要查表、不需要多項式,也不需要最終的補數運算。正是這種簡潔性,讓許多嵌入式裝置、RFID 讀取器以及工業用 PLC 都將它作為內建的完整性檢查機制。然而,問題出在「BCC」這個詞本身:不同廠商可能將它用於加法總和、LRC 值、完整的 CRC,或針對訊框不同部分所計算的校驗碼,因此「BCC 範例」只有在明確界定公式與位元組範圍後才具有意義。本文將透過實際的十六進制位元組,逐步說明標準的 XOR-8 形式,並將其與相關的 Modbus ASCII LRC 進行比較,展示如何在本地端重現相同的數值。

序列訊框中「BCC」的意義
BCC 是一個標籤,而不是一種演算法。在最嚴格、最常見的定義中,它指的是附加在訊框末端的一個單一位元組值,讓接收端能夠偵測偶發的資料損毀。這個位元組通常放置在訊框的尾端,位於承載資料之後,以及任何結尾的停止或結束標記之前,而傳送端會附加剛才所傳送之所有位元組的 BCC。接收端則對收到的承載資料執行相同的運算,將自己計算出的 BCC 與傳送端附加的 BCC 進行比對,若兩者不符便會產生錯誤。
「BCC」之所以會造成混淆,是因為這三個字母在不同廠商手冊中可能代表不同的運算機制。有些廠商將 BCC 定義為資料位元組的 XOR-8,有些定義為模數 256 的加法總和,有些定義為帶有最終補數的縱向冗餘檢查 (LRC),也有些則定義為特定寬度的 CRC。例如 Modbus 通訊社群將 LRC 一詞保留給其特定的二補數總和,並使用與原始 XOR 不同的位元組。因此,在任何範例能與真實儀器相符之前,確認特定裝置所採用的定義是首要步驟。若需要一份涵蓋這些慣例的簡明參考,BCC 校驗碼速查表將各種公式並列彙整。
XOR-8 BCC 的計算方式
XOR-8 BCC 從一個等於 0x00 的累加器開始。然後將訊框中每個選定的位元組,以位元互斥或 (XOR) 運算與累加器結合,並在每次運算後更新累加器的值。由於這個運算子是自身的反元素,並兼具交換律與結合律,因此位元組的順序即使重新排列也不會影響結果,而且對同一運算執行兩次會互相抵消。
在任何實作範例中,有三個運算特性值得牢記。第一,結果永遠是一個位元組,因此它以 00 到 FF 之間剛好兩位數的十六進制數字表示,且必須以此形式傳送。第二,由於 XOR 是逐位元運作而不涉及算術,因此沒有進位傳遞,這也是為何能在韌體中輕鬆實現的原因。第三,演算法具有對稱性:將 BCC 反向 XOR 回累加器即可還原為 0x00,這也是為何接收端只需將傳送過來的 BCC 折入其執行中的值,便能單次完成整個訊框的重新檢查。
實際十六進制位元組的 BCC 校驗碼範例
理解 BCC 範例最清晰的方式就是親手逐步演算。以四位元組序列 0x01、0x02、0x03、0x04 為例。累加器從 0x00 開始。第一個位元組處理完後的值為 0x00 XOR 0x01 = 0x01。第二個位元組處理完後為 0x01 XOR 0x02 = 0x03。第三個位元組處理完後為 0x03 XOR 0x03 = 0x00。第四個位元組處理完後為 0x00 XOR 0x04 = 0x04。因此序列 01 02 03 04 的 BCC 為 0x04,無論位元組順序為何,皆以兩位數的十六進制數字表示。
| 步驟 | 加入的位元組 | XOR 後的累加器 |
|---|---|---|
| 0 (初始) | — | 0x00 |
| 1 | 0x01 | 0x01 |
| 2 | 0x02 | 0x03 |
| 3 | 0x03 | 0x00 |
| 4 | 0x04 | 0x04 |
根據相同的規則可進行三項快速的健全性檢查。單位元組訊框的 BCC 等於該位元組本身,因為 0x00 XOR b = b。空訊框的 BCC 為 0x00,這也是為何許多規格明確禁止空承載資料的原因。包含位元組 0xFF 的訊框,其 BCC 為 0xFF,這也是一個有用的邊界案例,因為它證實了累加器並不會發生溢位或飽和。BALTECH 技術筆記等廠商參考文件記錄了相同的選定位元組八位元 XOR 運算,並針對示範序列 01 A0 7C FF 02 得出 0x20 的結果,讀者可透過逐步摺疊 0x00、0x01、0xA1、0xDD、0x22、0x20 來驗證此結果。校驗碼計算工具會自動產生相同的數值。
在瀏覽器中計算 BCC 校驗碼
確認範例是否符合真實裝置的最快方法,就是在本地端進行運算。校驗碼計算工具會預先宣告其三種公式,並顯示實際處理的位元組數量,因此能輕易驗證輸入內容是否符合通訊協定規格。
- 開啟校驗碼計算工具,並選擇符合通訊協定的輸入模式:人類可讀的承載資料使用 UTF-8 文字,原始訊框則使用十六進制位元組。
- 若選擇十六進位模式,請以剛好兩位數的十六進制數字輸入每個位元組,並以空白分隔;該工具不會猜測,而是會拒絕諸如 0x 前綴、逗號、奇數半位元組以及註解等格式。
- 僅輸入規格中指定納入檢查範圍的位元組;以 Modbus ASCII 而言,這表示必須排除起始冒號與結尾的 CRLF;而對於許多廠商的 BCC,則需排除 STX、ETX、長度位元組以及 BCC 位元組本身。
- 執行運算並讀取 XOR-8 BCC 的標籤結果。顯示的結果永遠是兩位數的十六進制數字,必要時會包含前置的零。
- 與裝置說明文件進行交叉比對。若裝置預期使用最終補數或不同的初始值,XOR-8 BCC 將不會相符;此時 Modbus LRC 欄位與原始位元組總和模數 256 欄位,將有助於釐清手冊所描述的是哪一種慣例。
- 複製標籤化的區塊,其中包含全部三個數值與處理過的位元組數量,如此貼上的診斷備註便能保留產生該數值的解讀方式。
Modbus ASCII LRC:一種不同的 8 位元檢查
Modbus ASCII 訊框並不使用原始 XOR。根據 Modbus over Serial Line 規格,LRC 的計算方式是將每個訊息位元組累加至一個八位元欄位,捨棄任何超出位元組範圍的進位,然後再取該總和的二補數。等效地說,LRC 就是位元組總和模數 256 的負值,這表示對於相同的輸入,LRC 與原始總和的總和恆為模數 256 之零。
在任何範例中可推導出兩項實際的結論。第一,起始冒號與結尾的歸位換行字元組屬於訊框定界字元,並不屬於提供給 LRC 的訊息位元組;規格中已明確將其排除。第二,兩個裝置若對同一訊框分別回報「校驗碼」與「LRC」,幾乎必然會得到不同的單一位元組數值,因為加法與 XOR 慣例在大多數承載資料上會產生分歧。將相同的十六進制位元組代入校驗碼計算工具,可同時並列顯示三種慣例的結果,這有助於辨識廠商文件實際描述的是哪一種公式。
8 位元區塊檢查字元的限制
值得再次強調的是,單位元組檢查能與不能做到的事情。一個八位元值只能產生 256 種不同的形式,因此對於任何非微不足道的訊框,許多不同的輸入會共用相同的 BCC。因此,這項檢查雖然能捕捉部分偶發的位元翻轉與部分訊框錯誤,卻無法偵測出所有的變更,而且要構造出具有相同數值的不同承載資料也極為容易。這就是為何 BCC 屬於傳輸完整性檢查,而非安全機制的緣故。
請勿使用 BCC、LRC 或原始總和模數 256 來保護憑證、授權指令、驗證軟體下載,或驗證不受信任的網路流量。請採用通訊協定實際要求的機制:以 CRC-16 或 CRC-32 提供更強的錯誤偵測能力,並使用加密雜湊函式或訊息鑑別碼來抵禦篡改。校驗碼計算工具對其適用範圍有明確說明:它重現兩種指定的八位元公式以及一項診斷總和,並未宣稱超出這些公式之外的通訊協定相容性,亦不宣稱具有鑑別功能。
該頁面同時設有 500,000 位元組的上限,絕不會默默截斷輸入,並會在遇到格式錯誤的十六進位資料時直接回報,而不會產出部分數值。輸出結果永遠是剛好兩位數的小寫十六進制數字。當貼上長串追蹤紀錄進行除錯時,這些防護機制至關重要,因為若輸入中含有誤讀的定界位元組或雜散的前綴字元,極容易被忽略。一旦公式宣告明確且輸入可供稽核,相同的演算範例便能在紙上、韌體中以及瀏覽器中毫無歧義地重現。
延伸閱讀:計算檔案的 CRC32:符合 8 位數的校驗碼。