原理图/PCB 已在 EasyEDA 里做到 12 页跨页 0 漏接,固件刚完成骨架包 A1。 这次是把已有的一切一次性纳入版本控制,没有改动任何设计内容。 纳入: - 设计与需求文档、PROGRESS.md、小米8 参考原理图 PDF 与追脚脚本 - .claude/ 下的 EasyEDA 桥接工具链与几何/网表缓存(eda-parts.json、 pcb-parts.json、pcb-pads.json、p2-ch1.json 等,是重画各页的唯一事实来源) - 117 张验证截图(本项目所有方向问题都是靠人眼看截图发现的,属于证据不是垃圾) - firmware/ 的 A1 骨架与 site/ 文档站源码 .gitignore 排除:构建产物(firmware/build、host/build、sdkconfig)、 site/node_modules、__pycache__、桥接日志 _bridge.log、脚本自标的 *.stale。 .gitattributes 默认 `* -text`:现有 .py/.json 大多是 CRLF,原样存, 不让 git 重写行尾。唯一例外是 *.sh 强制 LF —— 带 \r 的 shell 脚本 bash 跑不了。 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
144 行
7.9 KiB
Python
144 行
7.9 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""P3B-EXPAND 网表(74HC595 x2 按键驱动 + PCA9555 输入扩展 + DAC63204 x2 调压)。"""
|
||
import os, sys
|
||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||
'skills', 'easyeda-sch-geometry', 'scripts'))
|
||
import local_netcheck as N
|
||
w, gnd, pwr, port, txt = N.w, N.gnd, N.pwr, N.port, N.txt
|
||
|
||
def gnd_up(x, y): # 接地旗朝上(引脚在下),用于导线自下方接入
|
||
N.FLAGS.append(('Ground', 'GND', x, y, 180))
|
||
|
||
def pwr_dn(x, y): # 电源旗朝下(引脚在上),用于导线自上方接入
|
||
N.FLAGS.append(('Power', '+3V3', x, y, 180))
|
||
|
||
# == 【A】74HC595 x2 —— 15 路按键 ================================
|
||
SR = [
|
||
(730, ['K1_VUP', 'K1_VDN', 'K2_PWR', 'K2_VUP', 'K2_VDN', 'K3_PWR', 'K3_VUP'],
|
||
'K1_PWR', 'KEY_SER', 'SR_CAS', 500),
|
||
# U22 的 Q7 原来空着,2026-09-03 拿来做板载 Hub 的远程复位(§21.7)
|
||
(560, ['K4_PWR', 'K4_VUP', 'K4_VDN', 'K5_PWR', 'K5_VUP', 'K5_VDN', 'HUB_RST'],
|
||
'K3_VDN', 'SR_CAS', None, 500),
|
||
]
|
||
for cy, qs, q0, ds, q7s, cx in SR:
|
||
L, R = 210, 290
|
||
for i, net in enumerate(qs): # Q1..Q7 左侧单列(rot180 标签朝左)
|
||
if net is None:
|
||
continue
|
||
y = cy + 35 - i * 10
|
||
w(net, (L, y), (195, y))
|
||
port(net, 195, y, 180)
|
||
w('GND', (L, cy - 35), (175, cy - 35), (175, cy - 60))
|
||
gnd(175, cy - 60)
|
||
w('+3V3', (R, cy + 35), (325, cy + 35), (325, cy + 65)) # VCC
|
||
pwr('+3V3', 325, cy + 65)
|
||
w(q0, (R, cy + 25), (340, cy + 25)); port(q0, 340, cy + 25, 0)
|
||
w(ds, (R, cy + 15), (340, cy + 15)); port(ds, 340, cy + 15, 0)
|
||
w('KEY_OE#', (R, cy + 5), (340, cy + 5)); port('KEY_OE#', 340, cy + 5, 0)
|
||
w('KEY_RCLK', (R, cy - 5), (340, cy - 5)); port('KEY_RCLK', 340, cy - 5, 0)
|
||
w('KEY_SRCLK', (R, cy - 15), (340, cy - 15)); port('KEY_SRCLK', 340, cy - 15, 0)
|
||
w('+3V3', (R, cy - 25), (440, cy - 25), (440, cy - 45)) # MR# 拉高
|
||
pwr_dn(440, cy - 45)
|
||
if q7s:
|
||
w(q7s, (R, cy - 35), (340, cy - 35))
|
||
port(q7s, 340, cy - 35, 0)
|
||
w('+3V3', (cx, cy + 40), (cx, cy + 65)); pwr('+3V3', cx, cy + 65) # VCC 去耦
|
||
w('GND', (cx, cy), (cx, cy - 30)); gnd(cx, cy - 30)
|
||
|
||
# KEY_OE# 上拉 100k:ESP32 复位期间 595 输出高阻
|
||
w('+3V3', (600, 560), (600, 590)); pwr('+3V3', 600, 590)
|
||
w('KEY_OE#', (600, 520), (600, 495)); port('KEY_OE#', 600, 495, 0)
|
||
|
||
# == 【B】PCA9555 输入扩展(地址 0x20)===========================
|
||
L, R = 710, 810
|
||
for y, net in [(755, 'IOEXP_INT#'), (725, 'EFUSE_FLT1'), (715, 'EFUSE_FLT2'),
|
||
(705, 'EFUSE_FLT3'), (695, 'EFUSE_FLT4'), (685, 'EFUSE_FLT5'),
|
||
(675, 'BUCK_PG'), (665, 'INA_ALERT')]:
|
||
w(net, (L, y), (640, y))
|
||
port(net, 640, y, 180)
|
||
for y in (745, 735, 645): # A1 / A2 / VSS
|
||
w('GND', (L, y), (450, y))
|
||
w('GND', (450, 645), (450, 745)); gnd(450, 645)
|
||
w('GND', (L, 655), (690, 655), (690, 645)) # IO0_7 备用脚就近接地
|
||
for y, net in [(645, 'EFUSE_PG1'), (655, 'EFUSE_PG2'), (665, 'EFUSE_PG3'),
|
||
(675, 'EFUSE_PG4'), (685, 'EFUSE_PG5'), (735, 'SCL'), (745, 'SDA')]:
|
||
w(net, (R, y), (850, y))
|
||
port(net, 850, y, 0)
|
||
for y in (695, 705, 715, 725): # IO1_5~7 备用 + A0(地址位)
|
||
w('GND', (R, y), (830, y))
|
||
w('GND', (830, 695), (830, 725))
|
||
w('GND', (830, 725), (1030, 725), (1030, 640)); gnd(1030, 640)
|
||
w('+3V3', (R, 755), (845, 755), (845, 795)); pwr('+3V3', 845, 795) # VDD
|
||
w('+3V3', (845, 775), (860, 775)) # C606
|
||
w('GND', (900, 775), (930, 775), (930, 800)); gnd_up(930, 800)
|
||
|
||
# == 【C】DAC63204 x2 —— 5 路调压 ================================
|
||
def dac(cx, cy, a0_to, outs, gpio_net, cap_net, vref_net, xs):
|
||
L, R = cx - 60, cx + 60
|
||
ySDA, yA0, ySCL, yGPIO = cy - 40, cy - 30, cy - 20, cy - 10
|
||
yj = ySDA if a0_to == 'SDA' else ySCL
|
||
w(a0_to, (L, yA0), (xs['jog'], yA0), (xs['jog'], yj), (L, yj))
|
||
w('SDA', (L, ySDA), (xs['i2c'], ySDA)); port('SDA', xs['i2c'], ySDA, 180)
|
||
w('SCL', (L, ySCL), (xs['i2c'], ySCL)); port('SCL', xs['i2c'], ySCL, 180)
|
||
w(gpio_net, (L, yGPIO), (xs['rg'] + 20, yGPIO)) # GPIO -> 10k 下拉
|
||
w('GND', (xs['rg'] - 20, yGPIO), (xs['gndL'], yGPIO), (xs['gndL'], cy - 50))
|
||
gnd(xs['gndL'], cy - 50)
|
||
if outs.get('OUT2'): # OUT2 / FB2
|
||
n = outs['OUT2']
|
||
w(n, (L, cy + 10), (xs['o2'], cy + 10), (xs['o2'], cy), (L, cy))
|
||
w(n, (xs['o2'], cy + 5), (xs['p2'], cy + 5))
|
||
port(n, xs['p2'], cy + 5, 180)
|
||
n0 = outs['OUT0'] # OUT0 / FB0
|
||
w(n0, (R, cy - 10), (xs['j0'], cy - 10), (xs['j0'], cy - 20))
|
||
w(n0, (R, cy - 20), (xs['p0'], cy - 20)); port(n0, xs['p0'], cy - 20, 0)
|
||
n1 = outs['OUT1'] # OUT1 / FB1
|
||
w(n1, (R, cy - 40), (xs['j1'], cy - 40), (xs['j1'], cy - 30))
|
||
w(n1, (R, cy - 30), (xs['p1'], cy - 30)); port(n1, xs['p1'], cy - 30, 0)
|
||
w(cap_net, (R, cy), (xs['cap'], cy), (xs['cap'], cy + 60)) # CAP -> 2.2uF
|
||
w('GND', (xs['cap'] + 40, cy + 60), (xs['capg'], cy + 60), (xs['capg'], cy + 100))
|
||
gnd_up(xs['capg'], cy + 100)
|
||
w(vref_net, (R, cy + 30), (xs['vref'], cy + 30), (xs['vref'], cy + 85))
|
||
w('+3V3', (xs['vref'], cy + 125), (xs['vref'], cy + 150)) # VREF 10k 上拉
|
||
pwr('+3V3', xs['vref'], cy + 150)
|
||
w(vref_net, (xs['vref'], cy + 80), (xs['cvr'], cy + 80)) # VREF 100nF 到地
|
||
w('GND', (xs['cvr'], cy + 120), (xs['cvr'], cy + 140)); gnd_up(xs['cvr'], cy + 140)
|
||
w('+3V3', (R, cy + 20), (xs['vdd'], cy + 20), (xs['vdd'], cy + 140))
|
||
pwr('+3V3', xs['vdd'], cy + 140)
|
||
w('+3V3', (xs['vdd'], cy + 120), (xs['vdd'] + 15, cy + 120)) # VDD 去耦
|
||
w('GND', (xs['vdd'] + 55, cy + 120), (xs['cvd'], cy + 120), (xs['cvd'], cy + 150))
|
||
gnd_up(xs['cvd'], cy + 150)
|
||
w('GND', (R, cy + 10), (xs['agnd'], cy + 10), (xs['agnd'], cy + 50))
|
||
gnd_up(xs['agnd'], cy + 50)
|
||
w('GND', (R, cy + 40), (xs['ep'], cy + 40), (xs['ep'], cy + 140))
|
||
gnd_up(xs['ep'], cy + 140)
|
||
|
||
X6 = dict(jog=150, i2c=100, rg=110, gndL=50, o2=145, p2=130,
|
||
j0=330, p0=390, j1=360, p1=480, cap=450, capg=520,
|
||
vref=330, cvr=390, vdd=420, cvd=500, agnd=440, ep=310)
|
||
X7 = {k: v + 530 for k, v in X6.items()}
|
||
X7.update(i2c=630, p0=920, p1=1010)
|
||
dac(230, 290, 'SDA', {'OUT0': 'VDAC1', 'OUT1': 'VDAC2', 'OUT2': 'VDAC3'},
|
||
'GPIO6', 'CAP6', 'VREF6', X6)
|
||
dac(760, 290, 'SCL', {'OUT0': 'VDAC4', 'OUT1': 'VDAC5', 'OUT2': None},
|
||
'GPIO7', 'CAP7', 'VREF7', X7)
|
||
|
||
# == 文字 ========================================================
|
||
txt('[A] 74HC595 x2 —— 15 路侧键驱动', 45, 806)
|
||
txt('[B] PCA9555 输入扩展(地址 0x20)', 600, 806)
|
||
txt('[C] DAC63204 x2 —— 5 路调压', 150, 205)
|
||
txt('595: U21 在前,Q7S 级联到 U22.DS;先移入的位落到 U22.Q7。', 45, 190)
|
||
txt('U22.Q7 = HUB_RST,远程复位板载 USB Hub(§21.7);OE# 高阻时靠 R716 上拉保持不复位。', 45, 175)
|
||
txt('OE# 上拉 100k —— ESP32 复位期间 15 路输出全部高阻。', 45, 178)
|
||
txt('PCA9555 备用脚 IO0_7 / IO1_5~7 直接接地(上电默认即输入),', 45, 166)
|
||
txt('固件严禁把 Port0[7] / Port1[7:5] 配成输出。', 45, 154)
|
||
txt('DAC 地址:U6 = 0x4A(A0->SDA),U7 = 0x4B(A0->SCL)。', 45, 142)
|
||
txt('FBx 必须接回 OUTx;CAP 接 2.2uF 到 AGND;VREF 空置时', 45, 130)
|
||
txt('100nF 到地 + 10k 上拉 VDD。内部基准 1.212V x2 = 2.424V。', 45, 118)
|
||
|
||
NC = {
|
||
'U22': ['9'], # Q7S 未用(Q7 已给 HUB_RST)
|
||
'U6': ['1', '2'], # FB3 / OUT3(第 4 通道未用)
|
||
'U7': ['1', '2', '3', '4'], # FB3/OUT3/OUT2/FB2(第 3、4 通道未用)
|
||
}
|