原理图/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
112 行
4.8 KiB
Python
112 行
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
u"""C2-HUB 补一个上游 VBUS 检测分压:VBUS_UP(5V) -> 10k/20k -> UP_VBUS_DET -> 下板 IO44。
|
||
|
||
用法: /c/Python314/python .claude/c2_vbusdet.py [--push]
|
||
|
||
为什么要分压:J23 的 VBUS 是 5V,而排针那头接的是 ESP32 的 IO44(3.3V 域)。
|
||
10k/20k 得到 5×20/30 = 3.33V;USB 上限 5.25V 时是 3.5V,仍在 ESP32 的
|
||
绝对最大值 3.6V 以内,而且远高于 VIH(≈2.48V)。
|
||
主机没插时 VBUS=0 -> 读到 0,这正是这个信号要的判据。
|
||
"""
|
||
import json
|
||
import os
|
||
import sys
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
sys.path.insert(0, HERE)
|
||
from eda import run
|
||
|
||
PAGE = '472c9bdbd7180ac4' # C2-HUB
|
||
LIB = '0819f05c4eef4c71ace90d822a990e87'
|
||
R10K = 'c3b9baa5ef2e4070a4c0f9e9cd04fe6e' # C25744
|
||
R20K = '3a163ef2745c43cd822f855b5ea3efa4' # C25765
|
||
|
||
Y = 120
|
||
R721, R722 = (880, Y), (980, Y) # 上臂 10k / 下臂 20k
|
||
EXPECT = {'R721': [(860, Y), (900, Y)], 'R722': [(960, Y), (1000, Y)]}
|
||
|
||
|
||
def call(js, timeout=180):
|
||
r = run(js, timeout=timeout)
|
||
if not r.get('success'):
|
||
raise RuntimeError(json.dumps(r, ensure_ascii=False)[:800])
|
||
return r['result']
|
||
|
||
|
||
def main():
|
||
if '--push' not in sys.argv:
|
||
print(u'待加:R721 10k / R722 20k + VBUS_UP 端口 + UP_VBUS_DET 端口 + 地旗(加 --push)')
|
||
return
|
||
|
||
call("""
|
||
await eda.dmt_EditorControl.openDocument('%s'); await new Promise(r=>setTimeout(r,900));
|
||
const n=(await eda.dmt_Schematic.getCurrentSchematicPageInfo()).name;
|
||
if (n!=='C2-HUB') throw new Error('page='+n);
|
||
// 重跑安全:先把上一轮加的东西删掉
|
||
for (const c of await eda.sch_PrimitiveComponent.getAll()){
|
||
const t=c.getState_ComponentType();
|
||
if (t==='part' && ['R721','R722'].includes(c.getState_Designator())){
|
||
await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId()); continue; }
|
||
if (t!=='netflag' && t!=='netport') continue;
|
||
let nn=''; try{nn=c.getState_Net()||''}catch(e){}
|
||
const x=Math.round(c.getState_X()), y=Math.round(c.getState_Y());
|
||
if (x>=700 && y<=180 && (nn==='UP_VBUS_DET' || nn==='GND' || nn==='VBUS_UP'))
|
||
await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId());
|
||
}
|
||
for (const w of await eda.sch_PrimitiveWire.getAll()){
|
||
const a=w.getState_Line(); let hit=false;
|
||
for (let i=0;i<a.length;i+=2) if (a[i]>=700 && a[i+1]<=180) hit=true;
|
||
if (hit) await eda.sch_PrimitiveWire.delete(w.getState_PrimitiveId());
|
||
}
|
||
return 1;
|
||
""" % PAGE)
|
||
|
||
call("""
|
||
for (const [d,uuid,x,y] of %s){
|
||
await eda.sch_PrimitiveComponent.create({libraryUuid:'%s', uuid}, x, y, undefined, 0, false, true, true);
|
||
for (const c of await eda.sch_PrimitiveComponent.getAll()){
|
||
if (c.getState_ComponentType()!=='part') continue;
|
||
if (Math.round(c.getState_X())!==x || Math.round(c.getState_Y())!==y) continue;
|
||
await c.toAsync().setState_Designator(d).done();
|
||
}
|
||
}
|
||
return 1;
|
||
""" % (json.dumps([['R721', R10K, R721[0], R721[1]],
|
||
['R722', R20K, R722[0], R722[1]]]), LIB))
|
||
|
||
pins = call("""
|
||
const out={};
|
||
for (const c of await eda.sch_PrimitiveComponent.getAll()){
|
||
if (c.getState_ComponentType()!=='part') continue;
|
||
const d=c.getState_Designator();
|
||
if (d!=='R721' && d!=='R722') continue;
|
||
out[d]=(await c.getAllPins()).map(p=>[Math.round(p.getState_X()),Math.round(p.getState_Y())]);
|
||
}
|
||
return out;
|
||
""")
|
||
bad = [u'%s 期望 %s 实测 %s' % (d, EXPECT[d], sorted(map(tuple, pins.get(d, []))))
|
||
for d in EXPECT if sorted(map(tuple, pins.get(d, []))) != EXPECT[d]]
|
||
if bad:
|
||
raise SystemExit(u'引脚坐标对不上:\n ' + '\n '.join(bad))
|
||
print(u'引脚坐标核对通过')
|
||
|
||
W = [[800, Y, 860, Y], # VBUS_UP -> R721
|
||
[900, Y, 960, Y], # R721 -> R722(中点就在这一段上)
|
||
[930, Y, 930, 60], # 中点 -> UP_VBUS_DET
|
||
[1000, Y, 1050, Y], [1050, Y, 1050, 90]]
|
||
PT = [['BI', 'VBUS_UP', 800, Y, 180], ['BI', 'UP_VBUS_DET', 930, 60, 0]]
|
||
F = [['Ground', 'GND', 1050, 90, 0]]
|
||
TX = [(700, 175, u'上游 VBUS 检测:5V 经 10k/20k 分到 3.33V 送 IO44(§22.2)。主机没插时读 0。', 10)]
|
||
call("for (const s of %s) await eda.sch_PrimitiveWire.create(s); return 1;" % json.dumps(W))
|
||
call("for (const p of %s) await eda.sch_PrimitiveComponent.createNetPort(p[0],p[1],p[2],p[3],p[4],false); return 1;"
|
||
% json.dumps(PT))
|
||
call("for (const f of %s) await eda.sch_PrimitiveComponent.createNetFlag(f[0],f[1],f[2],f[3],f[4],false); return 1;"
|
||
% json.dumps(F))
|
||
call("for (const t of %s) await eda.sch_PrimitiveText.create(t[0],t[1],t[2],0,null,null,t[3],false,false,false,0); return 1;"
|
||
% json.dumps([list(t) for t in TX], ensure_ascii=False))
|
||
print(u'推送完成')
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|