简介:这份PDF文档是NXP S12SPIV3手册的中文翻译版,面向使用MCU进行同步串行通信开发的嵌入式工程师、学生与自学者,主要解决SPI协议英文资料阅读门槛高、寄存器配置细节查阅不便的问题。压缩包仅含1个PDF文件,大小约641KB,便于随查随用。内容围绕SPIV3模块展开,先概述SPI主/从模式、准模式、从选择输出、双缓冲数据寄存器、串行时钟极性与相位可编程、模式故障标识等特性,再梳理运行、等待、停止三种操作模式及低功耗控制要点;同时逐一解释MOSI、MISO、SS、SCK四个外部信号的方向与用途,并结合方框图说明状态、控制、数据寄存器、转换逻辑、波特率发生器和主从控制逻辑。文档还给出内存映射表,并对SPICR1、SPICR2、SPIBR、SPISR、SPIDR等寄存器的地址、访问权限和逐位定义进行说明。已有4810人学习,适合作为SPI接口调试、寄存器配置和协议复习时的中文速查材料。
1. 四根线跑全双工:SPI 把可靠性押在了物理层
很多人第一次看 SPI 时序图会觉得这套协议"简陋得不像话":没有地址帧、没有起始位、没有应答位、没有校验,连"从机是否在线"都无从得知。可它偏偏是板级通信里最耐用的那一种。反直觉的地方在于,SPI 把通常由协议层承担的责任,全部下推给了电气与时钟——SS 片选决定此刻谁有权驱动 MISO,SCK 的边沿决定数据在哪一刻被采样,主机与从机各自一个 8 位移位寄存器串成 16 位环,发送和接收是同一个移位动作的两面。理解了这一层,示波器上那些看起来像玄学的错位、丢位、慢一拍,就都能落到具体的位和边沿上。这份 SPIV3 中文手册的价值正在这里:它把寄存器位、时序边界、低功耗模式下的例外行为一条条摊开,是排障时真正能对着看的底图。
2. 分布式 16 位移位寄存器:一次写 SPIDR 到底发生了什么
2.1 两个 8 位寄存器怎么拼成一个环
SPI 全双工的本质,用一句话概括:发送和接收不是两个动作,而是同一个移位动作的两端。主机把自己的 SPIDR(8 位)和从机的 SPIDR 通过 MOSI、MISO 两条线首尾相连,拼成一个分布式 16 位移位寄存器。主机在 MOSI 上推出 1 位的同时,从机在 MISO 上推回 1 位,两边的数据在同一个 SCK 边沿上各前进一格。8 个 SCK 周期之后,主机 SPIDR 里装的是从机原来写进去的字节,从机 SPIDR 里装的是主机写进去的字节——一次完整的交换。
这个模型解释了两件在日常开发里反复撞见的事。第一,SPI 没有"只发"或"只收"。你只想发一帧命令、不关心回什么,硬件依然会在 MISO 上收进 8 位,通常是从机在空闲时输出的一串无效电平;反过来,你只想读一个传感器寄存器,也必须往 MOSI 上推一个 dummy 字节,因为时钟是你自己发的,不推数据就没有 SCK,从机也就不会把数据移出来。第二,SPI 的数据长度默认是 8 位,多字节传输靠软件连续写 SPIDR 完成,硬件不负责组帧,也不负责告诉你"这是一帧的第几个字节"。协议语义全部在软件里,这是 SPI 灵活性的来源,也是它容易被写错的原因。
还有一个细节常被忽略:SPICR1 里有一位 LSBFE,控制先移高位还是先移低位。手册特别强调,LSBFE 不改变数据在寄存器里的位置,读写 SPIDR 永远是从 bit7 的 MSB 开始组织,LSBFE 只影响移出移位寄存器的顺序。这一点在对接某些低位优先的外设时非常关键——如果你按"低位优先就得把数据倒过来写"的思路处理,波形会全错。
2.2 双缓冲寄存器与 SPTEF/SPIF 的握手
SPIDR 在地址表里只占 0x0005 一个字节,但物理上是两个寄存器共用一个地址:写访问落到发送数据寄存器,读访问落到接收数据寄存器。这就是所谓双缓冲。双缓冲的意义是让 CPU 在上一字节还在移位的时候,就把下一字节塞进发送缓冲,从而做到背靠背连续传输,中间不留气泡。
围绕这两个缓冲,硬件提供了两个状态位:
| 状态位 | 所在寄存器 | 含义 | 清除方式 |
|---|---|---|---|
| SPTEF | SPISR bit5 | 发送数据寄存器为空,可以写入新数据 | 读 SPISR 且 SPTEF=1,随后写 SPIDR |
| SPIF | SPISR bit7 | 接收数据已复制到 SPIDR | 读 SPISR 且 SPIF=1,随后读 SPIDR |
这里的清除序列是硬件设计里最容易被写错的地方。手册写得很直白:只有先读到 SPTEF 为 1,随后对 SPIDR 的写操作才有效;如果读到的 SPTEF 不是 1,这次写会被直接忽略,不报错、不置标志,数据就这么无声无息地丢了。SPIF 同理,它是一个"读状态寄存器 + 读数据寄存器"的两步序列,只读数据不清标志,只读状态也不清标志。
下面这段轮询收发是这套握手最直白的落地:
/* SPI 基地址由板级头文件给出,SPI_SR/SPI_DR 分别映射到 SPISR 与 SPIDR */ uint8_t spi_xfer(uint8_t tx) { /* 第一步:等发送缓冲空。这一步的读操作同时是 SPTEF 清零序列的前半段 */ while ((SPI->SR & SPI_SR_SPTEF) == 0) { /* 若这里长时间不返回,优先查 SPE 是否为 1、MSTR 是否与预期一致 */ } /* 第二步:写入待发送字节。硬件会在半个 SCK 周期后启动移位 */ SPI->DR = tx; /* 第三步:等接收完成。SPIF=1 表示 8 位已全部移入接收缓冲 */ while ((SPI->SR & SPI_SR_SPIF) == 0) { /* 从机模式下若 SS 被拉高,这里会永远等不到,务必先确认片选 */ } /* 第四步:读 SPIDR,取回从机数据,同时完成后半段清零序列 */ return SPI->DR; }这段代码的两个while不是可有可无的保险,而是协议的一部分。第一步的读 SPISR 承担了"申请写权限"的语义,第三步的读 SPISR 承担了"确认接收完成"的语义。把它们省掉、改成延时等待,是很多血泪经验的起点——在低速下能跑,一旦总线时钟提上去,丢字节的概率立刻上来。
还有一个坑藏在 SPIF 的服务时机里。手册明确说明:如果 SPIF 在下一次传输结束前没有被服务(标志一直挂着),后一次传输的数据不会被复制到 SPIDR,这次传输被忽略。也就是说,SPI 的接收缓冲只有一级,溢出不是覆盖旧数据,而是直接丢弃新数据,并且不给你任何溢出标志。这一点和串口那种带 ORE 标志的外设完全不同,调试时特别容易误判成"从机没发"。
2.3 主机写数据后的半个 SCK 周期
主机模式下,往 SPIDR 写完数据并不会立刻看到 SCK 抖动,硬件会先等半个 SCK 周期,然后才启动时钟。这半个周期不是实现上的偷懒,它同时解决了两件事:一是给 SS 输出留出建立时间,让从机在被选中的状态下迎接第一个边沿;二是给 CPHA=1 的时序格式留出"第一个边沿用于输出首位"的空间。
这半个周期的存在,直接导致了一个常见的测量困惑:用逻辑分析仪抓波形时,从"写寄存器"这条软件标记到第一个 SCK 边沿之间,总有一段对不齐的延迟。它不是中断延迟,也不是总线延迟,而是硬件固有的半周期。把这一点记在脑子里,可以省掉大量在软件里找"为什么慢了一拍"的时间。
3. CPOL 与 CPHA:四种时钟格式到底在哪个边沿采样
3.1 奇数边沿与偶数边沿的分工
SPI 有四种时序格式,由 SPICR1 里的 CPOL 与 CPHA 两位组合而成。CPOL 决定空闲时 SCK 是高还是低,CPHA 决定数据在奇数边沿还是偶数边沿被采样。这两个位的作用经常被说反,正确的分工是:
- CPHA=0:数据在 SCK 的奇数边沿(第 1、3、5…15 个边沿)被采样或输出,在偶数边沿移位。
- CPHA=1:数据在 SCK 的偶数边沿(第 2、4、6…16 个边沿)被采样,在奇数边沿移位。
这里必须提醒一件事:这份中文手册在 SPICR1 的 CPHA 位描述里有一处明显的笔误,把 CPHA=1 也写成了"奇数边",只是括号里给了 2、4、6…16 的编号。理解时应以 1.4.3.2 与 1.4.3.3 两节对时序的文字描述为准,即 CPHA=1 对应偶数边沿采样。这种手册笔误在实际项目中会实打实地让人多调半天,看到位描述和时序描述打架时,永远信时序那一节。
两种格式的差异,用一句更工程化的话说:CPHA=0 是"片选一拉低,首位就已经在线上",CPHA=1 是"先来一个边沿把首位推上线,第二个边沿才开始采"。前者适合那些片选有效后就立刻输出首位的从机,后者适合那些需要先看到时钟才肯输出数据的从机。主机和从机的 CPOL、CPHA 必须完全一致,否则采到的就是相邻位的错位数据——表现为读回来的值像是整体左移或右移了一位。
CPOL 本身不影响传输格式,只影响空闲电平。四种组合在实际项目里常被叫作 Mode 0 到 Mode 3,其中 Mode 0(CPOL=0,CPHA=0)和 Mode 3(CPOL=1,CPHA=1)用得最多。手册还提到一个实用点:有些系统会在两次传输之间临时改变相位和极性,以便同一个主机对接要求不同的多个从机。这种做法可行,但有代价——见 4.3 节,改这些位会中止当前传输。
3.2 SS 抖动、连续传输与背靠背
从机模式下,SS 不只是"选中我"这么简单,它还直接控制着移位寄存器的行为。手册里有两句话值得反复读:
第一,SS 为高时,SCK 输入被忽略,不发生内部移位。也就是说从机不需要判断"时钟是不是给我的",片选没拉低,时钟来了也不动。
第二,更反直觉的一条:CPHA=0 时,如果连续传输中 SS 一直保持低电平没有断开,SPIDR 里的内容不会被发送,从机发送的是上一次接收到的内容。原因是此时移位寄存器的输入来自上一轮的环回结果,而不是新写入的 SPIDR。要让新数据真正上线,SS 必须拉高至少半个 SCK 周期的空闲时间,让内部状态复位。主机侧同理,SSOE 使能时,SS 输出在连续传输中也要断开一个最小空闲时间。
这条规则解释了一个经典的翻车现场:CPHA=0 的从机,主机连着发两个字节,第二个字节读回来是第一字节的回环值。软件上看着一切正常,SPIF 也置了,数据就是不对。CPHA=1 没有这个限制,SS 可以一直保持低电平做背靠背传输,所以手册直接建议——单主单从系统优先选 CPHA=1。
3.3 模式故障 MODF:把主机强行降级为从机
SPI 只有一种错误状态:模式故障。它的触发条件很朴素——SPI 配置为主机,且 MODFEN 使能,此时 SS 输入被拉低。SS 在主机模式下本来是输出(片选别人),现在变成一个低电平输入,唯一合理的解释就是总线上还有另一个主机在同时驱动 MOSI 和 SCK。这是硬件层面的总线争用检测,没有软件参与。
检测到之后,硬件的反应是立即且不可协商的:MSTR 位自动清 0,SPI 从主机切换成从机;SCK、MOSI、MISO 三个引脚强制为高阻输入,避免与另一个主机硬碰硬;正在进行的传输立即中止,SPI 进入空闲态。如果 SPIE 使能,还会发起一次中断。清除 MODF 的序列和前面几个标志一样讲究顺序:读 SPISR(此时 MODF=1),随后写 SPICR1。清掉之后,SPI 不会自动回到主机模式,需要软件重新置 MSTR——这个"不自动恢复"的设计是刻意的,避免在两个主机还在争用时反复切换。
SS 引脚的角色由 MODFEN 和 SSOE 两位共同决定,四种组合的行为差异很大:
| MODFEN | SSOE | 主机模式下 SS 的行为 | 从机模式下 SS 的行为 |
|---|---|---|---|
| 0 | 0 | 不用于 SPI | 从机选择输入 |
| 0 | 1 | 不用于 SPI | 从机选择输入 |
| 1 | 0 | 带 MODF 检测的输入 | 从机选择输入 |
| 1 | 1 | 从机选择输出(MODF 被禁用) | 从机选择输入 |
这张表藏着一个绕不过去的取舍:自动片选和总线争用检测不能同时要。SSOE=1 让 SS 变成输出、自动在传输期间拉低,此时模式故障被禁用;想要 MODF 保护,就得 SSOE=0,把 SS 当输入用,片选只能靠软件用普通 GPIO 完成。多主机系统选后者,单主机多从机系统选前者,没有中间路线。
4. 寄存器地图与 SPIBR 分频:0x0000 到 0x0007 里的小世界
4.1 内存映射与访问属性
SPIV3 的寄存器窗口只有 8 个字节,地址偏移从 0x0000 到 0x0007,实际基地址由 SoC 层面定义。窗口虽小,访问属性却不统一,写错方向不会报错,只会静默失效:
| 偏移 | 寄存器 | 访问属性 | 备注 |
|---|---|---|---|
| 0x0000 | SPICR1 | 读/写 | 中断使能、模式、时钟格式、位序 |
| 0x0001 | SPICR2 | 读/写 | 部分位不可写 |
| 0x0002 | SPIBR | 读/写 | 部分位不可写 |
| 0x0003 | SPISR | 只读 | 写入被忽略 |
| 0x0004 | 保留 | — | 读返回 0,写无效 |
| 0x0005 | SPIDR | 读/写 | 读接收缓冲,写发送缓冲 |
| 0x0006 | 保留 | — | 读返回 0,写无效 |
| 0x0007 | 保留 | — | 读返回 0,写无效 |
保留地址读回 0 这一点在调试时有实际价值:如果你读 0x0004 得到的不是 0,说明基地址算错了,或者总线时序有问题,问题不在 SPI 模块本身。SPISR 只读这一点也值得强调——试图通过写 SPISR 去清标志是无效操作,所有标志的清除都依赖"读状态寄存器 + 读/写数据或控制寄存器"这种序列,硬件用访问顺序而不是写操作来表达意图。
SPICR1 里真正会咬人的位有这么几个:SPE(系统使能,清 0 会强制空闲并复位状态位)、SPIE(SPIF 或 MODF 触发中断)、SPTIE(SPTEF 触发中断)、MSTR(主从选择)、CPOL/CPHA(时钟格式)、SSOE(片选输出使能)、LSBFE(位序)。SPICR2 里则是 MODFEN(模式故障使能)、BIDIROE(双向模式输出使能)、SPISWAI(等待模式停时钟)、SPC0(双向引脚配置)。
SPC0 值得单独说。置 1 之后 SPI 进入双向模式,只用一根数据线:主机模式下 MOSI 变成 MOMI(双向数据口),MISO 不再用于 SPI;从机模式下 MISO 变成 SISO,MOSI 不再使用。方向由 BIDIROE 控制。这个模式在引脚紧张的封装上很实用,但有两点要注意:一是双向模式下同一根线既发又收,外部必须有合适的驱动能力配合;二是如果主机双向模式下发生 MODF,SPI 会自动切成从机,此时被 SPI 占用的是 MISO 而不是 MOSI,如果 MISO 原本被别的功能借用,就会产生冲突。手册专门为这一点写了提示,说明它在实际硬件上真的撞过。
4.2 波特率:为什么公式长成 (SPPR+1)·2^(SPR+1)
SPIBR 只用 6 位,分成两组:SPPR[2:0] 是预分频,SPR[2:0] 是选择位。分频因子的公式是:
BaudRateDivisor = (SPPR + 1) * 2^(SPR + 1) BaudRate = BusClock / BaudRateDivisor代入验证一下:SPPR=000、SPR=000 时,分频因子 = 1 × 2¹ = 2,25 MHz 总线出 12.5 MHz;SPPR=001、SPR=000 时,2 × 2 = 4;SPPR=010、SPR=000 时,3 × 2 = 6;SPPR=111、SPR=111 时,8 × 2⁸ = 2048,25 MHz 出 12.21 kHz。
这个结构的设计动机很清晰:单靠 2 的幂分频,能得到的频率只有 12.5M、6.25M、3.125M 这串等比数列,中间全是空洞。加上一个 1 到 8 的预分频,就能做出 6、10、12、14 分频这类非 2 的幂结果,让波特率更贴近外设的实际上限。比如某个从机最高只支持 5 MHz,纯 2 的幂只能退到 3.125 MHz,浪费带宽;用 6 分频能拿到 4.167 MHz,更接近上限。
/* 根据目标波特率反算 SPPR 与 SPR,返回最接近且不超过目标值的分频配置 */ uint16_t spi_calc_divisor(uint32_t bus_clk, uint32_t target_baud) { uint16_t best_div = 0; uint32_t best_err = 0xFFFFFFFF; for (uint16_t sppr = 0; sppr < 8; sppr++) { for (uint16_t spr = 0; spr < 8; spr++) { /* 分频因子 = (SPPR+1) * 2^(SPR+1) */ uint16_t div = (sppr + 1) << (spr + 1); uint32_t baud = bus_clk / div; /* 只接受不超过目标的配置,误差取绝对值最小 */ if (baud <= target_baud) { uint32_t err = target_baud - baud; if (err < best_err) { best_err = err; best_div = (sppr << 4) | (spr << 1); } } } } return best_div; /* 高 3 位是 SPPR,低 3 位是 SPR,可直接写入 SPIBR */ }这段反算里有个容易忽略的约束:分频因子越大,波特率越低,但从机的建立时间要求不会因为降速而消失。降速只能解决采样窗口太窄的问题,解决不了信号完整性问题。另外,波特率发生器只在主机模式且传输进行时激活,其余时间驱动被关闭以降低静态电流——这也意味着,从机模式下 SPIBR 的配置基本没有意义,时钟是从外面进来的。
4.3 改配置位为什么会中止传输
主机模式下,改 CPOL、CPHA、SSOE、LSBFE、MODFEN、SPC0、BIDIROE(SPC0 置起时)、SPPR、SPR 中的任何一位,硬件都会立即中止当前传输并强制 SPI 进入空闲态。手册对此有一句很重的提醒:远程从机无法检测到这种情况,所以主机必须自己保证从机也回到空闲。
这个行为的动机不难理解:这些位直接改变移位的节拍和方向,传输中途改掉,主从两边的位计数就对不上了,与其产生一段无法解释的垃圾数据,不如直接中止。但后果是,那些"传输途中顺手改个分频"的代码会在高速下随机丢帧,而且丢得毫无规律,看起来像玄学。
正确的做法是把所有配置变更收敛到传输开始之前,传输过程中只碰 SPIDR 和状态位。如果确实需要在运行中换配置(比如同一条总线上挂要求不同的从机),必须显式地把 SS 拉高、等待足够长的空闲时间、改配置、再重新拉低片选。这段"关总线—改配置—开总线"的序列,最好封装成一个函数,别散落在业务代码里。
5. 避坑:SPI 调试台上最常见的五个翻车现场
5.1 时序类的三个坑
坑一:从机永远返回 0xFF 或 0x00。现象是主机这边 SPIF 正常置位、时序也跑完了,读回来的值恒定为全 1 或全 0。原因通常有三层:一是 CPHA 配错,主机在从机还没把首位推上线的时候就去采样,采到的全是空闲电平;二是 SS 压根没拉低,从机按规则忽略 SCK,移位寄存器不动,MISO 保持高阻,被上拉拉成全 1;三是从机的 SPE 没置位,引脚还没切给 SPI 功能。排查顺序建议从 SS 开始,用示波器确认片选真的到了从机引脚,再对 CPHA,最后查从机的使能位。全 0 和全 1 的差别也有信息量:全 1 更像上拉,全 0 更像被主动驱动为低。
坑二:连续传输时数据慢一拍。现象是连发两个字节,第二帧读回来的却是第一帧的回环值。根因就是 3.2 节那条规则——CPHA=0 且 SS 一直保持低电平,从机不会发送 SPIDR 里的新内容,而是重复上一轮收到的数据。解决办法有两条:要么在两次传输之间把 SS 拉高至少半个 SCK 周期,要么改用 CPHA=1 做背靠背传输。前者改动小,后者效率高,看外设支持哪种。
坑三:主机莫名变成从机,MSTR 自己变 0。现象是跑着跑着 SPI 不工作了,读 SPICR1 发现 MSTR 被清 0,SPISR 里 MODF 置位。原因是 SS 引脚在主机模式下被拉低,触发了模式故障保护。常见诱因是 SSOE=0 却把 SS 配置成了带 MODF 检测的输入,而这根线在板子上悬空或者被别的器件拉低;也可能是多主机系统里真的发生了总线争用。处理方式是先判断这是误触发还是真故障:单主机系统里基本是误触发,把 MODFEN 清 0 或者改用 SSOE=1 的自动片选;多主机系统里就是真故障,需要按 3.3 节的序列清标志并重新仲裁。
5.2 寄存器握手类的两个坑
坑四:写 SPIDR 没反应,SPTEF 一直不清。现象是调用了发送函数,波形上什么都没有,SPTEF 读回来一直是 0。原因是没有遵守"先读 SPISR 且 SPTEF=1,再写 SPIDR"的顺序。有些代码为了省事,直接写 SPIDR 然后轮询,硬件会把这次写静默丢弃。还有一种变体是中断里写、主循环里也写,两处竞争同一个发送缓冲,其中一次的读-写序列被另一次打断,同样会丢。解决办法是把发送动作收口到一个函数里,进出临界区,别在多个上下文里同时碰 SPIDR。
坑五:低功耗唤醒后第一个字节是旧数据。现象是系统从等待或停止模式醒来,读到的第一个字节是进入低功耗之前的老数据,或者干脆没有产生 SPIF。原因在 1.4.8 节的注意事项里写得很细:从机在等待模式下,移位寄存器可能还在跟着主机的 SCK 走,但移位寄存器的内容要等退出等待或停止模式之后才会复制到 SPIDR,SPIF 也是那时候才产生。更微妙的是,只有"传输期间"进入或退出等待模式才会触发这次复制;如果从机是从空闲态进入等待、再从等待回到空闲,既不产生 SPIF 也不复制 SPIDR。所以唤醒后第一件事不是读数据,而是先确认当前是否处在一个字节的传输中间。
6. 低功耗与中断的取舍:从机为什么在等待模式还要多收一个字节
等待模式下的 SPI 行为,是这份手册里最容易被跳读、又最容易在真实项目里出事的一段。SPISWAI 置 1 后,主机进入等待模式会停掉 SCK,传输冻结,退出后继续;但从机的行为不一样——它会继续接收和发送一个字节,然后才停下来。
这个"多收一个字节"看着多余,其实是 SPI 从机架构决定的无选择。从机没有独立时基,它完全是被动器件,靠数 SCK 边沿来确定当前移到了第几位。如果在一个字节的中途把时钟掐掉,等系统醒来,位计数和主机那边就对不上了,整个帧的字节边界全废。硬件能做的只有一件事:把当前这个字节走完,让移位寄存器的边界重新对齐到字节。代价是功耗略高一点,以及一个更隐蔽的后果——SPIF 不会立刻产生,移位寄存器的内容要等退出等待或停止模式之后才复制进 SPIDR。如果软件在唤醒后立刻读 SPIDR,读到的可能是上一轮的残值。
第二个取舍在中断结构上。MODF、SPIF、SPTEF 三个标志是逻辑或的关系,共同产生一个中断请求。这省下了一个中断向量,代价是中断服务程序必须自己读 SPISR 分辨是哪一位触发的,而且要小心处理"清除一个标志时顺带影响了另一个"的情况。相比之下,如果三个标志各有独立向量,代码会更直白,但向量表和优先级仲裁的硬件开销就上去了。这个模块选择了省硬件、把复杂度交给软件,属于典型的嵌入式取舍。
验证这套行为,最靠得住的办法不是打印日志,而是用一根空闲 GPIO 在进出低功耗的前后翻转电平,再用逻辑分析仪同时抓 SCK、SS 和这根标记线。这样能直接看到"停在了第几个边沿""醒来后第一个字节是从哪来的",比在代码里猜快得多。
我自己的教训是:早期做一个低功耗采集节点,从机在等待模式醒来后总是丢第一帧,查了两天才发现问题不在驱动,而在于唤醒后立刻读 SPIDR 的那个瞬间,数据还没从移位寄存器复制过来。从那以后我每次写低功耗相关的 SPI 代码,都强制在唤醒后先轮询一次 SPISR 确认 SPIF 的真实状态,再动数据寄存器——这一步看着冗余,却能省掉大量在深夜里对着波形图怀疑人生的时间。希望帮到你。
本文还有配套的精品资源,点击获取