# -*- coding: utf-8 -*- u"""R2 刀片 **B3-PHONE** 页:手机侧机械接口 —— 电池排线 + 阻尼组 + 侧键焊盘 + EDL。 /c/Python314/python .claude/r2/b3_phone.py # 只算 + 本地自检 /c/Python314/python .claude/r2/b3_phone.py --push # 清页 + 重画(幂等) ## ⚠️ M2c 拆成两页 R1 把同样的内容铺在**四页**上(`C4-SITE1` 电池/阻尼/顶针/EDL、`C5-J1401A` 尾插座、 `C5-AUX` ESD/Rp/口温、`C3-USB` VBUS 开关)。塞进一张 A4 会挤到没法看,所以拆成: | 页 | 内容 | |---|---| | **`B3-PHONE`**(本页)| `J5` 电池排线 4 焊盘 + 阻尼电容组 + `K1~K4` 侧键中框焊盘 + EDL(`J3` + `U6`)| | **`B3B-USB`** | `J4` BM24-50DS 尾插座 + `U7` USBLC6 ESD + Rp/口温 + `U5` TPS22918 VBUS 开关 | ## 位号(方案 §7.2b,D11b 之后 U 序顺移) | 位号 | 器件 | 出处 | |---|---|---| | `J5` | MI8-BAT-FPC-4P(个人库自建,4 焊盘直焊排线)| R1 §13.5 的 `J81` | | `R60/R61` | 10k TEMP→GND / 68k ID→GND | R1 的 `R781/R791`,阻值抄保护板实测 | | `C60~C65` | 2200µF + 100µF×2 + 22µF×2 + 100nF | R1 §6.3 阻尼组 `C801~C806` 原样 | | `K1~K3` | 侧键中框焊盘(Ø1.5 裸铜盘,`MI8-KEY-PAD`)| R1 §22.3e:顶针取消,螺丝把主板压在焊盘上 | | `K4` | 侧键**公共地**焊盘(手机 J604)| 同上 | | `J3` `U6` `R63` `C69` | EDL 1.25mm 2P 座 + TS5A3157 模拟开关 + 100k 下拉 + 去耦 | R1 §22.4 的 `J61/U41/R741/C761` | ## 两条要紧的 1. **`P+`/`P−` 接的是保护板输出侧**(R1 §13.5):排线从保护板焊点处剪断, 4 个焊盘 `1=P+ 2=P− 3=TEMP 4=ID`,`TEMP`/`ID` 都是**对 P− 的**, 按「对负极线」量会得出「三个都不通」的假结论。 2. **`EDL_EN` 的 100k 下拉(`R63`)放在本页**(贴 `U6` 的 `IN` 脚), B2-CTRL 上没有 —— PCA9555 复位时是高阻输入,全靠这颗保证模拟开关断开。 """ import os import sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) from schcheck import Sheet, two_pin, by_rel, pins_of # noqa: E402 PAGE, NAME = 'cf32a688430fc2d1', 'B3-PHONE' FPC, KEYPAD, EDLJ, SW = 'MI8-BAT-FPC-4P', 'MI8-KEY-PAD', 'C225104', 'C353034' C2200U, C100U, C22U, C100N = 'C3828985', 'C15008', 'C12891', 'C1525' R10K, R68K, R100K = 'C25744', 'C36871', 'C25741' # 引脚偏移(R1 实测,见 _c4s1_live.json);rot 270 按 (x,y)->(y,-x) 推,放完断言 FPC_REL = {'1': (-20, 15), '2': (-20, 5), '3': (-20, -5), '4': (-20, -15)} EDLJ_R270 = {'1': (5, 25), '2': (-5, 25), '3': (25, 25), '4': (-25, 25)} SW_R270 = {'1': (10, 35), '2': (0, 35), '3': (-10, 35), '4': (-10, -35), '5': (0, -35), '6': (10, -35)} KEY_REL = {'1': (-15, 0)} NC = {'U6': ['3']} # NC 脚不接(R1 的 U41.3 也是空的) ALLOW_SPLIT = set(['GND', '+3V3']) RAIL_Y = 760 # VO_P 母线 CAPS = [('C60', C2200U, 320, 20), ('C61', C100U, 400, 15), ('C62', C100U, 480, 15), ('C63', C22U, 560, 15), ('C64', C22U, 640, 15), ('C65', C100N, 720, 20)] KEYS = [('K1', 'KPAD_PWR', 700), ('K2', 'KPAD_VUP', 640), ('K3', 'KPAD_VDN', 580)] J5 = (260, 700) J3 = (200, 340) U6 = (620, 340) def placement(): out = [['J5', FPC, J5[0], J5[1], 0], ['R60', R10K, 170, 640, 270], ['R61', R68K, 220, 600, 270], ['J3', EDLJ, J3[0], J3[1], 270], ['U6', SW, U6[0], U6[1], 270], ['R63', R100K, 760, 310, 270], ['C69', C100N, 1000, 300, 270]] for des, lcsc, x, half in CAPS: out.append([des, lcsc, x, RAIL_Y - 10 - half, 270]) for des, _net, y in KEYS: out.append([des, KEYPAD, 1100, y, 0]) out.append(['K4', KEYPAD, 1100, 520, 0]) return out def expect(): exp = {'J5': by_rel(J5[0], J5[1], FPC_REL), 'J3': by_rel(J3[0], J3[1], EDLJ_R270), 'U6': by_rel(U6[0], U6[1], SW_R270), 'R60': two_pin(170, 640), 'R61': two_pin(220, 600), 'R63': two_pin(760, 310), 'C69': two_pin(1000, 300)} for des, _l, x, half in CAPS: cy = RAIL_Y - 10 - half if des == 'C60': # ⚠ C60 是 2200µF **电解**:pin1(+) 必须在上(接 VO_P 母线)。 # 只比坐标集合是不够的 —— skill §6c:同一个料号在不同页 rot 语义能相反, # 本页实测 rot 270 给出的就是「pin1 在下」,第一次推下去极性是反的, # 而几何验证、DRC 全过,只有网表里「C60.2 在 VO_P」能看出来。 exp[des] = {'1': (x, cy + half), '2': (x, cy - half)} else: exp[des] = two_pin(x, cy, half) for des, _net, y in KEYS: exp[des] = by_rel(1100, y, KEY_REL) exp['K4'] = by_rel(1100, 520, KEY_REL) return exp def build(): s = Sheet(PAGE, NAME) # ── 1. 电池排线 + 阻尼组 ───────────────────────────────────────── # 四个脚都朝左出,越靠下的脚拐得越靠右,往下走时才不会撞上面几行的横线 px = J5[0] - 20 s.w('VO_P', (px, 715), (200, 715), (200, RAIL_Y)) # 1 P+ s.w('GND', (px, 705), (120, 705), (120, 660)) # 2 P− s.gnd(120, 660, 0) s.w('BAT_TEMP', (px, 695), (170, 695), (170, 660)) # 3 TEMP -> R60 s.w('GND', (170, 620), (170, 595)) s.gnd(170, 595, 0) s.w('BAT_ID', (px, 685), (220, 685), (220, 620)) # 4 ID -> R61 s.w('GND', (220, 580), (220, 555)) s.gnd(220, 555, 0) s.w('VO_P', (200, RAIL_Y), (800, RAIL_Y)) # 母线 s.port('IN', 'VO_P', 800, RAIL_Y, 180) for _des, _l, x, half in CAPS: cy = RAIL_Y - 10 - half s.w('VO_P', (x, RAIL_Y), (x, cy + half)) s.w('GND', (x, cy - half), (x, 685)) s.gnd(x, 685, 0) # ── 2. 侧键中框焊盘 ────────────────────────────────────────────── for _des, net, y in KEYS: s.w(net, (1085, y), (1000, y)) s.port('IN', net, 1000, y, 0) s.w('GND', (1085, 520), (1040, 520), (1040, 495)) # K4 公共地 s.gnd(1040, 495, 0) # ── 3. EDL:J3 两根信号经 U6 串在中间,EDL_EN 高 = 短接 ────────── # J3 rot270 四个脚都朝上。排线顺序(从左到右)= 4 / 2 / 1 / 3: # 外侧两个固定脚(4/3)就近入地、拐得比信号低;内侧两个信号往上翻出去, # 这样「外侧先拐、内侧后拐」就不产生交叉(U6.COM 是下排脚,只能从下面绕过去)。 s.w('GND', (175, 365), (175, 385), (135, 385), (135, 340)) # 4 固定脚 s.gnd(135, 340, 0) s.w('GND', (225, 365), (225, 405), (285, 405), (285, 430)) # 3 固定脚 s.gnd(285, 430, 180) s.w('EDL_A', (205, 365), (205, 510), (630, 510), (630, 375)) # 1 -> U6.NO(上排) s.w('EDL_B', (195, 365), (195, 400), (100, 400), # 2 -> U6.COM(下排) (100, 245), (610, 245), (610, 305)) s.w('GND', (620, 375), (620, 400), (580, 400), (580, 425)) # U6.2 GND s.gnd(580, 425, 180) # V+ 从下排出来往右走 y=265 这条道:它在 COM 那条横线(245)之上、 # 又在 EDL_EN 那几根竖线(275 起)之下,是唯一一条不产生交叉的高度 s.w('+3V3', (620, 305), (620, 265), (960, 265), (960, 290)) # U6.5 V+ s.pwr('+3V3', 960, 290, 0) s.w('+3V3', (960, 280), (1000, 280)) # -> C69 下脚 s.w('GND', (1000, 320), (1000, 345)) s.gnd(1000, 345, 180) s.w('EDL_EN', (630, 305), (630, 275), (860, 275)) # U6.6 IN s.w('EDL_EN', (760, 275), (760, 290)) # -> R63 下脚 s.w('GND', (760, 330), (760, 355)) # R63 上脚 -> 地 s.gnd(760, 355, 180) s.w('EDL_EN', (860, 275), (900, 275), (900, 320)) s.port('IN', 'EDL_EN', 900, 320, 0) # ── 4. 文字 ───────────────────────────────────────────────────── s.txt(45, 795, u'【B3-PHONE】手机侧接口:电池排线 4 焊盘 + 阻尼组 + 侧键中框焊盘 ×3 + EDL', 14) s.txt(60, 200, u'J5 = 小米8 电池排线剪断后的 4 焊盘(R1 §13.5):1=P+ 2=P− 3=TEMP 4=ID。', 10) s.txt(60, 182, u'⚠ 接的是保护板输出侧 P+/P−,不是 B+/B−;TEMP 与 ID 都是对 P− 的,', 10) s.txt(60, 164, u' 按「对负极线」量会得出「三个都不通」的假结论。保护板整块不装。', 10) s.txt(60, 146, u'R60 10k 代替原 NTC(固定模拟 25°C)、R61 68k 复制原 BATT_ID。', 10) s.txt(60, 128, u'K1~K3 中框式裸铜焊盘,K4 是三键公共地(J604);顶针已取消(§22.3e)。', 10) return s def main(): push = '--push' in sys.argv place = placement() exp = expect() s = build() s.assert_grid() errs = s.netcheck(pins_of(exp), NC, ALLOW_SPLIT) s.report(len(place), errs) if not push: return s.clear() s.place(place, exp) s.push_geometry() print(u'接着跑 verify_sch.py --nets --nc .claude/r2/b3-nc.json') if __name__ == '__main__': main()