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()




沒有留言:
張貼留言