从USB-A到Type-C:手把手用Arduino模拟一个‘傻瓜式’PD协议嗅探器
从USB-A到Type-C:手把手用Arduino模拟一个‘傻瓜式’PD协议嗅探器
Type-C接口的普及让充电和数据传输变得更加便捷,但背后的Power Delivery(PD)协议却鲜为人知。本文将带你用Arduino开发板和简单电路,亲手打造一个PD协议嗅探器,直观观察Type-C充电过程中的"握手"细节。
1. 准备工作:硬件与基础原理
1.1 元器件清单
制作这个PD嗅探器需要以下基础元件:
- Arduino Uno/Nano开发板(或其他兼容板)
- Type-C母座(推荐16pin全功能款)
- 10kΩ电阻 x2
- 5.1kΩ电阻 x2
- 1kΩ电阻 x1
- 面包板及跳线若干
- USB转TTL串口模块(用于调试输出)
提示:电阻精度建议选择1%的金属膜电阻,这对电压测量精度影响较大。
1.2 Type-C接口基础
Type-C接口的正反插特性源于其对称设计。关键引脚分布如下:
| 引脚组 | 功能说明 |
|---|---|
| A1/A12 | GND |
| A4/A9 | VBUS |
| A5/A8 | CC1/CC2 |
| B5/B8 | CC2/CC1 |
当设备连接时,CC(Configuration Channel)引脚上的电压变化会反映充电协议的状态。Source端通过上拉电阻(RP)表明供电能力,Sink端通过下拉电阻(Rd)完成检测。
2. 电路搭建与连接
2.1 核心电路设计
PD嗅探器的核心是监测CC线上的电压变化。电路连接要点:
- 将Type-C母座的CC1和CC2分别连接到Arduino的A0和A1模拟输入引脚
- 在CC1和CC2线上各串联一个10kΩ电阻(保护Arduino输入)
- 在Sink端模拟电路中加入5.1kΩ下拉电阻
- 可选:添加1kΩ电阻模拟E-Marker线缆识别
// 简易电路连接示意图 Type-C母座 CC1 —— 10kΩ —— Arduino A0 CC2 —— 10kΩ —— Arduino A1 GND —— 5.1kΩ —— CC1/CC2 (模拟Sink端)2.2 电压测量原理
当Source和Sink连接时,CC线上的电压由电阻分压决定:
V_measured = V_source * (Rd) / (Rp + Rd)不同供电能力对应的Rp值:
| 供电能力 | Rp值(分压模式) | 电压理论值(3.3V源) |
|---|---|---|
| 默认(500mA) | 56kΩ | 0.25V |
| 1.5A | 22kΩ | 0.61V |
| 3A | 10kΩ | 1.12V |
3. Arduino代码实现
3.1 基础电压监测代码
#define CC1_PIN A0 #define CC2_PIN A1 void setup() { Serial.begin(115200); pinMode(CC1_PIN, INPUT); pinMode(CC2_PIN, INPUT); } void loop() { float cc1_voltage = analogRead(CC1_PIN) * (3.3 / 1023.0); float cc2_voltage = analogRead(CC2_PIN) * (3.3 / 1023.0); Serial.print("CC1 Voltage: "); Serial.print(cc1_voltage); Serial.print("V | CC2 Voltage: "); Serial.print(cc2_voltage); Serial.println("V"); delay(500); }3.2 协议状态判断增强版
通过扩展代码可以自动判断当前充电状态:
// 供电能力判断函数 String detect_power_capability(float voltage) { if (voltage < 0.3) return "Default(500mA)"; else if (voltage < 0.8) return "1.5A"; else if (voltage < 1.5) return "3A"; else return "Unknown"; } void loop() { // ...(同上电压读取代码) Serial.print("Detected Power: "); Serial.print(detect_power_capability(cc1_voltage)); Serial.print(" on CC1, "); Serial.print(detect_power_capability(cc2_voltage)); Serial.println(" on CC2"); // 添加线缆类型判断 if (cc1_voltage > 2.5 || cc2_voltage > 2.5) { Serial.println("E-Marker cable detected"); } }4. 实战测试与数据分析
4.1 典型测试场景
连接不同充电器时的预期输出:
普通5V/1A充电器:
- CC电压约0.6V(对应22kΩ Rp)
- 输出识别为1.5A能力
PD快充充电器(18W):
- 初始阶段CC电压约1.1V(10kΩ Rp)
- 协议协商后电压可能变化
E-Marker线缆(5A):
- 初始检测到高电压(>2.5V)
- 随后进入协议协商阶段
4.2 数据记录与分析建议
建议使用Arduino的串口绘图器或第三方工具(如CoolTerm)记录电压变化曲线。典型握手过程会显示:
- 初始连接时的电压跳变
- 协议协商期间的脉冲信号
- 稳定后的维持电压
注意:某些充电器可能在无负载时会降低VBUS输出,这会影响CC线电压测量结果。
5. 进阶应用与扩展思路
5.1 添加状态指示灯
通过添加LED可以直观显示状态:
- 红色LED:默认供电(500mA)
- 黄色LED:中等供电(1.5A)
- 绿色LED:高功率供电(3A+)
// LED控制示例 void update_leds(String power_level) { if(power_level == "Default(500mA)") { digitalWrite(RED_LED, HIGH); digitalWrite(YELLOW_LED, LOW); // ...其他LED控制 } // ...其他条件判断 }5.2 支持更多PD协议特性
通过升级硬件可以监测更多PD协议细节:
- 添加I2C电平转换器监测PD报文
- 使用逻辑分析仪捕捉CC线上的BMC编码
- 增加USB PD触发芯片进行主动测试
5.3 制作便携式版本
将电路集成到PCB上,添加:
- OLED显示屏实时显示状态
- 锂电池供电系统
- 外壳与Type-C测试接口
6. 常见问题排查
在实际测试中可能会遇到以下情况:
- 无电压读数:检查CC线连接是否正确,确认Type-C母座引脚定义
- 读数不稳定:确保所有电阻连接牢固,尝试缩短导线长度
- 识别错误:校准Arduino的ADC参考电压,检查电阻精度
一个实用的调试技巧是在代码中添加原始ADC值输出:
Serial.print("Raw ADC: "); Serial.print(analogRead(CC1_PIN)); Serial.print("/"); Serial.println(analogRead(CC2_PIN));通过这个项目,不仅能直观理解Type-C PD协议的工作机制,还能为后续开发Type-C相关设备打下基础。在实际测试中,不同品牌充电器的协议实现可能略有差异,这正是硬件调试的乐趣所在。
