通用充电器快充协议识别实战:QC电平与PE电流脉冲解析 简介不同品牌手机的快充协议互不兼容使得通用充电器必须内置专用识别芯片才能匹配QC2.0、QC3.0、MTK PE/PE等多种标准。文档以“快充识别”为主线从2007年首个电池充电规范、2009年GSMA通用充电器标准谈起回顾了USB充电协议的发展历程并重点讲解其核心原理充电器通过Micro USB接口的D/D-引脚读取手机端加载的电压值进而调整自身AC/DC的输出电压和电流实现大功率快充。文档列出了QC2.0的5V/9V/12V、QC3.0从3.6V到12V以0.2V步进、MTK PE/PE的5V/7V/9V/12V等关键参数同时整理了BC1.2、Apple、Samsung、QC2.0、QC3.0、MTK PE/PE等主流协议的对照表以及充电电流、功率等数据便于横向比较。资源包为1个doc文件约176KB排版清晰、表格完整还以GenesysLogic GL889M-10芯片为例说明了识别芯片在通用充电器设计中的具体用法文档内容虽短但覆盖了标准、芯片、表格、参数等多个维度适合项目预研、方案选型和维修排障时快速查阅。硬件工程师、电源设计人员和维修技术人员阅读后可以快速掌握快充协议识别、端口适配和输出电压控制的整体思路提升充电类产品的研发和调试效率为开发兼容多品牌手机的通用充电器提供直接参考目前已有1696人学习下载。1. 通用充电器快充协议识别先分清 QC 电平协商和 PE 电流脉冲通用充电器这句话听起来像把电压调对就行实际开发里真正难的是那两根平时不起眼的 D/D- 引脚。QC2.0/QC3.0 把电压请求编码成 D/D- 上的 0.6V 与 3.3V 电平组合MTK PE/PEPump Express却绕开 D/D-用 VBUS 电流通断时序通知充电器升压两类协议共用同一根充电线协商通道却完全不同。所以一台兼容 QC2.0、QC3.0、MTK PE/PE 的通用充电器核心任务不是能出 20V而是先做对充电识别——判断对方用哪套协议说话。下文按协商机制、信号检测、硬件切换、排错验证四层展开适合做充电器、车充、多口座的硬件工程师以及想用 MCU 复现快充协议的嵌入式开发。2. QC2.0/QC3.0 握手机制与 D/D- 档位编码参数2.1 QC2.0 连续模式的四档电压与 0.6V/3.3V 电平表QC2.0 最常用的是连续模式充电器稳定输出一组固定电压设备通过改变 D/D- 上的直流电平来切换档位。四个档位的编码很有规律0V、0.6V、3.3V 三个电平组合出 5V/9V/12V/20V目标输出电压D 电平D- 电平典型应用5.0V0.6V0V默认值握手未完成也保持9.0V3.3V0.6V最常见的快充档位12.0V0.6V3.3V高功率设备20.0V3.3V3.3V需充电器支持 Class B为什么选 0.6V 而不是别的值因为它要和 USB BC1.2 的 CDP 检测电压体系兼容又要明显高于线路噪声。USB 2.0 数据线的空闲电平是 0VD 上压一个 0.6V 左右的直流电平不会干扰 1.5V 左右的差分信号判决门限而 3.3V 直接从逻辑电源取用分压或 DAC 都能稳定产生。0.6V 与 3.3V 之间留了 2.7V 的空区设备端 ADC 很容易把三个电平分开不必担心噪声造成的档位误判。握手时序却比电平表曲折。设备要先单方面把 D 拉到 0.6V 并保持约 1.25s充电器检测到 D 电压落在 0.25V0.95V 区间且持续稳定才确认这是 QC 设备再在内部把 D/D- 短接作为应答。设备观察到 D- 电压被拉到接近 D确认短接应答已经发生才释放 D 进入档位选择。这个先单侧拉高、后短接应答的顺序是初次做 QC 的人最容易画反的地方自己先把 D/D- 短接再等设备拉高永远等不到。2.2 QC3.0 的 INOV 调压5V 基准上的 200mV 步进QC3.0 保留了 QC2.0 的握手方式握手完成后的调压换成 INOVIntelligent Negotiation for Optimal Voltage。充电器先输出 5V设备在 D 上打一串低电平脉冲每打一个脉冲电压上升 200mV目标电压满足 V_out 5.0 0.2 × N。9V 对应 N2012V 对应 N3520V 对应 N75下调方向则在 D- 上打脉冲每打一个降 200mV。这里有个容易忽视的细节INOV 的 200mV 步进是相对当前电压的累加不是绝对目标。如果现在已经是 9.2V想回到 9.0V正确做法是在 D- 上打一个脉冲压下去 200mV而不是在 D 上重发 20 个脉冲。MCU 实现时最好维护一个 current_mv 变量每次脉冲都基于它加减再映射到 DAC 输出否则多打或少打一个脉冲最终电压就差出整整 200mV。脉冲速度不需要很快单脉冲宽度在几百微秒到 1ms 之间都能被识别。反而要小心去抖窗口去抖太长会把一串连续脉冲当成一次抖动吃掉导致最终电压少一档。我一般把去抖做在电平跳变确认上不做在脉冲计数上即只对 0.6V/3.3V 两个电平分别做 50µs 的确认滤波脉冲之间的间隔原样通过。2.3 用 STM32 DAC 复现 QC 握手的最小代码在 MCU 上做 QC 识别我一般用带 DAC 的 STM32F0/F3 系列每个 DAC 通道输出一路 0.6V 或 3.3V同时用 ADC 回读 D/D- 实际电压。下面是一段可复现的 QC2.0 切 9V 代码/* QC2.0 档位表目标电压与 D/D- 电平单位 mV */ static const uint16_t qc2_table[4][3] { { 5000, 600, 0 }, { 9000, 3300, 600 }, {12000, 600, 3300 }, {20000, 3300, 3300 }, }; /* DAC 12bit, VREF3.3V: mV 转 DAC 数值 */ static uint16_t dac_code(uint16_t mv) { return (uint16_t)((uint32_t)mv * 4095UL / 3300UL); } void qc2_select_class(uint8_t idx) { /* 1. D 拉至 0.6VD- 保持高阻开始握手 */ dac_set(DAC_CH_DPLUS, dac_code(600)); gpio_mode(PIN_DMINUS, GPIO_MODE_ANALOG); delay_ms(1300); /* 必须保持 1.25s 以上 */ /* 2. 等待充电器短接 D/D- 应答D- 电压被拉到 0.6V 附近 */ uint32_t t0 get_tick(); while (adc_read_mv(PIN_DMINUS) 400) { if (get_tick() - t0 2000) { fallback_to_5v(); return; } } /* 3. 按档位表输出 D/D- 电平充电器随后升压 */ dac_set(DAC_CH_DPLUS, dac_code(qc2_table[idx][1])); dac_set(DAC_CH_DMINUS, dac_code(qc2_table[idx][2])); delay_ms(300); pwm_enable(VBUS_BOOST, true); }第 1 步的 1300ms 延时直接对应 QC2.0 握手要求的D 持续 0.6V 超过 1.25s这个时间不能贪快不少兼容电源在 1s 以内不动作。第 2 步用 D- 是否被拉到 400mV 以上判断应答而不是读 D 自身——D 本来就被我们拉在 0.6V读它没有区分度。第 3 步先输出电平再开升压因为先升压后挂载会在 VBUS 上产生跌落容易被电源保护电路误判成过流。9V 档对应 idx1D 3.3V、D- 0.6V是实测兼容性最好的组合。提示没有 DAC 时可以用两个 GPIO 配合 33kΩ/7.5kΩ 分压产生约 0.61V但 GPIO 内阻会串进分压网络D 电压可能偏移 50mV 以上建议加一级运放跟随再切到 D。3. MTK PE/PE 协议基于 VBUS 电流脉冲的另一种充电识别3.1 为什么 PE 放在通用充电器里最难兼容先澄清一个缩写撞名这里的 PE 是 MTK 的 Pump Express和装系统用的 Windows PE 毫无关系检索时别混在一起。高通把信息放在 D/D- 上充电器有 ADC/DAC 就能解析MTK 的 Pump Express 和 Pump Express Plus 完全不碰 D/D-设备通过周期性拉载—卸载VBUS 电流来发指令充电器要像读电报一样按时间窗口统计电流通断次数才知道对方要 7V、9V 还是 12V。这带来三个麻烦。第一电流脉冲没有统一载波频率设备按自身负载情况决定节奏充电器只能用较宽的窗口去猜。第二普通充电器本身就有输出纹波和负载波动一个开一关一的电流序列和劣质线缆接触抖动在示波器上长得几乎一样。第三PE 设备在握手成功后不再持续发脉冲充电器要把输出电压锁在最后一个档位如果锁存逻辑提前退出设备立刻跌回 5V 重新协商。所以做多协议识别时PE 通常放在 QC 之后的第二优先级电流采样必须有独立硬件通道。3.2 PE/PE 的 0.5V 步进升压与电流拉载时序PE 1.0 的协商过程可以概括为初始 5V设备在 VBUS 上执行一组固定长度的拉载序列充电器识别后每收到一次有效负载脉冲输出电压上调 0.5V直到设备不再发新脉冲。PE 在此基础上明确 7V、9V、12V 档位缩短了脉冲宽度但仍保留逐级升压、设备确认的框架。MTK 平台与高通平台方案的本质区别就在这里高通在 D/D- 上做电平文章MTK 只认 VBUS 电流。协议协商通道电压步进典型档位充电器侧实现难度QC2.0D/D- 电平固定档位跳变5/9/12/20V低QC3.0D/D- 脉冲200mV520V 连续低PE 1.0VBUS 电流脉冲0.5V5/7/9/12V中PEVBUS 电流脉冲0.5V5/7/9/12V中实现难度的差异在于读电压和读电流完全不同。QC 只要准确输出电平PE 则要准确读出电流。我用 INA226 这类高边电流采样芯片以 1kHz 采样率监控 VBUS 电流判断逻辑不是解调脉冲宽度而是统计一个 500ms 窗口内跨越阈值的边沿次数。边沿次数落在 48 之间就认为是一次有效 PE 请求少于 4 次多为空载波动多于 8 次多半是线缆接触问题。窗口阈值要按实际充电器的静态纹波调整不能照抄。3.3 检测设备类型用电流边沿次数区分 PE 与普通负载充电器侧 PE 检测的难点是设备在充电和设备在协商无法靠电压区分只能靠电流变化率。下面这段代码统计固定窗口内的拉载边沿并把结果映射成 PE 协商信号/* 阈值为 350mA高于普通 5V 满载静态纹波 */ #define PE_CUR_THRESHOLD_mA 350 #define PE_WINDOW_MS 500 #define PE_EDGE_MIN 4 #define PE_EDGE_MAX 8 uint8_t pe_count_edges(uint16_t *cur_samples, uint16_t n) { uint8_t edges 0; uint8_t last (cur_samples[0] PE_CUR_THRESHOLD_mA) ? 1 : 0; for (uint16_t i 1; i n; i) { uint8_t st (cur_samples[i] PE_CUR_THRESHOLD_mA) ? 1 : 0; if (st ! last) { edges; last st; if (edges PE_EDGE_MAX) return 0; /* 边沿过多判为噪声 */ } } return (edges PE_EDGE_MIN) ? edges : 0; }这段代码的关键在阈值和窗口。350mA 阈值基于大多数手机在 PE 协商阶段会拉 300400mA 的实测值具体项目里先用电流探头抓几台真机记下静态纹波峰值阈值取它的 1.52 倍。500ms 窗口对应 PE 设备一轮完整拉载序列长度窗口太短会漏掉只发 5 个脉冲的设备太长则会把前后两轮协商混进同一个统计。返回值是确认到的边沿数后续升压逻辑每收到一次有效边沿就上调 0.5V升到 12V 后停止进入等待状态。还要注意顺序PE 设备开机初期会先以普通 5V 充电一小段时间等系统负载稳定才握手。充电器不能一看到几毫安负载变化就切到 PE 模式必须先等 VBUS 稳定在 5V 且持续 3 秒以上再开始听边沿。否则车充里常见的点烟器抖动会被误判成 PE 请求输出电压被顶到 12V烧坏后续接入的低压设备。4. 充电识别硬件与状态机从 BC1.2 到 Apple 分压的兼容切换4.1 先判端口类型SDP、CDP、DCP 与 D/D- 短接电阻充电识别的另一半含义是识别自己面对的是什么端口。USB BC1.2 把端口分成三类SDP 标准下行端口是普通电脑 USB 口最大 500mAD/D- 走完整数据通路CDP 下行端口既能充电也能传数据充电电流可达 1.5ADCP 专用充电端口不传数据D/D- 用小于 200Ω 的电阻短接充电电流上限由充电器声明。通用充电器在协议未知时应该先表现成 DCP这是所有手机都能接受的默认形态。端口/识别方式DD-对外表现SDP数据数据最大 500mACDP0.6V 检测后接数据数据充电数据DCP短接 200Ω短接默认 5V 专用充电Apple 1A2.7V2.0ViPhone 早期设备Apple 2.4A2.7V2.7ViPad/大电流设备D/D- 的判定用 ADC 一次就能完成两脚压差小于 50mV 且都大于 0.4V说明被短接判为 DCP 或 Apple 型D 有电压而 D- 接近 0V则继续监听 D 是否稳定在 0.6V 附近。读取顺序很关键必须先让两个引脚处于高阻态再采样充电器自己接的下拉电阻会把 D 的真实电平拉低0.6V 的握手电平可能被读成 0.3V。我一般用模拟开关先把 D/D- 全部切到高阻等 10ms 待线上电平稳定后再启动 ADC。提示做 Type-C 口时QC/PE 协商逻辑不变但必须先正确配置 CC 引脚让 VBUS 建立再开始 D/D- 采样CC 未配置时不少设备根本不会把 D/D- 接进 SoC。4.2 D/D- 复用电路模拟开关加电阻网络的常用接法一个通用充电器要兼容 DCP 短接、QC 电平、Apple 分压三组状态D/D- 线上至少需要三个通路短接通路、电平输出通路、ADC 采样通路。常见做法是每根线用一个双路 SPDT 模拟开关TS3A5223 或 CD4053公共端接连接器常开端分别接分压网络和 ADC 采样点常闭端接 DCP 短接电阻。开关要选导通电阻低于 1Ω 的型号把它放在连接器 D/D- 焊盘 3mm 以内否则分压精度会受线路阻抗影响。分压网络我一般这么算0.6V 从 3.3V 取用 33kΩ 串联 7.5kΩ 对地分压空载输出约 0.61V误差 10mV3.3V 档直接切到 3.3V 电源串联一个 220Ω 电阻限制短路电流。Apple 的 2.7V/2.0V 同理用两组分压但要求 D/D- 同时输出特定电平不能只做单侧。所有分压电阻用 1% 精度温漂按 ±50ppm 选保证 0.6V 档在 -20℃85℃ 范围内不越过 0.25V0.95V 的判定窗口。4.3 一轮识别状态机的转移顺序与超时回退状态机是充电识别的核心。我维护一个三状态轮询环DCP 默认态 → QC 监听态 → PE 监听态 → 回到 DCP。每个状态都有超时超时后无条件回 DCP因为 DCP 5V 是任何设备都能安全充电的兜底形态。typedef enum { ID_DCP_DEFAULT, ID_QC_LISTEN, ID_PE_LISTEN, } id_state_t; void charger_id_loop(void) { switch (g_id_state) { case ID_DCP_DEFAULT: switch_dpdm(SW_SHORT); /* D/D- 短接, 5V */ if (dp_voltage_near(0.6f, 150)) { /* D 出现 0.6V 迹象 */ g_id_state ID_QC_LISTEN; } break; case ID_QC_LISTEN: switch_dpdm(SW_HIZ); /* 释放短接, 暴露真实电平 */ if (adc_read_dplus() 450 adc_read_dminus() 200) { qc2_select_class(QC_CLASS_9V); /* 进入 QC 档位协商 */ g_id_state ID_DCP_DEFAULT; /* 协商完回到默认监听 */ } else if (timeout_2s()) { g_id_state ID_PE_LISTEN; } break; case ID_PE_LISTEN: if (pe_count_edges(current_buf, PE_BUF_LEN) 0) { pe_step_up_voltage(); /* 每个有效边沿 0.5V */ } else if (timeout_3s()) { g_id_state ID_DCP_DEFAULT; /* 无信号回 5V */ } break; } }状态机里有两个容易写错的地方。第一从 DCP 切到 QC 监听前必须先断开 D/D- 短接并延迟 5ms 以上否则短接电阻还在线上D 的 0.6V 会同时出现在 D- 上充电器应答时的短接就分不清是本来短接还是握手应答握手永远完不成。第二QC 协商成功后要回到 DCP 默认态继续监听不要停在 QC 状态QC 设备切换档位后会释放 D/D-此时再读电平反而像普通 DCP停住只会把后面 PE 设备的识别窗口堵死。5. 快充协议识别失败的排错顺序示波器判据与关键参数验证5.1 三路信号同时抓VBUS、D、D- 的时序对应关系调快充握手示波器比 USB 电表有用得多。通道 1 接 D通道 2 接 D-通道 3 接 VBUS触发源设在 VBUS 上升沿时基 500ms/div用真机触发一次完整 QC2.0 握手。正确波形应该是D 先出现约 1.3s 的 0.6V 平线然后 D- 被拉高到与 D 相等应答短接随后 D 跳到 3.3V、D- 停在 0.6VVBUS 从 5V 直接跳到 9V。D 平线只持续几百毫秒就消失说明设备侧提前释放了 DD- 一直跟不上 D优先查充电器内部短接 D/D- 的 MOSFET 是否真的导通。QC3.0 的判据不同VBUS 不是一跳到位而是一串 200mV 台阶。500ms/div 时台阶密集得像斜坡把时基切到 5ms/div 就能数个数数到 20 个台阶后稳定在 9VINOV 调压就是成功的。PE 设备则看不到 D/D- 任何动作只能用电流钳夹 VBUS 线数 500ms 窗口内的拉载脉冲数脉冲数与代码计到的边沿数一致检测逻辑才算没白做。5.2 三个高频失败点电平偏移、电容过大、顺序颠倒第一个高频失败是 0.6V 电平偏移。DAC 输出 0.6V 时D 线上若并着 TVS 漏电流或模拟开关漏电流实际电压掉到 0.5V 以下通常还在 0.25V 下限之上能勉强握手更危险的是 3.3V 档经过长线缆到充电器侧只剩 2.9V仍高于 2.6V 判决门限但如果 ADC 参考电压选成 2.5V 就直接超量程。参考电压必须高于 3.3V并做一对一校准。第二个高频失败是 D/D- 线上电容过大。对地电容总和超过 1000pF 时0.6V 上升沿变成十几毫秒的斜坡1.25s 持判据被斜坡吃掉一大段握手时好时坏。用 LCR 表在连接器处测 D/D- 对地电容正常在 100400pF超标时摘掉多余滤波电容D/D- 上不要放超过 100pF 的电容。第三个高频失败是顺序颠倒——先升压再握手或先接大负载再协商。示波器显示升压成功但电流为零最常被忽略的原因是假负载吸了太多电流充电器在握手阶段就进入过流保护。正确验证顺序是先空载完成 9V 握手再切电子负载 CC 模式从 100mA 逐步加到额定值每加一次观察 VBUS 是否回落。一加 500mA 就掉回 5V说明过流阈值没有按新档位重算回查电源方案 OCP 设置比继续调协议更有效。最后给一个能省半天时间的技巧用电子负载固定 100mA 做假负载写一个 3 秒自动循环的握手程序握手→切 9V→回 5V→再握手循环 50 次全部成功后再接真机。真机与假负载最大的区别是瞬间拉载真机可能在握手成功同一毫秒吃掉 2A 电流电源环路响应慢的充电器会被打出振荡表现为 9V 档纹波超过 200mV。这个问题根不在协议而在电源环路相位裕度把示波器切 AC 耦合看 VBUS 纹波即可确认。本文还有配套的精品资源点击获取