news 2026/9/8 20:07:15

深入拆解USB协议:从系统架构到端点通信的完整技术解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入拆解USB协议:从系统架构到端点通信的完整技术解析

1. 写在前面:为什么USB值得花一整篇文章来拆

做嵌入式或者电脑周边开发的朋友,应该都有过被USB折腾到怀疑人生的时刻。插上设备没反应、枚举失败、传输超时、带宽不够用……这些问题背后,其实都是对USB协议本身理解不够深。我最早接触USB是在做单片机项目的时候,当时只有一个模糊的概念:USB就是那个方口或者扁口的插头,插上就能用。等到真正去读协议文档、调端点、抓包分析的时候,才发现这里面藏着一整套精巧的设计逻辑。

这是USB协议系列解读的中篇,前一篇大概讲清楚了USB出现的背景和整体定位——它为什么能取代一大堆并口、串口、PS/2接口,靠的无非是三板斧:高速、可扩展、即插即用。这一篇我们往深处走一走,把USB的历史脉络、系统架构、传输模型和端点通信机制串起来讲透。我知道很多人看USB的资料都会卡在“端点”“管道”这些抽象概念上,所以这篇文章尽量避免教科书式的罗列,尽量用做项目的视角来理解协议设计者的思路。

适合谁看?正在调USB驱动却搞不懂枚举流程的嵌入式工程师,准备用USB做高速数据传输的硬件开发者,以及纯粹想搞明白“为什么USB这么复杂但又这么好用”的技术爱好者。读完这篇文章,你能建立起一个完整的USB通信模型,知道设备插上之后从硬件到软件发生了什么,也能看懂端点描述符里每个字段到底在说什么,到了排查问题的时候至少知道该往哪个方向查。

2. 从USB 1.0到USB4:一条接口的进化史

2.1 低速、全速、高速:每一代USB解决什么问题

USB协议从1996年正式发布1.0版本到现在,差不多快三十年。这期间版本号看着多,但核心演进逻辑其实很清晰:每一次版本升级,都是在解决当时最痛的问题。

USB 1.0/1.1时代,传输速率只有1.5 Mbps(低速)和12 Mbps(全速)。今天看来这个速度慢得离谱,但放在当时,它要替代的是传统的串口和并口,12 Mbps已经比串口的115200 bps快了一百倍。低速模式是给鼠标键盘这类交互设备准备的,为什么单独搞一个低速模式?因为这类设备数据量极小,不需要那么高的速率,低速模式可以用更便宜的线缆和连接器,而且对电磁干扰的容忍度更高,生产成本能压下来。全速模式则面向打印机、扫描仪、音频设备,12 Mbps足够传送一张A4纸的扫描图像,也足够承载CD音质的音频流。

USB 2.0在2000年发布,把速率提到了480 Mbps,叫高速模式。这个版本解决的核心痛点是存储设备。当时U盘、移动硬盘开始普及,12 Mbps传一个512 MB的文件要七分钟,根本没法用。480 Mbps把时间缩短到十秒左右,存储类设备才真正在PC上站稳脚跟。注意一个细节:USB 2.0的480 Mbps理论值,实际有效带宽大概只有320-400 Mbps,因为协议本身有开销(令牌包、握手包、帧间隔时间都是要占带宽的),后面讲事务处理的时候会展开。

USB 3.0在2008年发布,速率跳到了5 Gbps,叫超速模式。这一代不只是速率提升,物理层变了——增加了额外的差分数据对,从半双工改成了全双工通信,意味着可以同时收发数据。USB 3.0解决的是高清视频、大容量固态硬盘这些动辄几个GB的数据传输场景。之后USB 3.1把速率翻倍到10 Gbps,USB 3.2又合并了多通道模式达到20 Gbps,命名上也搞出了一堆SuperSpeed+的变体。

2.2 USB4和Type-C:归一化是终点吗

USB4在2019年发布,直接把速率干到了40 Gbps。这一代的技术底座是Intel贡献的Thunderbolt 3协议,所以它不仅仅是USB了,还兼容PCIe和DisplayPort隧道传输。一个Type-C口输出视频信号、传输数据、供电三合一,这种能力在USB4时代才算真正成熟。

Type-C连接器其实是和USB协议演进并行的一条线,它的创新在于:正反可插、支持最高100W供电、承载所有USB速率模式和Alternate Mode。很多人在实际项目里会混淆Type-C和USB版本的对应关系——Type-C只是物理连接器形状,它既可以是USB 2.0的速率,也可以是USB4的速率,取决于CC逻辑芯片和线缆里的E-Marker配置。这也是很多硬件工程师踩坑的地方:画了个Type-C座子,以为就支持USB 3.0了,结果只接了D+/D-两根线,速率跑在全速12 Mbps上,找半天问题最后发现是线序接错了、CC电阻没配。

讲历史不是为了背年份,而是为了理解一个关键事实:USB是一个向后兼容的协议,但也因为兼容性背负了巨大的复杂度。USB 2.0设备插到USB 3.0端口上能正常工作,那是因为端口在发现设备不支持SuperSpeed连接时会自动回退到高速模式。这一套协商机制,从物理层的电气特性到协议层的数据传输模式,全都是预先设计好的,也是下文要讲的架构设计的起点。

3. USB系统架构:主机、设备与Hub的三角关系

3.1 主从模式:为什么USB不像以太网那样对等通信

USB采用的是严格的主从架构,这一点和以太网很不一样。以太网上每个节点是对等的,随时可以发包;USB则规定:所有通信必须由主机发起,设备永远是被动的一方,不能主动向主机发送数据。

为什么这么设计?想想USB的两种替代对象就明白了。串口是一对一通信,两台设备对等,但协调起来麻烦;并口虽然可以做双向,但信号线太多,容易互相干扰。USB要把通信扩展到一主机多设备,同时还要管理设备热插拔,集中式仲裁是当时最务实的选择——由主机统一调度,就避免了多个设备同时抢占总线的冲突问题。代价是设备端的设计更简单(不需要复杂的冲突检测协议),但主机的任务更繁重。

在这个架构里,主机的角色是由**USB主机控制器(Host Controller)**承担的。PC上就是南桥或者CPU里的USB控制器,嵌入式平台上则是MCU的USB OTG外设或者独立USB PHY。主机控制器负责:检测设备插拔、管理设备地址、调度总线上所有的数据传输、处理错误和恢复。

3.2 设备、Hub与拓扑:七层葫芦娃结构

USB的物理连接拓扑是一个分层的星型结构,以主机控制器为根,通过Hub向下扩展,最多可以级联七层(包括根Hub),最多连接127个设备。这个127不是随便定的,因为设备地址字段只有7位,从0到127,地址0保留给未配置的设备,所以实际可用是1到127,共127个。

Hub在整个架构里不只是个“排插”,它承担了:总线电源管理、下行端口的状态检测、低速/全速/高速信号的中继和速度协商。当一个新的设备插入Hub的下行端口,Hub检测到D+/D-线上的上拉电阻信号(低速设备上拉在D-,全速/高速设备上拉在D+),会通知主机“有设备插入了”。这个通知是通过Hub自己的中断端点上报的,主机收到后再发起枚举流程。

这里有个嵌入式开发容易忽略的点:7层拓扑是包括根Hub的传输延时在内的最大层数。每个Hub都会引入一定延迟,协议规定整个路径的往返延迟不能超过一定值,否则时序就乱了。所以不是你想级联多少个Hub就级联多少个,超过7层USB会直接枚举失败或者通信不稳定。

3.3 角色翻转:OTG和Type-C如何打破主从限制

移动设备的普及催生了**USB OTG(On-The-Go)**协议,它的核心是支持设备在主从角色间动态切换。一个手机既可以作为设备连接PC(从机模式),也可以作为主机读取U盘(主机模式)。

OTG的关键机制是HNP(Host Negotiation Protocol)和SRP(Session Request Protocol)。HNP允许通过数据线的电平时序来协商主从角色,SRP则允许从机主动请求主机开启总线供电。到了Type-C时代,角色协商变得更加灵活,通过CC引脚上的电阻和配置通道通信(PD协议),设备可以在电源角色(Source/Sink)和数据角色(DFP/UFP)之间任意组合。这也是为什么你在做Type-C双角色设备时,CC逻辑电路的设计比USB收发本身还容易出问题。

4. 通信传输模型:帧、微帧与包

4.1 时间基准:帧和微帧怎么划分总线时间

USB传输有一个统一的时间基准,把总线时间分成固定长度的帧(Frame)和微帧(Microframe)。

  • 全速/低速模式:一帧为1 ms,每帧以SOF(Start of Frame)包开始。
  • 高速模式:一帧为125 μs,即1 ms分成8个微帧,每个微帧以SOF包开始。

SOF包的作用是什么?首先是同步——告诉所有设备一帧从此刻开始;其次,SOF本身带有一个递增的帧号,设备可以用它来做同步时钟。设备不能以SOF作为“本次可以传输”的信号,只是时间基准。

帧的划分直接影响带宽分配:等时和中断传输是周期性调度的,每帧或每N帧执行一次;批量传输和控制传输在每帧的剩余带宽里“见缝插针”。理解这个调度模型,对估算USB实际吞吐量很有帮助。

4.2 包的类型与结构:PID如何区分业务

USB总线上最小的数据单位是包(Packet),所有传输(Transfer)最终都拆解成一系列包的交换。包的通用结构是:SYNC同步字段 + PID(Packet ID)+ 数据字段(可选)+ CRC校验 + EOP结束符。

PID(Packet Identifier)只有8位,但实际有效位是4位,另外4位是取反校验。通过PID区分四类包:

PID类型方向常见子类型用途
令牌包主机→设备IN、OUT、SETUP、SOF发起一次事务,指定端点地址和方向
数据包双向DATA0、DATA1、DATA2、MDATA承载实际数据,配合数据翻转机制
握手包双向ACK、NAK、STALL、NYET确认、忙、错误、未就绪
特殊包双向PRE、ERR、SPLIT低速设备前导、分流传输等

**数据翻转(Data Toggle)**机制值得单独说。USB为了保证数据不丢不乱序,在每个端点维护了一个数据翻转位:DATA0和DATA1交替使用。发送方发DATA0,接收方确认后,下一次就发DATA1;如果接收方收到的数据和期望的翻转位不一致,说明丢了包或者重复了,就会丢弃并等待重传。这个机制虽然简单,但实实在在地解决了USB传输的可靠性问题。

4.3 事务:一次有来有回的数据交换

USB事务(Transaction)由三个阶段组成,不是所有事务都有三个阶段,但基础模型是:

  1. 令牌阶段:主机发送令牌包,告诉目标设备“我要做什么”(IN/OUT/SETUP)以及目标是哪个端点。
  2. 数据阶段:根据令牌类型,主机或设备发送数据包。数据包的大小受端点最大包大小限制。
  3. 握手阶段:接收方返回握手包,ACK表示接收成功,NAK表示“我暂时忙”,STALL表示“端点出错了”。

一个完整的批量传输场景是这样的:主机想向端点1发送512字节数据,端点最大包大小为512字节,那么——主机发OUT令牌,然后发DATA0数据包(512字节),设备收到后回ACK。这就完成了一次事务。如果数据是1024字节,那就得分两次事务:第一次DATA0,第二次DATA1,而且这两次事务之间是独立的,由主机的调度器决定什么时候发第二次。

注意一个关键概念:一次事务只对一个端点有效,端点通过令牌包里的端点号和方向字段唯一标识。这也是USB能够复用一套物理总线服务多个逻辑数据流的原因。

5. 端点通信机制:数据流的入口与出口

5.1 端点的本质:设备内部的“信箱”

端点是USB设备内部的一个可寻址的数据存储实体,它本质上是一个缓冲区加一组状态位。主机不直接和设备内部内存打交道,它只能读写端点。每个端点有:

  • 端点号(Endpoint Number):0-15,由设备定义。
  • 方向(Direction):IN为设备到主机,OUT为主机到设备。
  • 传输类型(Transfer Type):控制、批量、中断、等时。
  • 最大包大小(Max Packet Size):单次事务能传多少字节。
  • 服务间隔(Interval):对于中断和等时传输,多久调度一次。

端点在设备端是由硬件实现的,MCU里的USB外设通常有几个到几十个端点缓冲区,每个端点对应一组FIFO。写固件的时候配置端点寄存器、设置传输类型、缓冲区大小,这些就是在“布置信箱”。主机那端看到的每个端点都是一个独立的“数据流管道”。

5.2 四种传输类型:控制、批量、中断、等时的取舍

这四种传输类型是USB协议设计的精髓,各解决一类需求:

控制传输(Control):用于设备配置和命令控制,可靠性最高。每个设备必须有一个端点0,只能做控制传输,枚举过程全靠它。控制传输的特点是有固定的流程:SETUP阶段传命令、数据阶段(可选)、状态阶段。它保证可靠交付,但带宽优先级较低。

批量传输(Bulk):用于大量数据可靠传输,比如U盘读写、文件传输。它只在总线空闲时传输,带宽不保证,但能抢到多少就用多少。批量传输有错误检测和重传机制,可靠性高。最大包大小:全速64字节,高速512字节,超速1024字节。

中断传输(Interrupt):名字叫中断,但和硬件中断没关系,其实是保证轮询频率的可靠传输。它适合鼠标、键盘、游戏手柄等需要周期性上报数据的设备。在高速模式下,中断传输的最小服务间隔是1微帧(125 μs),最大包大小可达1024字节(高速)/3072字节(超速)。

等时传输(Isochronous):用于音视频等实时数据流,没有重传机制,传输带宽有保证,但出错就丢包。它是唯一不保证可靠性的传输类型,但换来的是确定性的带宽和延时。高速下最大包大小1024字节,超速下可达4096字节(USB 3.x)。

选择哪种传输类型,本质上是在可靠性、带宽、延迟、实现复杂度四个维度里做权衡。我做USB音频设备时,音频流用等时传输保证实时性,而控制命令(比如调音量)走控制传输。如果音频流用批量传输,数据不会丢,但一旦总线忙就会产生播放卡顿,体验极差。

5.3 管道:主机视角的逻辑连接

管道(Pipe)是主机软件层面的抽象,表示主机与某个端点之间的逻辑连接。管道有两类:

  • 流管道(Stream Pipe):数据方向单一,连接到一个非控制端点,用于批量、中断、等时传输。
  • 消息管道(Message Pipe):双向的,只能连接到控制端点,传输的是带结构的请求和响应消息。

这个抽象的意义在于:主机驱动只需要和管道打交道,不需要关心物理链路上的具体布线。你可以把管道理解成插座和设备之间的水管,主机往管道里灌水(写数据)、从管道接水(读数据),至于管子里的水怎么流的,协议栈帮你处理了。

配置好一个端点后,设备和主机之间其实就建立了一组管道。配置描述符里的每个接口(Interface)可以包含多个端点,每个端点对应一个管道,而接口本身则对应一个功能(比如摄像头、麦克风、键盘)。

5.4 端点0与枚举过程:设备第一次被认识的关键流程

端点0是每个USB设备出厂时就有的“默认控制端点”,它由USB协议强制规定:最大包大小(全速设备为8/16/32/64字节,高速设备为64字节),方向双向(0号端点的IN和OUT方向共同组成端点0)。在设备没有被分配地址之前,主机只能通过端点0和它通信。

枚举流程是整个USB通信体系里最经典也最容易被忽略的部分,它的完整顺序是:

  1. 设备插入,Hub检测到D+/D-的电平变化,确认有设备接入。
  2. Hub通过状态变化通知主机(中断端点上传端口状态变化)。
  3. 主机向Hub发送端口复位命令,复位后设备地址为0。
  4. 主机向地址0的端点0发送GET_DESCRIPTOR(Device)请求,读取前8字节设备描述符(包含MaxPacketSize字段)。
  5. 主机对设备执行SET_ADDRESS请求,给设备分配一个唯一地址(1-127)。
  6. 主机用新地址重新获取完整设备描述符(18字节),然后依次获取配置描述符、接口描述符、端点描述符等。
  7. 主机根据获取到的描述符加载或选择驱动程序。
  8. 主机发送SET_CONFIGURATION请求,设备进入配置状态,各非0端点开始工作。

枚举过程中的每个步骤都有超时处理,任何一个环节失败,设备都无法正常工作。实际做USB设备时,最常见的枚举失败原因是:设备描述符里的MaxPacketSize和实际端点0缓冲区不匹配、字符串描述符索引超出范围、端点描述符里的wMaxPacketSize超过了硬件限制。

6. 链路层与物理层:从差分信号到高速影响

6.1 差分信号与电气特性:USB为什么能传这么远

USB物理层使用差分信号传输,D+和D-两根线互为参考,接收方检测的是两根线之间的电压差。这个设计的核心好处是抗共模干扰——外部电磁噪声通常会同时影响两根线,但不会改变它们之间的差值,因此差分信号天然比单端信号抗干扰能力强得多。

USB 2.0的高速模式(480 Mbps)信号幅度约400 mV(差分),全速和低速模式约3.3 V。高速模式的信号幅度低,是因为频率高,过大的电压摆幅会导致严重的电磁辐射和信号完整性问题。但低幅度意味着对信号质量更敏感,这就需要更短的线缆长度(USB 2.0规范建议最长5米)和更好的屏蔽。这是我做USB延长线项目时踩过的坑,一开始用普通线缆加延长线到10米,高速设备直接识别不了,后来换成带有源放大器的延长方案才算解决。

USB 3.0以上则在物理层走了另一条路:新增SSTX/SSRX两组差分对,每组都是独立的单向通道,实现全双工通信。所以你看Type-C线缆里USB 3.0以上速率至少要8根数据线(D+/D-、SSTX+/SSTX-、SSRX+/SSRX-),再加上电源和CC线,比传统USB 2.0的4根线复杂得多。

6.2 USB 2.0与USB 3.x的事务模型差异

USB 3.x虽然尽力兼容USB 2.0的软件模型(端点、管道、传输类型这些概念依然保留),但底层事务模型做了不少改动:

  • 从半双工变为全双工,IN和OUT可以同时进行。
  • 引入了流控机制(Credits),接收方通过Flow Control Credit告诉发送方自己能接收多少数据,避免了USB 2.0时代“发送方猛发、接收方狂回NAK”的浪费。
  • 包格式变了:新增了LMP(Link Management Packet)、DPP(Device Notification)等,链路管理从主机集中式变成了点对点对等。

这对驱动开发者的实际影响是:USB 3.x的批量传输吞吐量更容易跑满,因为不需要等传统的ACK/NAK握手来空出总线时间了。但代价是USB 3.x的协议栈复杂度更高,调试工具也更加依赖逻辑分析仪和协议分析仪,普通万用表根本量不出信号问题。

7. 常见问题排查实录:从枚举失败到带宽不够用

7.1 枚举失败的五个常见原因

USB设备开发中,枚举失败占了问题的大半。根据我自己的经验,排查看这几个方向:

现象可能原因排查方式
设备插入后没有任何反应D+/D-上拉电阻缺失或接错用示波器量D+/D-是否有电平变化
枚举超时设备描述符返回超时、端点0缓冲区配错抓USB包看主机发到哪个步骤没响应
SET_ADDRESS后设备丢失地址写错、MCU时钟不稳导致USB PHY未同步检查晶振和PLL配置
无法识别设备(Code 43)设备供电不足、驱动加载失败换带供电的Hub,查描述符合法性
枚举成功但数据传输失败端点描述符与固件配置不匹配核对端点号、方向、最大包大小

注意:调试USB枚举问题,强烈建议一开始就上协议分析仪或者支持USB解码的示波器。靠肉眼猜和反复插拔试错,效率太低。哪怕是便宜的USB分析仪(几百块的逻辑分析仪也能用)都能在枚举失败时看到是哪个阶段断掉了。

7.2 实测数据:USB 2.0批量传输的真实吞吐量

很多开发者在项目里写“USB 2.0高速480 Mbps”,以为每秒能传60 MB,这是不现实的。我实测批量传输的吞吐量大致如下:

  • 理论速率:480 Mbps = 60 MB/s
  • 实际最大有效吞吐:约33-42 MB/s(高速模式下,取决于主机控制器和驱动)
  • 典型批量传输:30 MB/s左右
  • 控制传输:同步操作,速率更低

原因多方面:每传输512字节数据需要约76字节的协议开销(令牌包、握手包、帧间隔),高速模式下每隔125 μs才被调度一次,一微帧内能传多个批量事务,但还是受限于总线的空闲时间。做USB转网卡或者USB转串口应用时,别按理论值去做带宽预算,留30%-50%的裕量才是稳妥的。

7.3 端点配置的一个实战案例

我做了一个USB数据采集卡,要求把模拟信号以24位精度、48 kHz采样率连续上传到PC。算一下带宽需求:24位 × 48 kHz = 1.152 Mbps,加上协议开销,选USB 2.0全速12 Mbps就足够了。但问题来了:等时传输在全速模式下每帧最多1023字节,按需求算每帧要传192字节,可以放下。

我当时的端点配置是:

  • 端点0:控制传输,64字节
  • 端点1 IN:等时传输,192字节,服务间隔1(每帧传一次)

在做固件的时候,要注意等时端点的FIFO必须能在设备被主机访问前把数据准备好,否则主机读到的是旧数据。这里踩过一个坑:DMA配置不当导致两个USB帧之间数据没更新完,音频出现周期性爆音。解决办法是把DMA的传输完成中断和SOF帧同步关联起来,在接收到SOF之前把数据填好。

8. 实操心得:把USB协议讲得一清二楚的三个技巧

做USB项目这几年,我自己总结了一些给新手解释USB协议时特别管用的方法。这套“翻译”思路,面试的时候也救过我。

类比法讲主从架构:USB的主从模式可以类比成公司里只有老板能下达任务,员工不能主动找老板汇报。员工(设备)有事情要说,只能等老板(主机)来“巡视”的时候开口。这就解释了为什么USB设备不能自己发起通信,也解释了为什么中断传输其实不是设备发中断,而是主机定期去“敲门”问有没有新数据。

时序图讲事务:画一个三行的时间轴,令牌、数据、握手三个阶段永久不变。只要懂了“任何通信都是这三步”,后面的各种传输类型不过是排列组合的变体:控制传输是“先SETUP后IN/OUT”,批量传输是“OUT/IN+数据+ACK”,等时传输干脆去掉了握手阶段。

用快递理解端点:端点是邮箱,管道是快递路线。主机投递包裹(OUT)到指定邮箱,设备从邮箱取走;设备要寄包裹则在邮箱里放好,等主机来取(IN)。端点号就是收件人地址,传输类型就是快递方式(普通件、特快件、保价件、Note件)。

9. 最后再说一句

USB协议看着庞杂,但核心逻辑始终围绕三个问题:谁控制总线(主从)、数据怎么编组(包和事务)、数据怎么分流(端点和管道)。把这三件事想透了,USB就从一个玄学变成了一个可推理、可调试的系统。这篇中篇讲的是框架和通信模型,后续如果大家感兴趣,我可以再写一篇专门讲描述符——设备描述符、配置描述符、接口描述符、端点描述符和字符串描述符之间的层级关系,把每个字段的含义、取值规范、以及常见的“不合法描述符”逐一举例子拆开。那部分是把设备跑起来的最后一块拼图,也是很多驱动问题的根源。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 20:05:27

RPCS3汉化配置:3步搞定PS3游戏中文菜单,附踩坑速查表

RPCS3汉化配置:3步搞定PS3游戏中文菜单,附踩坑速查表 【免费下载链接】rpcs3 PlayStation 3 emulator and debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 下载完RPCS3、塞进游戏,结果满屏英文菜单,字体…

作者头像 李华
网站建设 2026/9/8 20:03:20

从Isaac Gym到RK3566:双足机器人强化学习策略的完整部署实践

先交代一下背景:Microduck是一台25厘米左右的小型双足机器人,最初是在英伟达GPU上用强化学习在仿真里练出来的,整套训练流程跑在Isaac Gym这类环境里。这篇文章记录的是我把它从“GPU上的数字模型”搬上RK3566实机(泰山派&#xf…

作者头像 李华
网站建设 2026/9/8 20:02:11

WOA-CNN-LSTM-Attention风电功率预测模型详解与Matlab复现

简介:面向风电功率预测研究与应用,提供一套复现SCI一区论文方法的Matlab源码,基于鲸鱼算法(WOA)优化CNN-LSTM-Attention模型,适合需要开展算法对比、学术复现或毕业设计的科研人员与在校学生。代码采用模块…

作者头像 李华