CRC(循環冗餘檢查)
完整的 CRC(循環冗餘檢查)逐步演示器。它支援自定義生成多項式與資料位元流,並透過「下一步」按鈕展示二進制長除法(XOR 運算)的過程。
二進制長除法模擬:
CRC 的核心是模二除法(Modulo-2 Division),實務上就是不斷進行 XOR(互斥或)。
程式會自動在資料後方補零(數量等於多項式長度減一)。
產生器 vs 檢查器:
產生器 (Generator):輸入原始資料(如
1101),得到的餘數就是 CRC 碼。發送時,會將此 CRC 碼附加在原始資料後方。檢查器 (Checker):輸入「原始資料 + CRC 碼」。如果最後算出的餘數為 全 0,則代表傳輸無誤。
import tkinter as tk
from tkinter import messagebox
class CRCApp:
def __init__(self, root):
self.root = root
self.root.title("CRC 循環冗餘檢查逐步演示器")
self.root.geometry("800x800")
# 運算狀態變數
self.data_bits = [] # 原始資料 + 補零
self.poly_bits = [] # 生成多項式
self.current_divisor_pos = 0
self.temp_remainder = []
self.steps_log = []
self.create_widgets()
def create_widgets(self):
# 輸入區
input_frame = tk.LabelFrame(self.root, text=" 參數設定 ", padx=10, pady=10)
input_frame.pack(fill=tk.X, padx=20, pady=10)
# 1. 生成多項式
tk.Label(input_frame, text="1) 生成多項式 (例如 CRC-4: 10011):").grid(row=0, column=0, sticky=tk.W)
self.ent_poly = tk.Entry(input_frame, font=("Courier New", 12), width=30)
self.ent_poly.insert(0, "10011")
self.ent_poly.grid(row=0, column=1, padx=10, pady=5)
# 2. 資料位元流
tk.Label(input_frame, text="2) 資料位元流 (Binary Bit Stream):").grid(row=1, column=0, sticky=tk.W)
self.ent_data = tk.Entry(input_frame, font=("Courier New", 12), width=30)
self.ent_data.insert(0, "1101011011")
self.ent_data.grid(row=1, column=1, padx=10, pady=5)
# 按鈕區
btn_frame = tk.Frame(self.root)
btn_frame.pack(pady=10)
tk.Button(btn_frame, text="初始化運算", command=self.init_crc, bg="#eee", 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)
# 3. 畫面顯示區 (文字區域)
tk.Label(self.root, text="演示畫面 (二進制長除法過程):", font=("Arial", 10, "bold")).pack(anchor=tk.W, padx=20)
self.txt_display = tk.Text(self.root, font=("Courier New", 12), height=25, bg="#000", fg="#0F0", padx=15, pady=15)
self.txt_display.pack(padx=20, pady=10, fill=tk.BOTH, expand=True)
# 底部狀態
self.lbl_status = tk.Label(self.root, text="請輸入參數並點擊初始化", font=("Arial", 12, "bold"), fg="blue")
self.lbl_status.pack(pady=10)
def init_crc(self):
# 讀取並驗證輸入
d_str = self.ent_data.get().strip()
p_str = self.ent_poly.get().strip()
if not all(b in '01' for b in d_str + p_str) or not d_str or not p_str:
messagebox.showerror("錯誤", "請輸入有效的二進制位元流 (僅限 0 與 1)")
return
# CRC 邏輯:在資料後方補上 (多項式長度 - 1) 個零
n_zeros = len(p_str) - 1
self.data_bits = [int(b) for b in d_str] + [0] * n_zeros
self.poly_bits = [int(b) for b in p_str]
self.current_divisor_pos = 0
self.temp_remainder = self.data_bits[0:len(p_str)]
self.btn_next.config(state=tk.NORMAL)
self.txt_display.delete(1.0, tk.END)
self.lbl_status.config(text="計算中...", fg="orange")
# 初始畫面繪製
init_info = f"多項式: {p_str} (長度 {len(p_str)})\n"
init_info += f"待處理資料: {d_str} (補 {n_zeros} 個零)\n"
init_info += "="*40 + "\n"
init_info += "".join(map(str, self.data_bits)) + " (被除數)\n"
self.txt_display.insert(tk.END, init_info)
def next_step(self):
p_len = len(self.poly_bits)
# 執行一次 XOR 運算
divisor = self.poly_bits if self.temp_remainder[0] == 1 else [0] * p_len
# 記錄目前步驟到 Text
prefix_space = " " * self.current_divisor_pos
self.txt_display.insert(tk.END, f"{prefix_space}{''.join(map(str, divisor))} (XOR)\n")
self.txt_display.insert(tk.END, f"{prefix_space}{'-' * p_len}\n")
# 計算 XOR 結果
xor_res = []
for i in range(p_len):
xor_res.append(self.temp_remainder[i] ^ divisor[i])
# 移除最高位,並從後方拉下一個位元
next_pos = self.current_divisor_pos + p_len
if next_pos < len(self.data_bits):
new_remainder = xor_res[1:] + [self.data_bits[next_pos]]
self.temp_remainder = new_remainder
self.current_divisor_pos += 1
self.txt_display.insert(tk.END, f"{' ' * self.current_divisor_pos}{''.join(map(str, self.temp_remainder))}\n")
self.txt_display.see(tk.END)
else:
# 結束,最後的結果即為餘數 (Check value)
remainder = "".join(map(str, xor_res[1:]))
self.txt_display.insert(tk.END, f"\n最終餘數 (CRC Check Value): {remainder}\n")
self.lbl_status.config(text=f"完成!CRC 碼: {remainder}", fg="blue")
self.btn_next.config(state=tk.DISABLED)
if __name__ == "__main__":
root = tk.Tk()
app = CRCApp(root)
root.mainloop()
沒有留言:
張貼留言