2025年11月8日 星期六

概念性地說明 16-bit CRC 的動作原理

概念性地說明 16-bit CRC 的動作原理



根據您提供的 MFRC522 技術文件截圖(圖 8.2.5 CRC coprocessor 和表 17)

一步一步(step by step)地概念性地說明 16-bit CRC 的動作原理

由於 CRC 運算本質上是基於二進制的多項式除法,我們將使用 tkinter 的標籤和文本來展示每一步的異或 (XOR) 運算過程,並遵循 MFRC522 的規格:

  1. 多項式 (Polynomial): x^16 + x^12 + x^5 + 1  (即 10001000000100001(2) )。

  2. 數據順序: MSB (最高有效位) First。

💻 Python Tkinter CRC 運算說明程式碼

這個程式會示範如何對一個 8-bit 的輸入數據進行 16-bit CRC 運算。


基礎原理

CRC 運算是一種錯誤偵測碼,其原理是將數據視為一個二進制多項式,並對其進行多項式除法。剩餘的 16 位數就是 CRC 校驗碼。

MFRC522 CRC 規格:

  • 多項式 P(x): x^16 + x^12 + x^5 + 1 (ISO/IEC 14443A 標準)。

  • 暫存器長度: 16-bit。

  • 數據順序: MSB (最高有效位) First。

  • 初始值 (Preset): 可選 0000h (本範例使用)、6363hA671h 或 FFFFh

CRC 暫存器步驟動作 (每個輸入位元)

對於 MFRC522 協處理器,每個輸入數據位元的處理步驟如下:

Step 1: 取得輸入位元

  • 從輸入數據流中取出一個位元 (MSB First)。

Step 2: 判斷是否需要 XOR (除法)

  • 判斷當前 CRC 暫存器的 MSB (第 15 位) 與 新輸入的位元 進行 異或 (XOR) 的結果。

    Do XOR = CRC[15]  ⊕  Input Bit

Step 3: CRC 暫存器左移 (乘 $x$)

  • 將 16-bit CRC 暫存器的所有位元向左移動一位。這相當於在多項式除法中將數據乘以 $x$

  • 左移會將 CRC 暫存器的 MSB (第 15 位) 移出。

Step 4: 執行條件式 XOR 運算 (除法)

  • 如果 Do XOR = 1

    • 表示當前的 CRC 餘數 (在左移前) 大於或等於多項式。

    • 將 CRC 暫存器與多項式的低 16 位進行異或運算。

    • 多項式的低 16 位 (即 x^15 到 x^0) 是 x^12 + x^5 + 1,對應二進制 0001000000100001(2) (1021h)。

  • 如果 Do XOR = 0

    • 表示餘數小於多項式,本次不需要進行 XOR 運算。

Step 5: 重複

  • 對所有輸入位元重複 Step 1 到 Step 4。

最終,CRC 暫存器中剩下的 16 位數,即是 CRCResultH 和CRCResultL 暫存器所指示的 CRC 校驗碼。



import tkinter as tk

from tkinter import ttk

from collections import deque


# --- MFRC522 CRC 規格參數 ---

# P(x) = x^16 + x^12 + x^5 + 1

# 17-bit 二進制表示 (最高位是 x^16, 最低位是 x^0)

POLYNOMIAL = 0b10001000000100001

POLYNOMIAL_STR = format(POLYNOMIAL, '017b')

CRC_WIDTH = 16


class CRCCalculatorApp:

    def __init__(self, master):

        self.master = master

        master.title("MFRC522 16-bit CRC 動作原理說明 (Step-by-Step)")


        # 選擇預設值 (ModeReg's CRCPreset[1:0] = 00)

        self.preset_value = 0x0000 

        

        # 範例輸入數據 (例如: 1 0 1 1 0 0 1 1)

        self.input_data_hex = tk.StringVar(value="B3") 

        self.input_data_bin = format(int(self.input_data_hex.get(), 16), '08b')

        

        self.data_queue = deque([int(b) for b in self.input_data_bin])

        

        # 16-bit CRC 暫存器 (初始為 Preset Value)

        self.crc_register = self.preset_value

        

        self.setup_ui(master)

        self.step = 0

        self.max_steps = 8 # 處理 8 個輸入位元


    def setup_ui(self, master):

        """建立應用程式的用戶界面"""

        

        main_frame = ttk.Frame(master, padding="15")

        main_frame.pack(fill='both', expand=True)


        ttk.Label(main_frame, text="⚙️ MFRC522 CRC 動作原理 ⚙️", 

                  font=("Arial", 16, "bold"), foreground="#0055AA").pack(pady=5)

        

        # --- 參數顯示區 ---

        param_frame = ttk.LabelFrame(main_frame, text="CRC 規格參數", padding="10")

        param_frame.pack(fill='x', pady=10)

        

        ttk.Label(param_frame, text=f"**多項式 P(x):** x¹⁶ + x¹² + x⁵ + 1", font=("Arial", 10)).grid(row=0, column=0, sticky='w')

        ttk.Label(param_frame, text=f"**二進制形式 (17-bit):** {POLYNOMIAL_STR}", font=("Arial", 10)).grid(row=0, column=1, sticky='w', padx=10)

        ttk.Label(param_frame, text=f"**預設值 (Preset):** {format(self.preset_value, '04X')}h", font=("Arial", 10)).grid(row=1, column=0, sticky='w')

        ttk.Label(param_frame, text=f"**輸入數據 (MSB First):** {self.input_data_hex.get()}h ({self.input_data_bin})", font=("Arial", 10)).grid(row=1, column=1, sticky='w', padx=10)


        # --- 運算顯示區 ---

        self.calc_frame = ttk.LabelFrame(main_frame, text="CRC 步驟運算", padding="10")

        self.calc_frame.pack(fill='both', expand=True, pady=10)


        # 標題

        ttk.Label(self.calc_frame, text="步驟", font=("Arial", 10, "bold")).grid(row=0, column=0, padx=5)

        ttk.Label(self.calc_frame, text="當前輸入位元", font=("Arial", 10, "bold")).grid(row=0, column=1, padx=5)

        ttk.Label(self.calc_frame, text="CRC 暫存器狀態 (16-bit)", font=("Arial", 10, "bold")).grid(row=0, column=2, padx=10)

        ttk.Label(self.calc_frame, text="操作/條件", font=("Arial", 10, "bold")).grid(row=0, column=3, padx=10)

        

        # 結果和步驟控制

        self.result_label = ttk.Label(main_frame, text="點擊 '下一步' 開始 CRC 運算。", font=("Arial", 11))

        self.result_label.pack(pady=10)


        self.next_button = ttk.Button(main_frame, text="下一步 (處理第 1 個位元)", command=self.next_step)

        self.next_button.pack(pady=5)

        

        ttk.Button(main_frame, text="重置", command=self.reset).pack(pady=5)


    def reset(self):

        """重置運算狀態"""

        self.step = 0

        self.crc_register = self.preset_value

        self.data_queue = deque([int(b) for b in self.input_data_bin])

        

        # 清除舊的運算步驟

        for widget in self.calc_frame.winfo_children():

            if int(widget.grid_info().get("row")) > 0:

                widget.destroy()


        self.result_label.config(text="點擊 '下一步' 開始 CRC 運算。")

        self.next_button.config(text=f"下一步 (處理第 1 個位元)", state=tk.NORMAL)



    def next_step(self):

        """執行 CRC 運算的下一步"""

        if self.step >= self.max_steps:

            self.next_button.config(state=tk.DISABLED, text="運算完成")

            return

            

        self.step += 1

        row = self.step

        

        # 1. 取得輸入位元 (MSB First)

        input_bit = self.data_queue.popleft()

        

        # 2. 獲取 CRC 暫存器的 MSB (第 15 位)

        # 由於是 16-bit 暫存器,最高位是 x^15

        crc_msb = (self.crc_register >> (CRC_WIDTH - 1)) & 0x1 

        

        # 3. 將新的輸入位元 XOR 暫存器的 MSB (決定是否進行多項式除法)

        do_xor = crc_msb ^ input_bit

        

        # 4. 暫存器左移 1 位 (相當於乘以 x)

        # 由於是 16-bit 暫存器,左移後,位元 x^0 被移出,x^16 進入

        self.crc_register = (self.crc_register << 1) & 0xFFFF 

        

        operation_text = ""

        

        # 5. 執行條件式 XOR (除法)

        if do_xor == 1:

            # 進行 XOR 運算 (異或多項式)

            # 注意:這裡多項式是 17-bit,但只對 CRC 暫存器 (16-bit) 進行異或。

            # MFRC522 的 CRC 多項式是 x^16 + x^12 + x^5 + 1 (17-bit)。

            # 在 XOR 階段,我們只 XOR 它的低 16 位 ($x^{15}$ 到 $x^0$),即 $x^{12} + x^5 + 1$。

            # P_low = 0001000000100001 (16-bit)

            

            P_low = (POLYNOMIAL >> 1) & 0xFFFF # 取得多項式的低 16 位

            self.crc_register ^= P_low

            operation_text = f"CRC[15] ^ Input = 1。CRC ^= P_low ({format(P_low, '04X')}h)"

        else:

            operation_text = f"CRC[15] ^ Input = 0。只進行左移。"


        # 6. 更新 UI 顯示

        # 顯示當前輸入位元

        ttk.Label(self.calc_frame, text=f"第 {row} 位", font=("Arial", 10)).grid(row=row, column=0, padx=5, pady=2)

        ttk.Label(self.calc_frame, text=f"**{input_bit}**", font=("Arial", 10, "bold"), foreground="blue").grid(row=row, column=1, padx=5, pady=2)

        

        # 顯示運算結果 (CRC 暫存器狀態)

        crc_bin_str = format(self.crc_register, '016b')

        crc_hex_str = format(self.crc_register, '04X')

        ttk.Label(self.calc_frame, text=f"**{crc_bin_str}** ({crc_hex_str}h)", 

                  font=("Courier", 9, "bold"), foreground="green").grid(row=row, column=2, padx=10, pady=2, sticky='w')

        

        # 顯示操作/條件

        ttk.Label(self.calc_frame, text=operation_text, font=("Arial", 9)).grid(row=row, column=3, padx=10, pady=2, sticky='w')

        

        # 7. 更新步驟按鈕和結果標籤

        if self.step < self.max_steps:

            self.next_button.config(text=f"下一步 (處理第 {self.step + 1} 個位元)")

        else:

            final_crc_bin = format(self.crc_register, '016b')

            final_crc_hex = format(self.crc_register, '04X')

            

            # MFRC522 的 CRCResult 暫存器是 CRCResultH (高 8 bit) 和 CRCResultL (低 8 bit)

            crc_result_h = (self.crc_register >> 8) & 0xFF

            crc_result_l = self.crc_register & 0xFF

            

            self.result_label.config(text=f"✅ 運算完成!最終 16-bit CRC: **{final_crc_hex}h**\n (CRCResultH: {format(crc_result_h, '02X')}h, CRCResultL: {format(crc_result_l, '02X')}h)",

                                     font=("Arial", 12, "bold"), foreground="purple")

            self.next_button.config(state=tk.DISABLED, text="運算完成")


# --- 運行 Tkinter 程式 ---

if __name__ == "__main__":

    root = tk.Tk()

    app = CRCCalculatorApp(root)

    root.mainloop()


沒有留言:

張貼留言

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...