2026年1月15日 星期四

縱向冗餘檢查法(LRC, Longitudinal Redundancy Check)

縱向冗餘檢查法(LRC, Longitudinal Redundancy Check)

縱向冗餘檢查法(LRC, Longitudinal Redundancy Check)是一種簡單的錯誤檢查方式,通常應用於工業通訊(如 Modbus ASCII)。它的原理是將所有資料位元組進行 XOR(互斥或) 運算。 

產生器 (Generator)檢查器 (Checker) 功能的 LRC 進階演示程式。

在「檢查器」模式下,如果最後計算出的結果為 00,則代表資料傳輸正確;若非 00 則代表資料有誤。

LRC 原理解析與操作說明

  1. 二進制 XOR (互斥或) 運算:

    LRC 的核心就是對每一個位元組進行二進制運算。

    • ⊕ 0 = 0

    •  1 = 0

    •  1 = 1 

    •  0 = 1 

      當我們將一連串的位元組互相 XOR 時,得到的結果就是 LRC 值。

  2. 為什麼要用 LRC?

    • 它比簡單的奇偶校驗強大,可以偵測出單一位元組內多個位元的錯誤。

    • Modbus ASCII 傳輸中,LRC 被放在封包的結尾。

  3. 如何使用檢查器?

    • 當接收端收到資料時,將所有資料位元組(含 LRC)再次全部 XOR 運算。

    • 如果結果為 00,則表示傳輸過程中沒有發生單一位元錯誤。

程式功能:

  • 16進制轉換:輸入 52 A3 等字串,程式自動將其解析為數值。

  • 二進制可視化:在執行下一步時,畫面會同時顯示 Hex 值與 8-bit 二進制值,方便觀察 XOR 的變化。

  • 逐步演示:透過「下一步」按鈕,您可以觀察 LRC 如何從第一個位元組累積到最後一個。

1. 產生器模式 (Generator)

  • 用途:當你要發送資料時,計算該附加上去的校驗碼。

  • 步驟:輸入資料(如 52 A3 BD)   點擊下一步直到完畢  程式會告訴你最終的 LRC(例如 48)。

  • 結果:你實際發送的內容應為 52 A3 BD 48

2. 檢查器模式 (Checker)

  • 用途:當你收到一串資料,想確認它對不對。

  • 步驟:輸入收到的完整序列(包含最後一個 LRC 位元組,例如 52 A3 BD 48)。

  • 判定:如果資料完全正確,最後一步的結果一定是 00

LRC 的數學美感

LRC 利用了 XOR 的對稱性質。如果你對一組數字 A, B, C 做 XOR 得到 L = A  B C ,那麼將 L 本身也加入運算時:


 B  C L = L  L = 0 

這就是為什麼檢查器模式下,正確資料的結果必然為零的原因。





import tkinter as tk

from tkinter import messagebox, ttk


class LRCAdvancedApp:

    def __init__(self, root):

        self.root = root

        self.root.title("LRC 縱向冗餘檢查器 (產生/檢查)")

        self.root.geometry("700x750")


        # 狀態變數

        self.data_bytes = []

        self.current_step = -1

        self.current_lrc = 0

        

        self.create_widgets()


    def create_widgets(self):

        # 模式選擇區

        mode_frame = tk.Frame(self.root, pady=10)

        mode_frame.pack()

        

        tk.Label(mode_frame, text="選擇模式:", font=("Arial", 10, "bold")).pack(side=tk.LEFT)

        self.mode_var = tk.StringVar(value="generator")

        tk.Radiobutton(mode_frame, text="產生器 (計算LRC)", variable=self.mode_var, value="generator").pack(side=tk.LEFT, padx=10)

        tk.Radiobutton(mode_frame, text="檢查器 (驗證資料)", variable=self.mode_var, value="checker").pack(side=tk.LEFT, padx=10)


        # 輸入區

        input_frame = tk.Frame(self.root, pady=10)

        input_frame.pack()

        

        tk.Label(input_frame, text="輸入 16 進制序列:", font=("Arial", 10)).pack(anchor=tk.W)

        self.ent_hex = tk.Entry(input_frame, font=("Courier New", 12), width=40)

        self.ent_hex.insert(0, "52 A3 BD 89 C6")

        self.ent_hex.pack(pady=5)

        

        tk.Label(input_frame, text="(檢查器模式請包含最後一個 LRC 位元組)", fg="gray", font=("Arial", 9)).pack()


        # 控制按鈕

        btn_frame = tk.Frame(self.root)

        btn_frame.pack(pady=10)

        

        tk.Button(btn_frame, text="初始化重置", command=self.reset_lrc, bg="#f0f0f0", width=15).pack(side=tk.LEFT, padx=5)

        self.btn_next = tk.Button(btn_frame, text="執行下一步 >>", command=self.next_step, 

                                  state=tk.DISABLED, bg="#4CAF50", fg="white", font=("Arial", 10, "bold"), width=15)

        self.btn_next.pack(side=tk.LEFT, padx=5)


        # 顯示區

        self.txt_display = tk.Text(self.root, font=("Courier New", 11), height=22, padx=15, pady=15, bg="#fafafa")

        self.txt_display.pack(padx=20, pady=10, fill=tk.BOTH, expand=True)

        

        # 最終狀態指示燈

        self.lbl_status = tk.Label(self.root, text="準備就緒", font=("Arial", 14, "bold"), fg="gray")

        self.lbl_status.pack(pady=15)


    def reset_lrc(self):

        hex_str = self.ent_hex.get().strip()

        try:

            self.data_bytes = [int(x, 16) for x in hex_str.split()]

            if not self.data_bytes: raise ValueError

        except:

            messagebox.showerror("錯誤", "16 進制格式錯誤。範例: 52 A3 BD")

            return


        self.current_step = 0

        self.current_lrc = 0

        self.btn_next.config(state=tk.NORMAL)

        

        mode_text = "產生器模式 (計算最後的 LRC)" if self.mode_var.get() == "generator" else "檢查器模式 (結果應為 00)"

        self.lbl_status.config(text=f"正在執行: {mode_text}", fg="#333")

        

        self.txt_display.delete(1.0, tk.END)

        self.txt_display.insert(tk.END, f"模式: {mode_text}\n")

        self.txt_display.insert(tk.END, f"載入資料: {' '.join([f'{b:02X}' for b in self.data_bytes])}\n")

        self.txt_display.insert(tk.END, "-"*50 + "\n")


    def next_step(self):

        if self.current_step < len(self.data_bytes):

            byte_val = self.data_bytes[self.current_step]

            old_lrc = self.current_lrc

            self.current_lrc ^= byte_val

            

            # 詳細顯示

            self.txt_display.insert(tk.END, f"【步驟 {self.current_step + 1}】\n")

            self.txt_display.insert(tk.END, f" 上一次 LRC:  {old_lrc:02X}  ({old_lrc:08b})\n")

            self.txt_display.insert(tk.END, f" XOR 資料:    {byte_val:02X}  ({byte_val:08b})\n")

            self.txt_display.insert(tk.END, f" =目前結果:   {self.current_lrc:02X}  ({self.current_lrc:08b})\n")

            self.txt_display.insert(tk.END, "-"*35 + "\n")

            self.txt_display.see(tk.END)

            

            self.current_step += 1

            

            # 檢查是否結束

            if self.current_step == len(self.data_bytes):

                self.btn_next.config(state=tk.DISABLED)

                self.finalize_result()


    def finalize_result(self):

        mode = self.mode_var.get()

        final_val = self.current_lrc

        

        if mode == "generator":

            self.lbl_status.config(text=f"產生完成!LRC = {final_val:02X}", fg="blue")

            self.txt_display.insert(tk.END, f"\n計算結束。建議傳輸序列: \n{' '.join([f'{b:02X}' for b in self.data_bytes])} {final_val:02X}")

        else:

            if final_val == 0:

                self.lbl_status.config(text="檢查通過 (PASS): 結果為 00", fg="green")

                self.txt_display.insert(tk.END, "\n[驗證成功] 所有位元組 XOR 結果為 0,資料正確。")

            else:

                self.lbl_status.config(text=f"檢查失敗 (FAIL): 結果 {final_val:02X}", fg="red")

                self.txt_display.insert(tk.END, f"\n[驗證失敗] 結果不為 0,資料在傳輸中可能已受損。")


if __name__ == "__main__":

    root = tk.Tk()

    app = LRCAdvancedApp(root)

    root.mainloop()


沒有留言:

張貼留言

CRC(循環冗餘檢查)

  CRC(循環冗餘檢查) 完整的 CRC(循環冗餘檢查)逐步演示器 。它支援自定義 生成多項式 與 資料位元流 ,並透過「下一步」按鈕展示二進制長除法(XOR 運算)的過程。 二進制長除法模擬 : CRC 的核心是模二除法(Modulo-2 Division),實務上就是不斷進...