Files
DTU-HMI/docs/绘图/SPI_Waveform_CPHA0.py

198 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import xml.etree.ElementTree as ET
def make_mxfile():
# 基础参数
y_cs_high, y_cs_low = 80, 110
y_sclk_high, y_sclk_low = 180, 210
y_mosi_high, y_mosi_low = 280, 310
y_miso_high, y_miso_low = 380, 410
# 8个bit周期每个100px从x=100开始到x=900结束
rise_edges = [150, 250, 350, 450, 550, 650, 750, 850]
fall_edges = [190, 290, 390, 490, 590, 690, 790, 890]
# MOSI: 0x5A = 0b01011010, MSB first
mosi_bits = [0, 1, 0, 1, 1, 0, 1, 0]
# MISO: 0xA5 = 0b10100101, MSB first
miso_bits = [1, 0, 1, 0, 0, 1, 0, 1]
lines = []
lines.append('<?xml version="1.0" encoding="UTF-8"?>')
lines.append('<mxfile host="app.diagrams.net" modified="2024-05-25T00:00:00.000Z" agent="AI" version="21.0.0" type="device">')
lines.append(' <diagram name="SPI Waveform" id="spi_waveform">')
lines.append(' <mxGraphModel dx="1000" dy="600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1000" pageHeight="600" math="0" shadow="0">')
lines.append(' <root>')
lines.append(' <mxCell id="0"/>')
lines.append(' <mxCell id="1" parent="0"/>')
# 背景网格
lines.append(' <mxCell id="grid" value="" style="points=[];gridColor=#e0e0e0;gridSize=20;spacingTop=20;spacingLeft=20;spacingBottom=20;spacingRight=20;html=1;" vertex="1" parent="1">')
lines.append(' <mxGeometry x="0" y="0" width="1000" height="600" as="geometry"/>')
lines.append(' </mxCell>')
# 标题
lines.append(' <mxCell id="title" value="SPI 全双工传输 (模式 0: CPOL=0, CPHA=0)" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" vertex="1" parent="1">')
lines.append(' <mxGeometry x="300" y="20" width="400" height="30" as="geometry"/>')
lines.append(' </mxCell>')
# MSB / LSB
lines.append(' <mxCell id="msb" value="MSB" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontColor=#666666;fontStyle=1;" vertex="1" parent="1">')
lines.append(' <mxGeometry x="130" y="60" width="40" height="20" as="geometry"/>')
lines.append(' </mxCell>')
lines.append(' <mxCell id="lsb" value="LSB" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontColor=#666666;fontStyle=1;" vertex="1" parent="1">')
lines.append(' <mxGeometry x="880" y="60" width="40" height="20" as="geometry"/>')
lines.append(' </mxCell>')
# 信号标签
for label, y, eid in [("CS", 85, "label_cs"), ("SCLK", 185, "label_sclk"),
("MOSI", 275, "label_mosi"), ("MISO", 365, "label_miso")]:
lines.append(f' <mxCell id="{eid}" value="{label}" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1;" vertex="1" parent="1">')
lines.append(f' <mxGeometry x="20" y="{y}" width="50" height="20" as="geometry"/>')
lines.append(' </mxCell>')
# 垂直参考虚线(放在每个上升沿采样点)
for i, x in enumerate(rise_edges):
lines.append(f' <mxCell id="vl_{x}" value="" style="endArrow=none;html=1;strokeWidth=1;strokeColor=#CCCCCC;dashed=1;" edge="1" parent="1">')
lines.append(' <mxGeometry width="50" height="50" relative="1" as="geometry">')
lines.append(f' <mxPoint x="{x}" y="180" as="sourcePoint"/>')
lines.append(f' <mxPoint x="{x}" y="420" as="targetPoint"/>')
lines.append(' </mxGeometry>')
lines.append(' </mxCell>')
# CS 波形
cs_points = [
(80, y_cs_high), (90, y_cs_high), (90, y_cs_low), (910, y_cs_low),
(910, y_cs_high), (920, y_cs_high)
]
lines.append(' <mxCell id="cs" value="" style="edgeStyle=none;html=1;strokeWidth=2;strokeColor=#FF5722;rounded=0;endArrow=none;" edge="1" parent="1">')
lines.append(' <mxGeometry relative="0" as="geometry">')
lines.append(f' <mxPoint x="{cs_points[0][0]}" y="{cs_points[0][1]}" as="sourcePoint"/>')
lines.append(f' <mxPoint x="{cs_points[-1][0]}" y="{cs_points[-1][1]}" as="targetPoint"/>')
lines.append(' <Array as="points">')
for x, y in cs_points[1:-1]:
lines.append(f' <mxPoint x="{x}" y="{y}"/>')
lines.append(' </Array>')
lines.append(' </mxGeometry>')
lines.append(' </mxCell>')
# SCLK 波形
sclk_pts = [(80, y_sclk_low), (100, y_sclk_low)]
for rise, fall in zip(rise_edges, fall_edges):
sclk_pts.extend([
(rise, y_sclk_low),
(rise, y_sclk_high),
(fall, y_sclk_high),
(fall, y_sclk_low),
])
sclk_pts.append((920, y_sclk_low))
lines.append(' <mxCell id="sclk" value="" style="edgeStyle=none;html=1;strokeWidth=2;strokeColor=#2196F3;rounded=0;endArrow=none;" edge="1" parent="1">')
lines.append(' <mxGeometry relative="0" as="geometry">')
lines.append(f' <mxPoint x="{sclk_pts[0][0]}" y="{sclk_pts[0][1]}" as="sourcePoint"/>')
lines.append(f' <mxPoint x="{sclk_pts[-1][0]}" y="{sclk_pts[-1][1]}" as="targetPoint"/>')
lines.append(' <Array as="points">')
for x, y in sclk_pts[1:-1]:
lines.append(f' <mxPoint x="{x}" y="{y}"/>')
lines.append(' </Array>')
lines.append(' </mxGeometry>')
lines.append(' </mxCell>')
# MOSI 波形
mosi_start_y = y_mosi_high if mosi_bits[0] else y_mosi_low
mosi_pts = [(80, mosi_start_y), (100, mosi_start_y)]
for i, bit in enumerate(mosi_bits):
y_level = y_mosi_high if bit else y_mosi_low
end_x = fall_edges[i] if i < len(fall_edges) else 900
mosi_pts.append((end_x, y_level))
if i + 1 < len(mosi_bits):
y_next = y_mosi_high if mosi_bits[i+1] else y_mosi_low
if y_next != y_level:
mosi_pts.append((end_x, y_next))
mosi_pts.append((920, mosi_pts[-1][1]))
lines.append(' <mxCell id="mosi" value="" style="edgeStyle=none;html=1;strokeWidth=2;strokeColor=#4CAF50;rounded=0;endArrow=none;" edge="1" parent="1">')
lines.append(' <mxGeometry relative="0" as="geometry">')
lines.append(f' <mxPoint x="{mosi_pts[0][0]}" y="{mosi_pts[0][1]}" as="sourcePoint"/>')
lines.append(f' <mxPoint x="{mosi_pts[-1][0]}" y="{mosi_pts[-1][1]}" as="targetPoint"/>')
lines.append(' <Array as="points">')
for x, y in mosi_pts[1:-1]:
lines.append(f' <mxPoint x="{x}" y="{y}"/>')
lines.append(' </Array>')
lines.append(' </mxGeometry>')
lines.append(' </mxCell>')
# MISO 波形 — 修复sourcePoint 与第一个中间点同 y避免斜线
miso_start_y = y_miso_high if miso_bits[0] else y_miso_low
miso_pts = [(80, miso_start_y), (100, miso_start_y)]
for i, bit in enumerate(miso_bits):
y_level = y_miso_high if bit else y_miso_low
end_x = fall_edges[i] if i < len(fall_edges) else 900
miso_pts.append((end_x, y_level))
if i + 1 < len(miso_bits):
y_next = y_miso_high if miso_bits[i+1] else y_miso_low
if y_next != y_level:
miso_pts.append((end_x, y_next))
miso_pts.append((920, miso_pts[-1][1]))
lines.append(' <mxCell id="miso" value="" style="edgeStyle=none;html=1;strokeWidth=2;strokeColor=#9C27B0;rounded=0;endArrow=none;" edge="1" parent="1">')
lines.append(' <mxGeometry relative="0" as="geometry">')
lines.append(f' <mxPoint x="{miso_pts[0][0]}" y="{miso_pts[0][1]}" as="sourcePoint"/>')
lines.append(f' <mxPoint x="{miso_pts[-1][0]}" y="{miso_pts[-1][1]}" as="targetPoint"/>')
lines.append(' <Array as="points">')
for x, y in miso_pts[1:-1]:
lines.append(f' <mxPoint x="{x}" y="{y}"/>')
lines.append(' </Array>')
lines.append(' </mxGeometry>')
lines.append(' </mxCell>')
# MOSI 数据位标签
mosi_centers = [145, 240, 340, 440, 540, 640, 740, 840]
for i, (bit, cx) in enumerate(zip(mosi_bits, mosi_centers)):
lines.append(f' <mxCell id="m{i}" value="{bit}" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontColor=#4CAF50;" vertex="1" parent="1">')
lines.append(f' <mxGeometry x="{cx}" y="255" width="20" height="20" as="geometry"/>')
lines.append(' </mxCell>')
# MISO 数据位标签
miso_centers = [145, 240, 340, 440, 540, 640, 740, 840]
for i, (bit, cx) in enumerate(zip(miso_bits, miso_centers)):
lines.append(f' <mxCell id="s{i}" value="{bit}" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontColor=#9C27B0;" vertex="1" parent="1">')
lines.append(f' <mxGeometry x="{cx}" y="355" width="20" height="20" as="geometry"/>')
lines.append(' </mxCell>')
# 数据包标注
lines.append(' <mxCell id="hex_mosi" value="0x5A" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1;fontColor=#4CAF50;" vertex="1" parent="1">')
lines.append(' <mxGeometry x="500" y="235" width="80" height="20" as="geometry"/>')
lines.append(' </mxCell>')
lines.append(' <mxCell id="hex_miso" value="0xA5" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1;fontColor=#9C27B0;" vertex="1" parent="1">')
lines.append(' <mxGeometry x="500" y="425" width="80" height="20" as="geometry"/>')
lines.append(' </mxCell>')
lines.append(' </root>')
lines.append(' </mxGraphModel>')
lines.append(' </diagram>')
lines.append('</mxfile>')
return "\n".join(lines)
xml_content = make_mxfile()
output_path = "SPI_Waveform_CPHA0_Corrected.drawio"
with open(output_path, "w", encoding="utf-8") as f:
f.write(xml_content)
# 验证 MISO 起始点
import re
with open(output_path, "r", encoding="utf-8") as f:
content = f.read()
match = re.search(r'id="miso".*?<Array as="points">(.*?)</Array>', content, re.DOTALL)
if match:
pts = re.findall(r'<mxPoint x="(\d+)" y="(\d+)"/>', match.group(1))
print("MISO 点:")
for x, y in pts[:4]:
print(f" ({x}, {y})")
src = re.search(r'id="miso".*?<mxPoint x="(\d+)" y="(\d+)" as="sourcePoint"/>', content)
if src:
print(f"sourcePoint: ({src.group(1)}, {src.group(2)})")
print("\n文件已保存:", output_path)