2025年11月8日 星期六

修正後米勒編碼 曼徹斯特編碼

 修正後米勒編碼 曼徹斯特編碼 

專門說明 Modified Miller Encoding (修正後米勒編碼)Manchester Encoding (曼徹斯特編碼) 這兩種用於 RFID (ISO 14443A) 通信的數據編碼規則

🚀 1. 修正後米勒編碼 (Modified Miller Encoding)

用途: 讀卡機 (Reader) 發送數據到卡片 (Card) (ISO 14443A @ 106 kbps)。

調變方式: 100% ASK (振幅移位鍵控) - 編碼的高電平 (1) 代表載波 ON,低電平 (0) 代表載波 OFF

編碼規則:

數據位元 (Data Bit)規則描述 (載波 ON/OFF 狀態)編碼時序
邏輯 '1'在位元週期中間點電平必須轉換 (強制轉換)。自同步性來自於中間點的轉換。
邏輯 '0'若前一位元是 '1':整個位元週期保持低電平 (0)無轉換目的:創造一個長時間的 OFF 狀態。
邏輯 '0'若前一位元是 '0':在位元週期末尾電平必須轉換 (強制轉換)。目的:創造一個長時間的 ON 或 OFF 狀態。

程式碼中的繪圖邏輯解釋:

  • draw_modified_miller 函數根據上述複雜的規則來判斷每個位元週期內的電平變化和轉換點。

  • 圖中紅點標記了發生電平轉換的位置。例如:

    • 1:在中間點發生轉換。

    • 0 (前一個是 1): 整個週期保持低電平,無轉換。

    • 0 (前一個是 0): 在末尾點發生轉換。


🚀 2. 曼徹斯特編碼 (Manchester Encoding)

用途: 卡片 (Card) 發送數據到讀卡機 (Reader) (ISO 14443A @ 106 kbps)。

調變方式: 副載波負載調變 (Subcarrier Load Modulation) - 編碼信號調變 847 kHz 副載波

編碼規則 (ISO 14443A 定義):

數據位元 (Data Bit)規則描述 (電平轉換)編碼時序
邏輯 '1'在位元週期中間點發生 低電平 (L) $\to$ 高電平 (H) 轉換。前半 L,後半 H。
邏輯 '0'在位元週期中間點發生 高電平 (H) $\to$ 低電平 (L) 轉換。前半 H,後半 L。

特點:

  • 自同步性強: 每個位元週期中間都有一次強制轉換,接收端可以利用這個轉換來同步時鐘。

  • DC平衡: 每個位元週期內,高電平時間和低電平時間相等 (各佔一半),保證了信號沒有直流分量,適合電容耦合的通信環境。





import tkinter as tk

from tkinter import ttk


class EncodingViewer:

    def __init__(self, master):

        self.master = master

        master.title("ISO 14443A 數據編碼規則說明 (Tkinter)")

        

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

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


        ttk.Label(main_frame, text="✨ RFID 數據編碼規則 (106 kbps) ✨", 

                  font=("Arial", 16, "bold"), foreground="#336699").pack(pady=10)

        

        # --- 修正後米勒編碼 (Modified Miller Encoding) ---

        self.create_encoding_block(main_frame, "Modified Miller Encoding", 

                                   "讀卡機 -> 卡片: 修正後米勒編碼 (Modified Miller)", 

                                   [1, 0, 1, 1, 0, 0, 1], "#0099cc", self.draw_modified_miller)

        

        ttk.Separator(main_frame, orient='horizontal').pack(fill='x', pady=15)


        # --- 曼徹斯特編碼 (Manchester Encoding) ---

        self.create_encoding_block(main_frame, "Manchester Encoding", 

                                   "卡片 -> 讀卡機: 曼徹斯特編碼 (Manchester)", 

                                   [1, 0, 1, 0, 1, 1, 0], "#cc6600", self.draw_manchester)


    def create_encoding_block(self, parent_frame, name, title, data_bits, color, draw_function):

        """建立編碼區塊和繪圖區"""

        

        block_frame = ttk.Frame(parent_frame, relief="ridge", borderwidth=1, padding="10")

        block_frame.pack(fill='x', pady=5, padx=5)


        ttk.Label(block_frame, text=title, font=("Arial", 14, "bold"), 

                  foreground=color).pack(pady=(5, 5))

        

        ttk.Label(block_frame, text=f"**範例數據序列:** {' '.join(map(str, data_bits))}", 

                  font=("Arial", 10)).pack(anchor='w', padx=10, pady=5)

        

        canvas = tk.Canvas(block_frame, width=750, height=150, bg='white', borderwidth=1, relief="sunken")

        canvas.pack(padx=10, pady=10)

        

        # 繪製詳細波形

        draw_function(canvas, data_bits, color)

        

    

    # --- 繪圖邏輯輔助函數 ---

    def draw_line_segment(self, canvas, x_start, x_end, start_level, end_level, y_mid, color):

        """繪製編碼信號的線段和轉換"""

        y_start = y_mid - 40 if start_level == 1 else y_mid + 40

        y_end = y_mid - 40 if end_level == 1 else y_mid + 40

        

        # 繪製電平線

        canvas.create_line(x_start, y_start, x_end, y_start, fill=color, width=3)

        

        # 繪製轉換線

        if x_end != x_start and y_start != y_end:

             canvas.create_line(x_end, y_start, x_end, y_end, fill=color, width=3)

             canvas.create_oval(x_end - 3, y_start - 3, x_end + 3, y_start + 3, fill='red') # 標記轉換點

             

    def draw_bit_frame(self, canvas, x_start, bit_len, y_label, bit, color):

        """繪製單個位元的時序框和數據標籤"""

        y_data = 30

        

        canvas.create_line(x_start, y_label, x_start, y_label + 50, fill="gray", dash=(2, 2))

        canvas.create_line(x_start + bit_len, y_label, x_start + bit_len, y_label + 50, fill="gray", dash=(2, 2))

        

        canvas.create_text(x_start + bit_len/2, y_data, text=str(bit), fill="black", font=("Arial", 11, "bold"))

        canvas.create_text(x_start + bit_len/2, 140, text=f"T{bit}", fill=color)


    

    # --- 修正後米勒編碼 (Modified Miller Encoding) 繪圖 ---

    def draw_modified_miller(self, canvas, data_bits, color):

        BIT_LENGTH = 100

        Y_MID = 80

        canvas.create_text(20, Y_MID, text="載波\nON/OFF", anchor='w', font=("Arial", 10, "bold"))

        canvas.create_text(20, 30, text="數據位元", anchor='w', font=("Arial", 10, "italic"))

        

        # 繪製基準線

        canvas.create_line(50, Y_MID - 40, 750, Y_MID - 40, fill="lightgray")

        canvas.create_line(50, Y_MID + 40, 750, Y_MID + 40, fill="lightgray")

        

        current_x = 50

        prev_level = 0  # 假定開始前電平為低 (無載波)

        

        for bit in data_bits:

            self.draw_bit_frame(canvas, current_x, BIT_LENGTH, 50, bit, color)

            

            # --- 編碼規則 ---

            if bit == 1:

                # 邏輯 '1': 在位元中間點轉換

                current_level = 1 if prev_level == 0 else 0

                

                # 繪製前半週期

                self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH/2, prev_level, current_level, Y_MID, color)

                # 繪製後半週期 (無轉換)

                self.draw_line_segment(canvas, current_x + BIT_LENGTH/2, current_x + BIT_LENGTH, current_level, current_level, Y_MID, color)

                

                prev_level = current_level

                

            elif bit == 0:

                # 邏輯 '0': 

                # 1. 若前一個位元是 '1' (電平在中間轉換過): 整個位元週期保持在**低電平** (無載波)。

                # 2. 若前一個位元是 '0' (電平在中間未轉換): 在位元週期**末尾轉換**。


                # 判斷前一個位元電平是否在中間轉換

                if current_x > 50:

                    prev_bit = data_bits[data_bits.index(bit) - 1]

                else:

                    prev_bit = 0 # 假定第一個位元前為 0


                if prev_bit == 1:

                    # 情況 1: 整個週期保持在低電平 (無載波)

                    current_level = 0

                    self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH, prev_level, current_level, Y_MID, color)

                    # 由於沒有轉換,prev_level 不變,仍為 0


                else: # prev_bit == 0

                    # 情況 2: 位元末尾轉換

                    current_level = 1 if prev_level == 0 else 0

                    

                    # 繪製前半週期 (無轉換)

                    self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH, prev_level, prev_level, Y_MID, color) 

                    

                    # 繪製末尾轉換 (在位元結束點強制轉換)

                    self.draw_line_segment(canvas, current_x + BIT_LENGTH, current_x + BIT_LENGTH, prev_level, current_level, Y_MID, color)

                    prev_level = current_level


            current_x += BIT_LENGTH

            

            

    # --- 曼徹斯特編碼 (Manchester Encoding) 繪圖 ---

    def draw_manchester(self, canvas, data_bits, color):

        BIT_LENGTH = 100

        Y_MID = 80

        canvas.create_text(20, Y_MID, text="編碼\n電平", anchor='w', font=("Arial", 10, "bold"))

        canvas.create_text(20, 30, text="數據位元", anchor='w', font=("Arial", 10, "italic"))

        

        # 繪製基準線

        canvas.create_line(50, Y_MID - 40, 750, Y_MID - 40, fill="lightgray")

        canvas.create_line(50, Y_MID + 40, 750, Y_MID + 40, fill="lightgray")

        

        current_x = 50

        prev_level = 0 

        

        for bit in data_bits:

            self.draw_bit_frame(canvas, current_x, BIT_LENGTH, 50, bit, color)

            

            # --- 編碼規則 (ISO 14443A 定義) ---

            if bit == 1:

                # 邏輯 '1': 低電平 (L) -> 高電平 (H) 轉換 (在位元中間)

                start_level = 0

                end_level = 1

            else: # bit == 0

                # 邏輯 '0': 高電平 (H) -> 低電平 (L) 轉換 (在位元中間)

                start_level = 1

                end_level = 0

            

            # 繪製前半週期

            self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH/2, start_level, start_level, Y_MID, color)

            

            # 繪製轉換點

            self.draw_line_segment(canvas, current_x + BIT_LENGTH/2, current_x + BIT_LENGTH/2, start_level, end_level, Y_MID, color)

            canvas.create_oval(current_x + BIT_LENGTH/2 - 3, self.get_y_coord(start_level, Y_MID) - 3, 

                               current_x + BIT_LENGTH/2 + 3, self.get_y_coord(start_level, Y_MID) + 3, fill='red') # 標記轉換點

            

            # 繪製後半週期

            self.draw_line_segment(canvas, current_x + BIT_LENGTH/2, current_x + BIT_LENGTH, end_level, end_level, Y_MID, color)

            

            current_x += BIT_LENGTH

            

    def get_y_coord(self, level, y_mid):

        """根據電平 (0或1) 獲取 y 坐標"""

        return y_mid - 40 if level == 1 else y_mid + 40


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

if __name__ == "__main__":

    root = tk.Tk()

    app = EncodingViewer(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...