2025年11月8日 星期六

ISO/IEC 14443A 標準在 106 kbps 速率下的讀卡機與卡片之間的物理層通信信號

 




  

1. 程式會創建一個圖形用戶界面(GUI),用於概念性地說明 MFRC522 晶片遵循 ISO/IEC 14443A 標準106 kbps 速率下的讀卡機與卡片之間的物理層通信信號。

2. 讀卡機到卡片 (Reader to Card) - 發送數據

  • 信號格式:

    • 調變方式 (Signal type): 100 % ASK (Amplitude Shift Keying,振幅移位鍵控)。

    • 位元編碼 (Bit Encoding): Modified Miller Encoding (改變的米勒編碼)。

    • 傳輸速率 (Transfer Speed): 106 kBd (千位元/秒)。

    • 位元長度 (Bit length): $128 \times (1/13.56 \text{ MHz}) \approx 13.56 \text{ } \mu\text{s}$

  • 調變波形概念 (Canvas 繪圖區說明):

    • 100% ASK 意指讀卡機發射的 13.56 MHz 載波在傳輸數據時,其振幅會從 100% (有載波) 降到 0% (無載波),達到完全切斷載波的效果。

    • Modified Miller Encoding 是一種自同步編碼方式,它決定了載波何時開啟或關閉:

      • 傳輸 邏輯 '1':在位元週期的前半段有載波,後半段無載波 (在位元週期中間發生調變)。

      • 傳輸 邏輯 '0'

        • 若前一個位元為 '1':在整個位元週期內無載波

        • 若前一個位元為 '0':在位元週期的後半段有載波,前半段無載波 (在位元週期開始時無調變,但在中間會調變)。

3. 卡片到讀卡機 (Card to Reader) - 接收數據

  • 信號格式:

    • 調變方式 (Signal type): Subcarrier Load Modulation (副載波負載調變)。

    • 副載波頻率 (Subcarrier frequency): 13.56 MHz / 16 (約 847 kHz)。

    • 位元編碼 (Bit Encoding): Manchester Encoding (曼徹斯特編碼)。

    • 傳輸速率 (Transfer Speed): 106 kBd (千位元/秒)。

  • 調變波形概念 (Canvas 繪圖區說明):

    • 負載調變:卡片本身沒有發射器,它透過改變天線上的負載阻抗,來對讀卡機發出的 13.56 MHz 載波場造成微小的反射調變。讀卡機偵測場的微小變化來接收數據。

    • 副載波與曼徹斯特編碼: 卡片不會直接調變 13.56 MHz 載波,而是先產生一個 847 kHz 的副載波,用 Manchester Encoding 將數據編碼到這個副載波上,然後再用這個編碼過的副載波去調變負載。

      • Manchester Encoding:在每個位元週期中間都會發生電平轉換。邏輯 '0' 為高到低轉換;邏輯 '1' 為低到高轉換 (極性可能在不同文獻中有差異,但核心是中間的轉換)。





import tkinter as tk

from tkinter import ttk


# --- ISO/IEC 14443A 106 kbps 通信參數 (根據您提供的圖片表格) ---

PARAMS = {

    "Reader_to_Card": {

        "Direction": "讀卡機 -> 卡片 (發送數據)",

        "Modulation": "100 % ASK (振幅移位鍵控)",

        "Bit_Encoding": "Modified Miller Encoding (改變的米勒編碼)",

        "Transfer_Speed": "106 kBd",

        "Bit_Length": "128 (13.56 μs)",

        "Signal_Info": "載波 (13.56MHz) 被100%調變,使用Modified Miller編碼。訊號在數據傳輸期間完全開啟或關閉。"

    },

    "Card_to_Reader": {

        "Direction": "卡片 -> 讀卡機 (接收數據)",

        "Modulation": "Subcarrier Load Modulation (副載波負載調變)",

        "Subcarrier_Freq": "13.56 MHz / 16 (約 847 kHz)",

        "Bit_Encoding": "Manchester Encoding (曼徹斯特編碼)",

        "Transfer_Speed": "106 kBd",

        "Signal_Info": "卡片通過改變負載阻抗來調變讀卡機的場。使用13.56MHz/16的副載波進行曼徹斯特編碼。"

    }

}


class MFRC522SignalViewer:

    def __init__(self, master):

        self.master = master

        master.title("MFRC522 (ISO/IEC 14443A) 106 kbps 信號格式說明")


        # 設定主視窗樣式

        style = ttk.Style()

        style.configure("TLabel", font=("Arial", 10))

        style.configure("TFrame", padding=10)

        

        # 建立主要框架

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

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


        # 標題

        ttk.Label(main_frame, text="🌟 MFRC522 106 kbps 通信信號概覽 🌟", 

                  font=("Arial", 14, "bold")).pack(pady=10)

        

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


        # 讀卡機到卡片 (Reader to Card) 區塊

        self.create_signal_block(main_frame, "Reader_to_Card", "讀卡機到卡片的調變波形 (100% ASK)", "lightblue")

        

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


        # 卡片到讀卡機 (Card to Reader) 區塊

        self.create_signal_block(main_frame, "Card_to_Reader", "卡片到讀卡機的調變波形 (負載調變)", "lightcoral")


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


        ttk.Label(main_frame, text="注意: 這是對物理層調變原理的概念性展示,並非實際的射頻波形圖。", 

                  font=("Arial", 9, "italic")).pack(pady=5)



    def create_signal_block(self, parent_frame, key, title_text, color):

        """建立信號格式的說明區塊和概念性波形圖"""

        

        block_frame = ttk.Frame(parent_frame, relief="groove", borderwidth=2)

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


        # 區塊標題

        ttk.Label(block_frame, text=title_text, font=("Arial", 12, "bold"), 

                  foreground="navy").pack(pady=(5, 5))

        

        # 參數列表

        params_frame = ttk.Frame(block_frame)

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


        row_num = 0

        for name, value in PARAMS[key].items():

            ttk.Label(params_frame, text=f"**{name.replace('_', ' ')}:**", 

                      font=("Arial", 10, "bold")).grid(row=row_num, column=0, sticky='w', padx=5, pady=2)

            ttk.Label(params_frame, text=value, 

                      font=("Arial", 10)).grid(row=row_num, column=1, sticky='w', padx=5, pady=2)

            row_num += 1


        # 概念性波形繪製區

        ttk.Label(block_frame, text="[概念性調變信號展示]", font=("Arial", 10, "italic")).pack(pady=(5, 0))

        canvas = tk.Canvas(block_frame, width=400, height=100, bg='white', borderwidth=1, relief="solid")

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

        

        self.draw_conceptual_waveform(canvas, key, color)

        

        

    def draw_conceptual_waveform(self, canvas, key, color):

        """繪製概念性的調變波形"""

        

        if key == "Reader_to_Card":

            # 讀卡機 -> 卡片 (100% ASK & Modified Miller)

            canvas.create_text(200, 10, text="100% ASK / Modified Miller 概念", fill="black")

            

            # 假設數據 '101'

            # 1: 50% 載波

            canvas.create_rectangle(10, 30, 130, 70, fill=color, outline="darkblue")

            canvas.create_text(70, 50, text="載波 (1)", fill="darkblue")

            

            # 0: 無載波

            canvas.create_line(130, 50, 250, 50, fill="darkblue", width=2)

            canvas.create_text(190, 80, text="無載波 (0)", fill="darkblue")


            # 1: 50% 載波

            canvas.create_rectangle(250, 30, 370, 70, fill=color, outline="darkblue")

            canvas.create_text(310, 50, text="載波 (1)", fill="darkblue")

            

            canvas.create_text(20, 90, text="時脈", fill="gray")

            canvas.create_text(370, 90, text="...", fill="gray")

            

        elif key == "Card_to_Reader":

            # 卡片 -> 讀卡機 (負載調變 & Manchester)

            canvas.create_text(200, 10, text="負載調變 / Manchester 概念", fill="black")

            

            # 簡化表示: 副載波在負載調變期間出現

            canvas.create_line(10, 50, 390, 50, fill="gray", width=1, dash=(5, 5))

            canvas.create_text(50, 80, text="讀卡機載波場", fill="gray")


            # 假設數據 '101' 產生的負載調變(副載波)

            # 1 (曼徹斯特: 0->1 transition, 副載波出現)

            canvas.create_rectangle(10, 30, 130, 70, fill=color, outline="darkred", stipple="gray25")

            canvas.create_text(70, 50, text="副載波", fill="darkred")


            # 0 (曼徹斯特: 1->0 transition, 副載波出現)

            canvas.create_rectangle(130, 30, 250, 70, fill=color, outline="darkred", stipple="gray25")

            canvas.create_text(190, 50, text="副載波", fill="darkred")


            # 1 (曼徹斯特: 0->1 transition, 副載波出現)

            canvas.create_rectangle(250, 30, 370, 70, fill=color, outline="darkred", stipple="gray25")

            canvas.create_text(310, 50, text="副載波", fill="darkred")


            canvas.create_text(200, 90, text="... 在副載波上編碼數據 ...", fill="black")


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

if __name__ == "__main__":

    root = tk.Tk()

    app = MFRC522SignalViewer(root)

    root.mainloop()



import tkinter as tk

from tkinter import ttk


# --- ISO/IEC 14443A 106 kbps 通信參數 ---

PARAMS = {

    "Reader_to_Card": {

        "Direction": "讀卡機 -> 卡片 (發送數據)",

        "Modulation": "100 % ASK (振幅移位鍵控)",

        "Bit_Encoding": "Modified Miller Encoding (修正後米勒編碼)",

        "Transfer_Speed": "106 kBd",

        "Carrier_Freq": "13.56 MHz (被100%調變)",

        "Example_Data": "數據範例: 1 0 1 1 0 0" # 修正後米勒編碼需要看前一個位元

    },

    "Card_to_Reader": {

        "Direction": "卡片 -> 讀卡機 (接收數據)",

        "Modulation": "Subcarrier Load Modulation (副載波負載調變)",

        "Subcarrier_Freq": "13.56 MHz / 16 (約 847 kHz)",

        "Bit_Encoding": "Manchester Encoding (曼徹斯特編碼)",

        "Transfer_Speed": "106 kBd",

        "Example_Data": "數據範例: 1 0 1 0"

    }

}


class MFRC522SignalViewer:

    def __init__(self, master):

        self.master = master

        master.title("MFRC522 (ISO/IEC 14443A) 106 kbps 信號波形圖")

        

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

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


        ttk.Label(main_frame, text="🌟 ISO/IEC 14443A 106 kbps 調變波形圖 🌟", 

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

        

        # 讀卡機到卡片區塊

        self.create_signal_block(main_frame, "Reader_to_Card", 

                                 "讀卡機到卡片: 100% ASK 修正後米勒編碼波形", "deepskyblue")

        

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


        # 卡片到讀卡機區塊

        self.create_signal_block(main_frame, "Card_to_Reader", 

                                 "卡片到讀卡機: 副載波負載調變 曼徹斯特編碼波形", "orangered")


    def create_signal_block(self, parent_frame, key, title_text, color):

        """建立信號格式的說明區塊和波形圖"""

        

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

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


        ttk.Label(block_frame, text=title_text, font=("Arial", 12, "bold"), 

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

        

        # 參數列表

        params_frame = ttk.Frame(block_frame)

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


        for name, value in PARAMS[key].items():

            ttk.Label(params_frame, text=f"**{name.replace('_', ' ')}:**", 

                      font=("Arial", 10, "bold")).pack(side='left', padx=(10, 2), anchor='w')

            ttk.Label(params_frame, text=value, 

                      font=("Arial", 10)).pack(side='left', padx=(0, 15), anchor='w')

        

        # 波形繪製區

        canvas = tk.Canvas(block_frame, width=650, height=200, bg='#FAFAFA', borderwidth=1, relief="sunken")

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

        

        self.draw_detailed_waveform(canvas, key, color)

        

    

    def draw_detailed_waveform(self, canvas, key, color):

        """繪製詳細的編碼和調變概念波形圖"""

        

        BIT_LENGTH = 100  # 每個位元在Canvas上的像素長度

        HEIGHT_MID = 100  # 中線

        HEIGHT_TOP = 40   # 載波/高電平

        HEIGHT_BOT = 160  # 無載波/低電平

        

        

        if key == "Reader_to_Card":

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

            data_bits = [1, 0, 1, 1, 0, 0] # 範例數據

            

            self.draw_axis_labels(canvas, "數據位元", "編碼信號 (方波)", "100% ASK 波形", 

                                  HEIGHT_TOP, HEIGHT_MID, HEIGHT_BOT)

            

            # --- 繪製修正後米勒編碼邏輯 ---

            current_x = 50

            prev_bit_state = 0 # 假設第一個位元前的狀態

            

            for i, bit in enumerate(data_bits):

                # 繪製數據位元

                self.draw_bit_frame(canvas, current_x, BIT_LENGTH, HEIGHT_TOP - 20, "gray")

                canvas.create_text(current_x + BIT_LENGTH/2, HEIGHT_TOP - 30, text=str(bit), fill="black", font=("Arial", 10, "bold"))


                # 繪製編碼信號 (用方波表示載波的 ON/OFF)

                # Modified Miller 規則:

                # 邏輯 '1': 在位元前半段轉換 (若有載波則關閉,若無則開啟)

                # 邏輯 '0': 

                #   - 若前一個是 '1':在位元末尾轉換。

                #   - 若前一個是 '0':在位元中間不轉換,在位元末尾轉換。

                

                start_level = 0 # 0=Low, 1=High (載波 OFF/ON)

                end_level = 0

                

                if bit == 1:

                    # 邏輯 '1': 在位元中間必須有一次轉換

                    if prev_bit_state == 1: # 若前一個是 H,則 H -> L (前半)

                        self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH/2, start_level, 0, 0, HEIGHT_MID, color) # H

                        self.draw_line_segment(canvas, current_x + BIT_LENGTH/2, current_x + BIT_LENGTH, 0, 0, 0, HEIGHT_MID, color) # L

                        end_level = 0

                    else: # 若前一個是 L,則 L -> H (前半)

                        self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH/2, start_level, 1, 0, HEIGHT_MID, color) # L

                        self.draw_line_segment(canvas, current_x + BIT_LENGTH/2, current_x + BIT_LENGTH, 1, 1, 0, HEIGHT_MID, color) # H

                        end_level = 1

                        

                elif bit == 0:

                    if prev_bit_state == 1:

                        # 邏輯 '0' (前一個是 '1'): 在位元末尾轉換 (H -> L)

                        self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH, start_level, 0, 0, HEIGHT_MID, color) # H (整個週期都 H)

                        # Modified Miller: '0' 繼承前一個電平,除非前一個是 1,則在末尾轉換。

                        # 更準確的簡化規則 (以載波存在為 H):

                        # 1: 在前半週期中間轉換。

                        # 0: 如果前面是 1,整個週期無載波 (L)。

                        # 0: 如果前面是 0,後半週期有載波 (H)。

                        

                        # 重新應用 Simplified Modified Miller 規則 (與 ISO 14443A 一致)

                        if prev_bit_state == 1: # 前一個是 1 (H-L)

                            # 當前是 0: 整個週期無載波 (L)

                            self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH, 0, 0, 0, HEIGHT_MID, color) # L

                            end_level = 0

                        else: # 前一個是 0 (L-L 或 H-L)

                            # 當前是 0: 後半週期有載波 (H)

                            self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH/2, 0, 0, 0, HEIGHT_MID, color) # L (前半)

                            self.draw_line_segment(canvas, current_x + BIT_LENGTH/2, current_x + BIT_LENGTH, 0, 1, 0, HEIGHT_MID, color) # H (後半)

                            end_level = 1

                            

                # 繪製 100% ASK 調變波形 (概念性)

                self.draw_ask_modulation(canvas, current_x, BIT_LENGTH, HEIGHT_BOT, end_level == 1)


                current_x += BIT_LENGTH

                prev_bit_state = end_level


        

        elif key == "Card_to_Reader":

            # 曼徹斯特編碼 (Manchester Encoding)

            data_bits = [1, 0, 1, 0] # 範例數據

            BIT_LENGTH = 150 # 為了有足夠空間繪製

            

            self.draw_axis_labels(canvas, "數據位元", "曼徹斯特編碼", "副載波調變波形", 

                                  HEIGHT_TOP, HEIGHT_MID, HEIGHT_BOT)


            # --- 繪製曼徹斯特編碼邏輯 ---

            current_x = 50

            

            for i, bit in enumerate(data_bits):

                # 繪製數據位元

                self.draw_bit_frame(canvas, current_x, BIT_LENGTH, HEIGHT_TOP - 20, "gray")

                canvas.create_text(current_x + BIT_LENGTH/2, HEIGHT_TOP - 30, text=str(bit), fill="black", font=("Arial", 10, "bold"))

                

                # 曼徹斯特編碼 (低-高轉換=1; 高-低轉換=0)

                if bit == 1:

                    # '1': L -> H 轉換 (副載波 ON)

                    self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH/2, 0, 0, 0, HEIGHT_MID, color) # L (前半)

                    self.draw_line_segment(canvas, current_x + BIT_LENGTH/2, current_x + BIT_LENGTH, 1, 1, 0, HEIGHT_MID, color) # H (後半)

                    

                    # 繪製調變波形 (副載波 ON)

                    self.draw_subcarrier_modulation(canvas, current_x, BIT_LENGTH, HEIGHT_BOT, True)

                    

                else: # bit == 0

                    # '0': H -> L 轉換 (副載波 OFF)

                    self.draw_line_segment(canvas, current_x, current_x + BIT_LENGTH/2, 1, 1, 0, HEIGHT_MID, color) # H (前半)

                    self.draw_line_segment(canvas, current_x + BIT_LENGTH/2, current_x + BIT_LENGTH, 0, 0, 0, HEIGHT_MID, color) # L (後半)


                    # 繪製調變波形 (副載波 ON)

                    self.draw_subcarrier_modulation(canvas, current_x, BIT_LENGTH, HEIGHT_BOT, True)

                    

                current_x += BIT_LENGTH


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

    

    def draw_axis_labels(self, canvas, data_label, encoded_label, modulated_label, top_y, mid_y, bot_y):

        """繪製波形軸的標籤"""

        canvas.create_text(20, top_y - 30, text=data_label, anchor='w', font=("Arial", 10, "italic"))

        canvas.create_text(20, mid_y + 10, text=encoded_label, anchor='w', font=("Arial", 10, "italic"))

        canvas.create_text(20, bot_y + 10, text=modulated_label, anchor='w', font=("Arial", 10, "italic"))

        

        canvas.create_line(50, top_y, 650, top_y, fill="lightgray")

        canvas.create_line(50, mid_y, 650, mid_y, fill="lightgray")

        canvas.create_line(50, bot_y, 650, bot_y, fill="lightgray")


    def draw_bit_frame(self, canvas, x_start, bit_len, y, color):

        """繪製單個位元的時序框"""

        canvas.create_line(x_start, y - 5, x_start, y + 5, fill=color, dash=(2, 2))

        canvas.create_line(x_start + bit_len, y - 5, x_start + bit_len, y + 5, fill=color, dash=(2, 2))


    def get_y_coord(self, level, y_mid):

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

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

        

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

        """繪製編碼信號的線段"""

        y_start = self.get_y_coord(start_level, y_mid)

        y_end = self.get_y_coord(end_level, y_mid)

        y_prev = self.get_y_coord(prev_level, y_mid)

        

        # 繪製電平線

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

        

        # 繪製轉換線

        if y_start != y_prev:

            canvas.create_line(x_start, y_prev, x_start, y_start, fill=color, width=2)


    def draw_ask_modulation(self, canvas, x_start, bit_len, y_center, is_carrier_on):

        """概念性繪製 100% ASK 波形 (載波 ON/OFF)"""

        wave_height = 20

        

        if is_carrier_on:

            # 有載波: 簡化為方波

            canvas.create_rectangle(x_start, y_center - wave_height, x_start + bit_len, y_center + wave_height, 

                                    outline="#0099cc", fill="#ccffff")

            canvas.create_text(x_start + bit_len/2, y_center, text="載波 ON (100% ASK)", fill="#006699")

        else:

            # 無載波

            canvas.create_line(x_start, y_center, x_start + bit_len, y_center, fill="red", width=2)

            canvas.create_text(x_start + bit_len/2, y_center + 15, text="載波 OFF (0% ASK)", fill="red")


    def draw_subcarrier_modulation(self, canvas, x_start, bit_len, y_center, is_subcarrier_on):

        """概念性繪製負載調變波形 (副載波調變載波場)"""

        if is_subcarrier_on:

            # 副載波 ON: 簡化為有紋理的方波

            canvas.create_rectangle(x_start, y_center - 20, x_start + bit_len, y_center + 20, 

                                    outline="#cc6600", fill="#ffddcc", stipple="gray25")

            canvas.create_text(x_start + bit_len/2, y_center, text="負載調變 (副載波 ON)", fill="#993300")

        else:

            # 副載波 OFF

            canvas.create_line(x_start, y_center, x_start + bit_len, y_center, fill="green", width=2)

            canvas.create_text(x_start + bit_len/2, y_center + 15, text="無負載調變", fill="green")


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

if __name__ == "__main__":

    root = tk.Tk()

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