4、充电协议详解(上):USB PD协议基础、PDO与APDO协商、CC线通信逻辑
各位同学,大家好。今天我们进入充电协议部分。说实话,这部分内容在万用表电池管理系统里,是真正拉开项目档次的地方。你想想看,如果只是用个4056充电芯片,那太简单了,没什么技术含量。但如果你能让万用表支持USB PD快充,那就不一样了——充电速度快,兼容性好,而且显得很专业。
我个人习惯把USB PD协议拆成三个层次来理解:物理层(CC线怎么通信)、协议层(PDO怎么协商)、策略层(怎么选电压电流)。今天我们先讲前两层。
4.1 USB PD协议基础——它到底在干什么?
USB PD,全称是USB Power Delivery。说白了,它就是一种让充电器和设备之间“商量”电压电流的协议。传统USB只有5V,PD可以做到5V、9V、12V、15V、20V,甚至更高。
我记得第一次接触PD协议时,觉得这东西挺复杂的。后来发现,核心就一句话:通过CC线传输二进制消息,双方协商出一个共同认可的供电参数。
PD协议有几个关键点:
- 双向通信:充电器和设备都能发起协商
- 电压可调:不再是固定的5V,而是可以动态调整
- 电流可调:最大可以到5A(需要emark线缆)
- 角色互换:DFP(下行端口,供电方)和UFP(上行端口,用电方)可以互换
核心概念:PD协议不是“硬切换”电压,而是通过协商来“软切换”。充电器先输出5V,等设备说“我要9V”,充电器才切换到9V。这个过程叫“Source Capability”协商。
嗯,这里要注意:PD协议和QC协议不一样。QC是高通的私有协议,PD是USB-IF的标准协议。我们的万用表电池管理系统,我建议优先支持PD,因为兼容性更好,而且现在大部分快充头都支持PD。
4.2 PDO与APDO——供电能力的“菜单”
PDO,全称是Power Data Object。你可以把它理解成充电器提供的“菜单”。充电器告诉设备:“我有这些电压电流组合,你选一个吧。”
举个例子,一个典型的PD充电器会发送这样的PDO列表:
| PDO编号 | 电压 | 电流 | 功率 |
|---|---|---|---|
| PDO 1 | 5.0V | 3.0A | 15W |
| PDO 2 | 9.0V | 3.0A | 27W |
| PDO 3 | 12.0V | 3.0A | 36W |
| PDO 4 | 15.0V | 3.0A | 45W |
| PDO 5 | 20.0V | 3.0A | 60W |
设备收到这个列表后,会根据自己的需求选择一个PDO。比如我的万用表电池是3串锂电池,充电电压需要12.6V,那我就会选PDO 3(12V),然后通过DC-DC升压到12.6V。
那APDO又是什么?APDO是Augmented PDO,是PD 3.0引入的增强型PDO。它允许更精细的电压调节,比如5V到20V之间,可以以20mV为步进调整。这在一些需要精确电压的场景下特别有用。
我的经验:在万用表电池管理系统中,我建议使用APDO。因为锂电池充电需要恒流恒压,如果能精确控制充电电压,可以更好地保护电池。我曾经在一个项目中,因为PDO电压步进太大(只有5V、9V、12V),导致充电效率不高。后来改用APDO,电压可以调到11.8V,刚好匹配电池的充电曲线。
4.3 CC线通信逻辑——物理层怎么干活?
CC线,全称是Configuration Channel。它是USB Type-C接口里的一根特殊引脚。PD协议的所有通信,都是通过这根线完成的。
CC线的通信逻辑,说白了就是“一问一答”。充电器(Source)和设备(Sink)通过CC线发送和接收二进制数据包。每个数据包包含一个头部和若干数据对象。
通信流程大概是这样的:
- 连接检测:充电器检测到CC线上有下拉电阻(Rd),就知道有设备插入了
- 能力宣告:充电器发送Source Capabilities消息,告诉设备自己有哪些PDO
- 请求协商:设备发送Request消息,选择其中一个PDO
- 确认切换:充电器发送Accept消息,然后切换到新的电压
- 供电开始:充电器发送PS_RDY消息,告诉设备“电压已经稳定,可以用了”
这里有个细节:CC线通信是半双工的,而且速率不高(300kbps左右)。但对我们来说足够了,因为PD协商只在连接时发生一次,平时不会频繁通信。
避坑指南:我曾经在一个项目中,CC线的上拉电阻选错了值。Type-C规范要求,Source端的CC线必须接一个上拉电阻(Rp),Sink端接下拉电阻(Rd)。Rp的值决定了充电器能提供的电流能力:
- Rp = 10kΩ:默认USB电流(500mA)
- Rp = 22kΩ:1.5A
- Rp = 56kΩ:3.0A
如果你选错了,充电器可能不会识别你的设备,或者只能以很低的电流充电。所以,一定要仔细看数据手册。
4.4 实战:用Python模拟PD协商
光说不练假把式。我们写一段简单的Python代码,模拟PD协商的过程。虽然实际项目中我们用的是C语言,但Python更容易理解逻辑。
# 模拟PD协商过程
class PDSource:
def __init__(self):
self.pdos = [
{"voltage": 5.0, "current": 3.0},
{"voltage": 9.0, "current": 3.0},
{"voltage": 12.0, "current": 3.0}
]
self.current_pdo = 0 # 默认使用PDO 0(5V)
def send_capabilities(self):
print("Source: 我的能力列表如下:")
for i, pdo in enumerate(self.pdos):
print(f" PDO {i}: {pdo['voltage']}V @ {pdo['current']}A")
return self.pdos
def accept_request(self, pdo_index):
if pdo_index < len(self.pdos):
self.current_pdo = pdo_index
print(f"Source: 接受请求,切换到 {self.pdos[pdo_index]['voltage']}V")
return True
return False
class PDSink:
def __init__(self, target_voltage):
self.target_voltage = target_voltage
def request_pdo(self, capabilities):
for i, pdo in enumerate(capabilities):
if pdo['voltage'] == self.target_voltage:
print(f"Sink: 请求PDO {i} ({pdo['voltage']}V)")
return i
print("Sink: 没有找到匹配的电压,使用默认5V")
return 0
# 模拟协商
source = PDSource()
sink = PDSink(target_voltage=9.0)
caps = source.send_capabilities()
requested_pdo = sink.request_pdo(caps)
source.accept_request(requested_pdo)
这段代码虽然简单,但体现了PD协商的核心逻辑。实际项目中,你需要在单片机里实现类似的状态机,处理各种超时和错误情况。
我的建议:在万用表电池管理系统中,不要试图自己从头实现PD协议栈。市面上有很多成熟的PD控制器芯片,比如STUSB4500、FUSB302等。它们内部已经实现了协议层,你只需要通过I2C接口读写寄存器就行了。这样既省时间,又稳定可靠。
4.5 小结
今天我们讲了USB PD协议的基础知识。核心就三点:
- PD协议通过CC线通信,协商电压电流
- PDO是供电能力的“菜单”,APDO允许更精细的调节
- CC线通信有固定的流程:能力宣告→请求→确认→切换
下一节我们会讲PD协议的状态机实现,以及如何在万用表电池管理系统中实际应用。到时候我会分享一个我踩过的坑——关于PD协议里的“Hard Reset”处理,差点把电池充爆了。嗯,到时候细说。