# Easyeda Draw Wiring

> Wire routing, net labeling, and connection management for EasyEDA Pro schematics. Invoke when drawing wires, adding net labels, creating power/ground symbols, or managing signal connections.

- Skill: `kukucaicndy/easyeda-draw-wiring` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add kukucaicndy/easyeda-draw-wiring`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kukucaicndy/easyeda-draw-wiring/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kukucaicndy (https://skillmd.com/u/kukucaicndy)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kukucaicndy/easyeda-draw-wiring

---


# 连线与网络管理

导线绘制、网络标签、总线、电源/地符号的完整指南。

---

## 核心原则

> **多使用网络标号，避免复杂连线。** 网络标号可以减少导线交叉，提高可读性。

---

## 0. 关键规则（必读）

### 0.1 导线必须设置网络名

> **⚠️ 导线无网络名 = 电气连接不建立**
>
> 在 EasyEDA 中，导线的 `net` 属性为空时，该导线不参与电气网络构建。
> 这会导致：网络表导出错误、PCB Layout 无法建立连接关系、DRC 检测不到开路/短路。
>
> **正确做法**（参考 POWER 页风格）：
> - 每创建一条导线必须指定网络名
> - 芯片引脚到网络标签的导线：网络名 = 标签的网络名
> - 同网络名的标签 + 导线 = 完整的电气连接
> - 模块内部导线（开关→二极管）：至少指定行/列网络名

### 0.2 防止跨网络自动合并（API 坑）

> **⚠️ EasyEDA `sch_PrimitiveWire.create()` 的 net 参数陷阱：**
>
> 当 `net` 参数为 `undefined`（未指定）时，API 会**自动从触碰的图元继承网络名**：
> - 导线触碰一个已有网络的导线 → 新导线自动继承该网络名
> - 导线触碰多个不同网络的图元 → 创建失败
>
> 这会导致**跨网络合并**：AI 画 ROW0 导线时，如果不指定 net，而导线端点碰巧触碰到 ROW1 的导线，
> 新导线会静默变成 ROW1，造成电气短路。
>
> **防护措施：**
> 1. **CLI 已修复**：`draw_cli.py wire` 不指定 net 时传空字符串 `""` 而非 `undefined`，阻止自动继承
> 2. **安全模式**：`wire --safe` 先检查坐标是否触碰不同网络导线，冲突时中止创建
> 3. **批量安全**：`wire-batch` 逐条调用安全模式，适合大规模走线
> 4. **冲突检测**：`check-wire-conflicts` 检测已存在的导线网络冲突

### 0.3 标签唯一性：同一坐标不能有重复标签

> **⚠️ 禁止在同一坐标放置多个标签**
>
> 同一网络只需一个标签。重复放置会导致视觉叠加、网络冲突、DRC 异常。
>
> 放置标签前先检查：
> ```bash
> ./scripts/draw_cli.py check-duplicates
> ```

### 0.3 NC 未用引脚标记

> **⚠️ 不使用 IC 引脚必须标记 NC**
>
> NC 标记告诉 DRC "此引脚有意不连接"。**必须使用 CLI 的原生 NC API**（禁止放置文本 "NC"）：
>
> ```bash
> # ✅ 正确：原生 NC 标记（引脚上显示标准叉号，DRC 正确识别）
> ./scripts/draw_cli.py mark-nc U1 14
> ./scripts/draw_cli.py mark-nc U1 14,16
> ```
>
> **原理**：`mark-nc` 调用 `sch_PrimitiveComponent.setState_NoConnected(true)`，EasyEDA 在引脚上显示标准 NC 叉号，DRC 将其识别为"有意不连接"。

### 0.4 电源/地优先级规则

> **参考 POWER 页风格**: 电源/地使用 NetFlag (Power/Ground)，信号仅用延伸导线（导线已含网络名）。
>
> - VCC/VDD/VBAT → `createNetFlag("Power", ...)`
> - GND/AGND/DGND → `createNetFlag("Ground", ...)`
> - 信号 (I2C/SPI/UART/GPIO) → 仅 `wire` 延伸，不附加任何标签/文本
>
> **⚠️ 不使用 NetPort/文本标注 的原因**：导线本身已承载网络名，额外的符号或文本只会增加 BBox 重叠风险。

---

## 1. 导线绘制

### 基本绘制

```javascript
await eda.sch_PrimitiveWire.create(
  [x1, y1, x2, y2],    // 线段坐标组
  "NET_NAME",           // 网络名（必须显式指定！）
  null,                 // 颜色
  null,                 // 线宽
  null                  // 线型
);
```

### 多段导线

```javascript
// 折线: 从 (100,100) → (150,100) → (150,150)
await eda.sch_PrimitiveWire.create(
  [100, 100, 150, 100, 150, 150],
  "SIGNAL_NET",
  null, null, null
);
```

### 多段独立导线

```javascript
// 两条独立线段
await eda.sch_PrimitiveWire.create(
  [[100, 100, 150, 100], [200, 200, 250, 200]],
  "SIGNAL_NET",
  null, null, null
);
```

**⚠️ 注意**: 如果多段线彼此无任何连接，创建会失败。

### 修改已有导线的网络名

```javascript
// 用 toAsync() 修改已有导线的网络名
const wires = await eda.sch_PrimitiveWire.get([wireId]);
const aw = wires[0].toAsync();
aw.setState_Net("NEW_NET_NAME");
aw.done();
```

---

## 2. 网络标签 (Net Flag) — 电源/地专用

网络标签用于标识电源和地，是最常用的连接方式。

### 电源标签

```javascript
await eda.sch_PrimitiveComponent.createNetFlag(
  "Power",              // 类型: Power | Ground | AnalogGround | ProtectGround
  "VCC_3V3",            // 网络名
  x, y,                 // 位置
  0,                    // 旋转角度
  false                 // 镜像
);
```

### 地标签

```javascript
await eda.sch_PrimitiveComponent.createNetFlag("Ground", "GND", x, y, 0, false);
```

### 电源命名规范

| 网络名 | 用途 |
|--------|------|
| `VCC` | 通用电源 |
| `VCC_3V3` | 3.3V 电源 |
| `VCC_5V` | 5V 电源 |
| `VCC_1V8` | 1.8V 电源 |
| `VBAT` | 电池电源 |
| `VBUS` | USB 总线电源 |
| `VDD` | 数字电源 |
| `VSS` | 数字地 |
| `GND` | 通用接地 |
| `AGND` | 模拟地 |
| `DGND` | 数字地 |
| `PGND` | 电源地 |

---

## 3. 信号标注 — 延伸导线-only

> **⚠️ NetPort 已不推荐，文本标注也已不推荐。导线本身承载网络名，无需额外符号或文本。**

**策略 A — 信号引脚**：仅延伸导线，导线网络名即信号名，不附加任何额外标签/文本。
```
wire "pinX,pinY,pinX ± distance,pinY" SIGNAL_NAME
```

**策略 B — 电源/地引脚**：延伸导线 + NetFlag。**NetFlag 坐标必须 = 导线终点**（否则电气不连接）。
```
wire "pinX,pinY,endX,endY" VCC   # 先延伸导线
netflag Power VCC endX endY      # 再贴 NetFlag（坐标=导线终点）
```

**标签摆放规则**：
- **左侧引脚**：文字左对齐，靠近导线末端，但**远离 PIN 脚编号**
- **右侧引脚**：文字右对齐，同上
- **上侧引脚**：文字上对齐，同上
- **下侧引脚**：文字下对齐，同上
- 若文字覆盖编号：旋转 180° 或缩短导线长度

**策略 C — 同侧同名电源/地合并**：连续同名引脚，竖线段短接 → 一根水平引出 → 共 1 个 NetFlag。
```
wire "pin1X,pin1Y,pin1X,pin2Y" GND         # 竖线短接连续同名引脚
wire "pin1X,pin2Y,pin1X-100,pin2Y" GND      # 水平引出
netflag Ground GND pin1X-100 pin2Y           # NetFlag 在终点
```

若已有页面使用了 NetPort，可一键转换：
```bash
./scripts/draw_cli.py replace-netports

### 信号命名规范

| 网络名 | 用途 |
|--------|------|
| `I2C_SDA` / `I2C_SCL` | I2C 总线 |
| `SPI_MOSI` / `SPI_MISO` / `SPI_SCK` / `SPI_CS` | SPI 总线 |
| `UART_TX` / `UART_RX` | UART 串口 |
| `ROW0` / `COL0` | 键盘矩阵行/列 |
| `ENC_A` / `ENC_B` | 编码器 |
| `RESET` / `RESET_N` | 复位信号 |
| `STATUS_BTN` | 状态按钮 |
| `D0` / `D1` | 调试/通用 IO |
| `RAW` | 原始电源输入 |

---

## 4. 总线 (Bus)

多位信号线使用总线符号减少混乱。

```javascript
// 创建总线
await eda.sch_PrimitiveBus.create(
  [x1, y1, x2, y2],     // 总线路径
  "DATA[7:0]",          // 总线名
  null, null, null
);
```

**总线命名约定**:
- `DATA[7:0]` — 8 位数据总线
- `ADDR[15:0]` — 16 位地址总线
- `GPIO[0:3]` — 4 个 GPIO 引脚

---

## 5. 连接策略：导线 vs 网络标签

### 5.0 最高优先级规则（MUST FOLLOW）

> **⚠️ 模块到模块也使用网络标签，禁止连接导线！**
>
> 无论模块到模块还是模块到主控，都必须通过网络标签（NetFlag/NetPort）连接，禁止用导线直接拉过去。
> 如果一条导线的两端分别在两个不同功能模块的器件上 → 必须改用网络标签。

### 5.1 三条核心原则

| 原则 | 说明 | 示例 |
|------|------|------|
| **① 模块内部用导线** | 同一功能电路内的器件之间用导线直连，体现电路拓扑的完整性 | 按键 SW1 → 二极管 D1 → 行线 |
| **② 芯片周边用网络标签** | 主控/IC 的引脚引出用网络标签，不直接拉线到远端器件 | U1.D7 → NetPort(ROW0) |
| **③ 复杂走线优先调布局** | 当连线出现绕路或交叉时，先调整器件位置和方向简化走线，而非硬拉线 | 二极管旋转 270° 使 A/K 上下排列 |

### 5.2 判断流程

```
两个引脚需要连接时：

  ┌─ 同一功能模块内？─┐
  │                    │
  YES                  NO
  │                    │
  ▼                    ▼
 用导线          芯片引脚引出？
  │                    │
  │               YES  │  NO
  │                │    │   │
  │                ▼    │   ▼
  │          用网络标签   │  导线会交叉/绕路？
  │          + 短导线     │   │
  │                    │  YES  NO
  │                    │   │    │
  │                    │   ▼    ▼
  │                    │  调整器件  直接导线
  │                    │  位置/方向
  │                    │  简化走线
  └────────────────────┘
```

### 5.3 模块内部用导线

同一功能模块内的连接必须用导线，体现电路拓扑完整性：

```javascript
// 按键 pin2 → 二极管 A（L 形 2 段导线）
await eda.sch_PrimitiveWire.create([220, 210, 220, 300, 200, 300]);

// 行线：连接多个二极管 K 端（必须指定网络名）
await eda.sch_PrimitiveWire.create([200, 340, 600, 340], 'ROW0');

// 列线：连接同列开关 pin3，延伸到标签位置
await eda.sch_PrimitiveWire.create([180, 170, 180, 390], 'COL0');
```

**为什么不用网络标签？** 模块内部的连接关系是电路原理的核心，用导线直观展示拓扑结构，便于审阅和理解。满屏网络标签会让模块内部逻辑支离破碎。

### 5.4 芯片周边用网络标签

主控/IC 引脚的引出用**延伸导线**（导线网络名即信号名），见 [Section 3](#3-信号标注--延伸导线-only) 的三种策略：

- **信号**：`wire "pinX,pinY,pinX±100,pinY" NET_NAME`
- **电源/地**：`wire` + `netflag`，NetFlag 坐标 = 导线终点
- **连续同名电源/地**：竖线短接 → 引出 → 共 1 个 NetFlag

### 5.5 连线时动态调整器件布局

> **核心思想：连线不是被动适应器件位置，而是主动调整器件位置和方向来简化连线。**
>
> 在规划连线时，如果发现两个待连引脚不在同一水平线或垂直线上，**先移动器件使引脚对齐，再画直线导线**，而不是画多段折线去凑。

**Step 0: 连线前先对齐引脚（最重要）**

在画导线之前，先检查两个待连引脚的坐标。如果不在同一行/列，**移动器件使引脚对齐**：

```javascript
import utils from './scripts/draw-utils.js';

// 示例：开关 pin2(220, 210) 需要连接到二极管 A 端
// 二极管当前在 (200, 320)，A 端在 (200, 300)
// pin2 x=220, D.A x=200 → 水平偏移 20

// ❌ 错误：硬拉 L 形线
await utils.addWire([220, 210, 220, 300, 200, 300]);

// ✅ 正确：先把二极管移到 x=220 对齐，再画直线
const comps = await eda.sch_PrimitiveComponent.get(["二极管ID"]);
const ac = comps[0].toAsync();
ac.setState_X(220);  // 移动到与 pin2 对齐
ac.done();
// 现在 D.A 在 (220, 300)，pin2 在 (220, 210)
await utils.addWire([220, 210, 220, 300], 'MATRIX_NET');  // 一段垂直直线
```

**对齐策略表：**

| 连接方向 | 对齐方式 | 移动哪个器件 |
|---------|---------|------------|
| 垂直连线（上下） | X 坐标对齐 | 移动器件使 pinX 相同 |
| 水平连线（左右） | Y 坐标对齐 | 移动器件使 pinY 相同 |
| 开关→二极管 | X 对齐到开关 pin | 移动二极管 |
| 二极管→行线 | X 对齐到二极管 K | 行线是导线，自动经过 |
| 编码器→标签 | 标签移到引脚延长线 | 移动标签 |

**Step 1: 调整器件方向**

旋转器件使引脚朝向合理方向，减少折线段数：

```javascript
// 二极管默认水平放置：A 在左 K 在右
// 旋转 270° 后：A 在上 K 在下，正好对接开关(上)和行线(下)
const comps = await eda.sch_PrimitiveComponent.get(["二极管ID"]);
const ac = comps[0].toAsync();
ac.setState_Rotation(270);
ac.done();
```

```
❌ 二极管水平放置：A(左) K(右)
   开关在上，行线在下 → 需要 3 段折线

✅ 二极管旋转 270°：A(上) K(下)
   开关→A 直线，K→行线直线 → 2 段直线
```

**Step 2: 调整器件间距**

确保器件之间有足够间距，导线不会与其他器件引脚重叠：

```javascript
// 检查间距：开关 pin y=210，二极管 A y=300 → 间距 90
// 如果间距 < 60，导线太短不美观，移动器件拉开距离
```

**Step 3: 仍然复杂则改用网络标签**

如果调整布局后仍然需要 3 段以上折线，或会导致与其他导线交叉，改用网络标签。

### 5.6 移动器件的 API

```javascript
// 移动器件到新坐标
const comps = await eda.sch_PrimitiveComponent.get([primitiveId]);
const ac = comps[0].toAsync();
ac.setState_X(newX);
ac.setState_Y(newY);
ac.done();

// 旋转器件
const ac2 = comps[0].toAsync();
ac2.setState_Rotation(90);  // 0, 90, 180, 270
ac2.done();

// 镜像器件
const ac3 = comps[0].toAsync();
ac3.setState_Mirror(true);
ac3.done();
```

> **⚠️ 注意**: 移动器件后引脚坐标会变化。如果之前已经画了导线，需要同步更新导线。建议先调整好所有器件位置，再统一画导线。

### 5.7 混合使用示例

```
按键 ──导线── 二极管 ──导线(行线)── 文本标注 ──┐
                                               │
主控引脚 ──导线── 文本标注 ────────────────────┘
```

模块内部（开关→二极管→行线）用导线，模块边界（行线末端→主控）用网络标签。

---

## 6. 电源连接

### 电源树结构

```
VCC_BAT ──[保险丝]── VCC_5V ──[LDO]── VCC_3V3 ──[滤波]── MCU_VCC
                                      │
                                      ├── OLED_VCC
                                      ├── SENSOR_VCC
                                      └── LED_VCC
```

### 去耦电容放置

```javascript
// 在 IC 电源引脚附近放置去耦电容
await eda.sch_PrimitiveComponent.create(
  { libraryUuid: "库UUID", uuid: "电容UUID" },
  icX + 20, icY, "", 0, false, true, true
);

// 连接电容到电源和地（必须指定网络名）
await eda.sch_PrimitiveWire.create([icX + 20, icY, icX + 20, icY - 20], "VCC_3V3", null, null, null);
await eda.sch_PrimitiveComponent.createNetFlag("Power", "VCC_3V3", icX + 20, icY - 20, 0, false);
await eda.sch_PrimitiveWire.create([icX + 20, icY + 10, icX + 20, icY + 30], "GND", null, null, null);
await eda.sch_PrimitiveComponent.createNetFlag("Ground", "GND", icX + 20, icY + 30, 0, false);
```

---

## 7. 导线出口点规范

从符号引脚直线前进至少一个网格点后再改变方向：

```
正确: 引脚 ───┬─── 网络标签
            │
            └─── 导线

错误: 引脚 ───┐
            └───┐
                └─── 网络标签
```

---

## 8. 避免四向交叉

**优先使用 T 形连接而不是四向交叉。**

```
正确 (T 形):
────┬────
    │
    └────

错误 (四向交叉):
────┼────
    │
────┘
```

如果必须交叉，确保交叉点没有连接点（表示导线跨越而不连接）。

---

## 9. 网络名继承规则

导线创建时的网络名规则：

1. **没有坐标落在任何图元上** → 默认为空网络
2. **有一个坐标点在某个网络的图元上** → 跟随该图元的网络
3. **有多个坐标点在多个不同网络的图元上** → 创建失败

**指定网络名时的规则**:
1. **有一个或多个坐标点在其他网络的图元上，且其他图元未显式指定网络** → 其他图元跟随指定的网络
2. **其他图元指定了网络** → 创建失败

---

## 10. 芯片外围信号引出规范

> 见 [Section 3](#3-信号标注--延伸导线-only) 的策略 A/B/C。

---

## 11. 导线高级操作 (CLI)

### 11.1 查看导线详细信息

```bash
./scripts/draw_cli.py get-wire <primitiveId>
```

返回：网络名、坐标组、线宽、线型、颜色。

### 11.2 修改已有导线（异步模式）

导线放置后如需调整网络名、坐标、线宽/线型/颜色等，用 `modify-wire`：

```bash
# 修改网络名
./scripts/draw_cli.py modify-wire <id> --net "NEW_NET"

# 修改坐标（移动导线）
./scripts/draw_cli.py modify-wire <id> --line "100,200,150,200"

# 修改线宽
./scripts/draw_cli.py modify-wire <id> --width 3

# 修改线型（实线/短划线/点线/点划线）
./scripts/draw_cli.py modify-wire <id> --dashed
./scripts/draw_cli.py modify-wire <id> --solid

# 修改颜色
./scripts/draw_cli.py modify-wire <id> --color "#ff0000"
```

### 11.3 创建时指定线型/颜色/线宽

`wire` 命令同样支持这些选项：

```bash
# 虚线导线
./scripts/draw_cli.py wire "100,100,200,100" NET --dashed

# 红色粗线
./scripts/draw_cli.py wire "100,100,200,100" NET --color "#ff0000" --width 5
```

线型取值（对应 `ESCH_PrimitiveLineType` 枚举）：
| 选项 | 值 | 说明 |
|------|-----|------|
| (默认) | 0 | 实线 (SOLID) |
| `--dashed` | 1 | 短划线 (DASHED) |
| `--dotted` | 2 | 点线 (DOTTED) |
| `--dot-dashed` | 3 | 点划线 (DOT_DASHED) |

---

## 12. 总线 (Bus) — 多位信号线分组

总线用于标识一组相关的多位信号，减少原理图混乱。总线本身不具有电气连接属性，仅作视觉标识。

### 12.1 创建总线

```bash
./scripts/draw_cli.py bus "DATA[7:0]" "100,200,300,200,300,500"
```

### 12.2 总线命名约定

- `DATA[7:0]` — 8 位数据总线
- `ADDR[15:0]` — 16 位地址总线
- `GPIO[0:3]` — 4 个 GPIO 引脚
- `ROW[0:3]` — 4 条行信号
- `COL[0:15]` — 16 条列信号

### 12.3 总线接入标识 (BUSENTRY)

总线到导线之间必须通过 BUSENTRY（总线接入标识）连接，它定义了哪些导线信号属于总线的哪些位。

> BUSENTRY 通过 EasyEDA 画布界面手动添加更方便，目前 API 不支持直接创建 BUSENTRY。

### 12.4 查询和删除总线

```bash
# 列出所有总线
./scripts/draw_cli.py list-buses

# 删除指定总线
./scripts/draw_cli.py delete-buses id1 id2
```

---

## 13. 多边形/折线 (Polygon) — 装饰区域标识

多边形用于绘制功能区域边框、信号分组框等视觉装饰。**多边形没有电气属性（无 net）**，仅用于视觉标识。

### 13.1 创建多边形

```bash
# 实线框（无填充）
./scripts/draw_cli.py polygon "100,100,300,100,300,300,100,300"

# 虚线框 + 浅色填充
./scripts/draw_cli.py polygon "100,100,300,100,300,300,100,300" \
  --dashed --fill "#f0f0f0"

# 无填充
./scripts/draw_cli.py polygon "100,100,300,100,300,300,100,300" --fill none
```

**⚠️ 注意：** 多边形会自动闭合首尾端点，坐标不需要重复起始点。

### 13.2 查询和删除

```bash
./scripts/draw_cli.py list-polygons
./scripts/draw_cli.py delete-polygons id1 id2
```

---

## 14. 常见错误

| 错误 | 原因 | 解决方案 |
|------|------|----------|
| `创建失败` | 多段线彼此无连接 | 确保所有线段有共同连接点 |
| `创建失败` | 多个不同网络的图元 | 使用网络标签替代直接连线 |
| 导线交叉混乱 | 未使用网络名连接 | 长距离连接用延伸导线+网络名 |
| 网络名冲突 | 同一网络名用于不同信号 | 检查网络名唯一性 |
| 电源未连接 | 忘记放置 NetFlag | 检查所有电源引脚有对应 NetFlag |
| **导线无网络名** | 创建导线时 net 参数为空 | 每创建一条导线必须指定网络名 |
| **标签重复** | 同一坐标放置两个相同标签 | 使用 `check-duplicates` 检测并删除 |
| **未用引脚无 NC** | IC 未用引脚没有标记 | 使用 `mark-nc` CLI 标记 |

