STM32F4 DCMI驱动OV7725摄像头与SPI LCD实时图像显示实战 📅 发布时间:2026/9/2 14:16:21 👁 浏览次数: 简介本资源是一套基于STM32F4系列微控制器与OV7725摄像头模块的嵌入式图像采集与LCD实时显示完整工程面向嵌入式初学者、课程设计学生及STM32图像应用开发者解决从硬件驱动配置、图像数据同步采集到LCD帧缓冲显示的一体化实践难题。压缩包共170个文件含47个头文件h定义外设寄存器与接口协议、46个源文件c实现OV7725初始化、FSMC/LCD驱动、DMA图像搬运及RGB格式转换等核心逻辑另有编译中间文件o/d、Keil工程配置uvprojx/uvoptx、启动脚本bat及调试输出axf/hex/map等结构完整可直接编译运行包体大小为4.67MB。已有393人学习下载配套代码覆盖GPIO时序适配、OV7725寄存器配置表、LCD分辨率匹配、双缓冲防撕裂显示等关键细节并包含keilkilll.bat等实用工具脚本便于快速清理重建工程是掌握STM32图像系统开发流程的高实用性参考项目。1. 项目概述从零构建一个嵌入式视觉系统最近在做一个需要视觉反馈的小项目核心需求是把摄像头拍到的画面实时显示在一块屏幕上。听起来像是手机或者电脑上很简单的一个功能但在资源受限的嵌入式世界里这其实是一个涉及硬件接口、数据流处理和显示驱动的系统工程。我选择了经典的STM32F407作为主控搭配OV7725摄像头模块和一块常见的SPI接口LCD屏目标就是打通从“看到”到“显示”的完整链路。这个组合在电子爱好者圈子里很常见STM32F4系列性能足够DCMI接口专门为摄像头设计OV7725成本低廉且资料丰富SPI屏则节省IO。但常见不代表简单从硬件连接到软件驱动再到数据搬运和显示优化每一步都有不少细节需要注意。网上能找到的代码片段往往只解决了部分问题或者在不同的硬件平台上无法直接运行。我花了些时间把整个流程重新梳理、调试了一遍最终实现了一个稳定、流畅的图像采集与显示系统。这篇文章我就来详细拆解这个过程。我会从硬件选型与连接讲起然后深入到OV7725的寄存器配置、STM32的DCMI和DMA设置再到LCD的驱动与图像数据格式转换最后分享一些调试过程中遇到的坑和性能优化的技巧。无论你是刚接触嵌入式图像处理的新手还是想为现有项目增加视觉功能希望这篇近万字的实战记录都能给你提供一份可靠的“抄作业”指南。2. 硬件平台搭建接口选择与电路连接要点硬件是地基连接错了软件调得再努力也是白费。STM32F407、OV7725和SPI LCD这三者之间的连接核心在于理解各自的数据接口和通信协议。2.1 核心器件选型与接口分析首先看主控我用的STM32F407ZGT6它自带一个数字摄像头接口DCMI。这是一个并行的同步数据接口可以接收8位、10位、12位或14位的数据流正好匹配大多数CMOS摄像头传感器的输出。如果没有DCMI的型号用普通IO口模拟时序也是可以的但会大量消耗CPU资源帧率和稳定性很难保证。所以强烈建议选择带有DCMI外设的STM32F4系列芯片这是实现高效图像采集的硬件基础。摄像头模块我选的是OV7725一款30万像素640*480的CMOS传感器。它支持输出多种数据格式如RGB565、YUV422接口是标准的SCCB类似I2C用于配置以及并行数字视频输出D[7:0]。市面上常见的模块已经集成了稳压和晶振直接使用即可。这里有个关键点务必确认你手上的OV7725模块输出的是什么数据格式。很多默认是YUV422但我们的LCD屏通常需要RGB565这中间就需要转换。有些高级模块可以通过电阻选择输出格式买的时候要留意。显示部分为了节省IO口和简化驱动我选择了一块2.4寸的ILI9341驱动的LCD屏使用SPI接口通信。SPI屏的优点是接线简单仅需4根线SCK, MOSI, DC, CS外加复位和背光驱动代码编写也相对容易。缺点是刷屏速度比并口屏慢但对于显示OV7725的QVGA320*240或更低分辨率的图像优化后的SPI速度完全可以满足实时性要求。如果你对帧率要求极高可以考虑使用FSMC接口的并口屏但接线和驱动会复杂一些。2.2 具体引脚连接方案连接时可以遵循以下映射关系。注意STM32的引脚有复用功能需要根据数据手册正确配置。OV7725 与 STM32F4 DCMI 连接OV7725_D0~D7-STM32 DCMI_D0~D7(例如PD0-PD7 具体需查手册确保这些引脚属于DCMI数据线)OV7725_PCLK(像素时钟) -STM32 DCMI_PIXCLK(例如PA6)OV7725_HREF(行同步) -STM32 DCMI_HSYNC(例如PA4)OV7725_VSYNC(场同步/帧同步) -STM32 DCMI_VSYNC(例如PB7)OV7725_SIOC(SCCB时钟) -STM32 I2C1/2/3_SCL(例如PB8 配置为I2C)OV7725_SIOD(SCCB数据) -STM32 I2C1/2/3_SDA(例如PB9 配置为I2C)OV7725_RST(复位可选) - 任意GPIOOV7725_PWDN(电源 down 可选) - 任意GPIO通常拉低使能SPI LCD (ILI9341) 与 STM32F4 连接LCD_SCK-STM32 SPI1/2/3_SCK(例如PA5 用于SPI1)LCD_MOSI-STM32 SPI1/2/3_MOSI(例如PA7)LCD_DC(数据/命令选择) - 任意GPIO (例如PB0)LCD_CS(片选) - 任意GPIO (例如PB1)LCD_RST(复位) - 任意GPIO (例如PB2)LCD_BLK(背光控制) - 任意GPIO或直接接VCC (例如PB10)注意DCMI的数据线D0-D7必须连接到支持DCMI功能的特定GPIO上不能随意分配。一定要查阅你所使用型号的《数据手册》中“引脚定义”章节或《参考手册》的DCMI章节找到标有DCMI_Dx的引脚。胡乱连接会导致无法捕获数据。2.3 电源与时钟注意事项OV7725模块通常需要3.3V供电与STM32逻辑电平匹配直接接开发板的3.3V输出即可。确保电源容量足够尤其在摄像头启动瞬间电流可能较大。如果图像出现横条纹噪点很可能是电源纹波过大可以尝试在摄像头模块的电源引脚附近并联一个10uF和0.1uF的电容进行滤波。时钟方面OV7725需要外部提供时钟XCLK通常由STM32的MCO引脚输出一个频率稳定的时钟给它。STM32F4的MCO可以输出系统时钟、HSE、HSI等。我们可以配置一个8MHz或12MHz的时钟输出给OV7725。例如将PA8引脚配置为MCO输出并连接到模块的XCLK引脚。摄像头内部的PLL会以此为基础产生像素时钟PCLK等内部时序。3. 软件驱动层配置摄像头与显示屏硬件连好后就进入了软件世界。我们需要让STM32能够“命令”摄像头开始工作并“指挥”屏幕准备显示。3.1 OV7725的SCCB初始化与寄存器配置OV7725通过SCCB总线配置其协议与I2C高度兼容可以直接使用STM32的I2C外设驱动。首先初始化一个I2C速度用标准模式100kHz或快速模式400kHz即可。配置的本质是向OV7725内部的一系列寄存器写入特定的值以设定其工作模式。这里提供一套针对QVGA320*240分辨率、RGB565格式输出的常用寄存器配置数组。你需要根据你的模块和需求进行调整例如有些模块默认输出是YUV。// 示例OV7725 QVGA RGB565 配置寄存器组 #define OV7725_ADDR 0x42 // SCCB 写地址通常为0x42读地址为0x43 const uint8_t ov7725_config_regs[][2] { {0x12, 0x80}, // 复位所有寄存器 {0x3d, 0x03}, // 保留设置 {0x12, 0x00}, // 取消复位开启 DSP 功能 // 设置输出格式为 RGB565 {0x12, 0x04}, // 开启 DSP 缩放功能并设置输出格式控制位 {0x8c, 0x00}, // 选择 RGB 输出 {0x04, 0x00}, // 设置 DSP 缩放控制 {0x40, 0xd0}, // 设置 COM15 RGB565 输出全范围 // 设置 QVGA 分辨率 {0x17, 0x13}, // HSTART 水平起始位置高8位 {0x18, 0x01}, // HSTOP 水平结束位置高8位 {0x19, 0x2e}, // VSTART 垂直起始位置高8位 {0x1a, 0x72}, // VSTOP 垂直结束位置高8位 {0x32, 0x80}, // HREF 控制 {0x03, 0x0a}, // VREF 控制 // 更多图像质量调节寄存器... // 例如曝光、增益、白平衡等初始调试时可先使用默认值 {0xff, 0xff} // 数组结束标记 };配置流程是I2C初始化后延时等待OV7725上电稳定约10ms然后遍历这个数组通过I2C将每个{寄存器地址 寄存器值}对写入OV7725。特别注意0x12寄存器的0x80是软复位写入后需要适当延时比如30ms再写入其他配置。配置完成后可以尝试读取某个已知寄存器如产品ID寄存器0x0a和0x0b应为0x77和0x21来验证通信是否成功。3.2 ILI9341 LCD的SPI驱动实现对于SPI接口的ILI9341我们需要实现两个最基本的函数写命令LCD_Write_Cmd和写数据LCD_Write_Data。这通过控制DC引脚的高低电平来实现DC0表示后续SPI数据是命令DC1表示是数据。void LCD_Write_Cmd(uint8_t cmd) { LCD_DC_GPIO_Port-BSRR (uint32_t)LCD_DC_Pin 16; // DC 0 LCD_CS_GPIO_Port-BSRR (uint32_t)LCD_CS_Pin 16; // CS 0 HAL_SPI_Transmit(hspi1, cmd, 1, HAL_MAX_DELAY); LCD_CS_GPIO_Port-BSRR LCD_CS_Pin; // CS 1 } void LCD_Write_Data(uint8_t data) { LCD_DC_GPIO_Port-BSRR LCD_DC_Pin; // DC 1 LCD_CS_GPIO_Port-BSRR (uint32_t)LCD_CS_Pin 16; // CS 0 HAL_SPI_Transmit(hspi1, data, 1, HAL_MAX_DELAY); LCD_CS_GPIO_Port-BSRR LCD_CS_Pin; // CS 1 }初始化LCD的过程就是发送一系列初始化命令序列这些序列通常可以在ILI9341的数据手册或卖家提供的例程中找到。关键步骤包括复位、退出睡眠模式、设置像素格式我们使用16位RGB565、设置显示方向、打开显示等。初始化成功后屏幕应该会点亮背光并可能变为某种纯色如黑色或白色。3.3 实现LCD画点与画矩形函数有了基础读写函数就可以构建上层应用函数。最核心的是LCD_DrawPoint用于在指定坐标画一个指定颜色的点。void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color) { // 1. 设置光标位置 (x, y) LCD_Write_Cmd(0x2A); // 列地址设置命令 LCD_Write_Data(x 8); LCD_Write_Data(x 0xFF); LCD_Write_Data((x) 8); // 结束列地址通常和开始一样因为我们只写一个点 LCD_Write_Data((x) 0xFF); LCD_Write_Cmd(0x2B); // 行地址设置命令 LCD_Write_Data(y 8); LCD_Write_Data(y 0xFF); LCD_Write_Data((y) 8); LCD_Write_Data((y) 0xFF); // 2. 发送写GRAM命令并写入颜色数据 LCD_Write_Cmd(0x2C); LCD_Write_Data(color 8); // 先高字节 LCD_Write_Data(color 0xFF); // 后低字节 }基于画点函数可以轻松实现LCD_Fill函数用于填充一个矩形区域这在显示整幅图像时效率远高于循环画点。其原理是先通过命令设置好要填充的矩形区域起始和结束的行、列地址然后连续发送0x2C命令再连续写入大量的颜色数据。ILI9341会自动将数据填充到设定的区域。这是我们后续显示图像的核心函数。4. 核心数据流DCMI与DMA的协同工作这是整个项目的“高速公路”负责将摄像头产生的海量像素数据高效、不间断地搬运到我们指定的内存缓冲区。STM32的DCMI数字摄像头接口和DMA直接存储器访问的配合是实现实时图像采集的关键。4.1 DCMI初始化与数据捕获模式DCMI是一个同步并行接口它根据PCLK、HSYNC和VSYNC这三个信号来捕获数据线上的有效像素数据。VSYNC帧同步信号。一次由高到低或可配置的跳变表示一帧图像的开始。HSYNC行同步信号。一次跳变表示一行像素数据的开始。PCLK像素时钟。在HSYNC有效期间PCLK的每个上升沿或下降沿可配置锁存一次数据线D[7:0]上的值。我们需要在CubeMX或直接配置寄存器初始化DCMI外设时钟极性根据OV7725的时序图配置VSYNC、HSYNC和PCLK的有效极性。OV7725通常是VSYNC高电平有效、HSYNC高电平有效、PCLK上升沿捕获数据。数据宽度设置为8位因为我们用D0-D7。捕获模式选择“连续抓取模式”Continuous grab mode。在此模式下DCMI会一帧接一帧地不停捕获数据。捕获速率选择“全帧捕获”All frames。JPEG模式禁用我们捕获原始数据流。4.2 DMA配置实现“零CPU占用”的数据搬运如果不使用DMACPU需要不断响应DCMI的数据就绪中断然后手动读取数据寄存器这会彻底拖垮系统。DMA的作用就是在DCMI每捕获完一行或一帧数据后自动将数据从DCMI的数据寄存器搬运到我们预先定义好的内存数组中整个过程无需CPU干预。配置DMA例如DMA2 Stream1外设地址DCMI的数据寄存器地址(uint32_t)(DCMI-DR)。内存地址我们定义的图像缓冲区数组的首地址如image_buffer。方向外设到内存。数据宽度外设和内存都设置为半字16位或字32位。这里有个关键技巧虽然DCMI数据是8位的但我们可以让DMA一次传输16位或32位。DCMI硬件会自动将连续的2个或4个8位像素数据组合成一个16位或32位数据放入DR寄存器。这样能减少DMA传输次数提升效率。我们选择**半字16位**模式正好对应RGB565格式的一个像素两个8位字节。传输模式循环模式Circular。这样当DMA搬运完一帧数据到缓冲区末尾后会自动回到缓冲区开头等待下一帧数据的到来实现连续不断的搬运。中断使能DMA传输完成中断或半传输完成中断用于双缓冲。这样当一帧数据搬运完毕DMA会产生一个中断我们可以在中断服务函数里知道“有一帧新图像准备好了”。4.3 双缓冲机制与图像撕裂问题如果我们只定义一个缓冲区bufferDMA在往buffer里写新一帧数据的同时LCD可能正在从buffer里读取数据去显示。这就会导致屏幕上同时出现新旧两帧的内容产生“图像撕裂”。解决方案是双缓冲定义两个大小相同的缓冲区buffer1和buffer2。DMA配置为循环模式但初始目标地址是buffer1长度为buffer1的大小。在DMA传输完成中断中我们进行缓冲区切换。例如当DMA写完buffer1后在中断函数里我们将LCD的显示数据源指向buffer1此时buffer1是完整的新帧同时立即将DMA的目标地址修改为buffer2让它去接收下一帧。下一帧完成时再将LCD指向buffer2DMA切回buffer1如此往复。这样DMA总是在向一个“后台”缓冲区写入而LCD总是从一个“前台”缓冲区读取两者互不干扰完美避免了撕裂。在STM32中我们可以利用DMA的双缓冲模式Double Buffer Mode或者手动在中断中切换内存地址来实现。5. 图像数据处理与显示优化数据流打通后我们得到的是存储在内存中的原始图像数据数组。但直接把这些数据丢给LCD很可能显示异常因为中间还隔着数据格式和显示坐标两道坎。5.1 数据格式转换从YUV422到RGB565很多OV7725模块默认输出的是YUV422YUYV格式。这是一种颜色编码方法用亮度Y和色度U V来表示颜色比RGB节省带宽。但我们的ILI9341屏需要的是RGB565格式。因此我们需要在内存中进行转换。YUV422到RGB565的转换有标准的公式。我们可以写一个转换函数但需要注意的是在MCU上对一整幅图像320*24076800像素进行浮点运算转换速度会非常慢。实战中的优化方法是使用查找表LUT或者定点整数运算。这里给出一个常用的整数近似算法针对一个YUV像素对YUYV格式[Y0, U, Y1, V]输出两个RGB像素// 简化版的 YUV 转 RGB 函数 (仅供参考实际需优化) void YUV2RGB(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) { int32_t r_tmp, g_tmp, b_tmp; // 减去偏移量 y y - 16; u u - 128; v v - 128; // 整数运算近似 r_tmp (298 * y 409 * v 128) 8; g_tmp (298 * y - 100 * u - 208 * v 128) 8; b_tmp (298 * y 516 * u 128) 8; // 限幅到 0-255 *r (r_tmp 0) ? 0 : ((r_tmp 255) ? 255 : r_tmp); *g (g_tmp 0) ? 0 : ((g_tmp 255) ? 255 : g_tmp); *b (b_tmp 0) ? 0 : ((b_tmp 255) ? 255 : b_tmp); } // 然后将 r,g,b 各取高5、6、5位组合成 RGB565 // uint16_t rgb ((r 0xF8) 8) | ((g 0xFC) 3) | (b 3);更好的办法是如果OV7725可以配置为直接输出RGB565格式通过修改寄存器COM7和COM15等就尽量避免在MCU端进行转换这是提升帧率最有效的手段。购买模块时或调试前务必确认并尝试配置为RGB565输出。5.2 显示坐标映射与窗口设置OV7725采集的图像分辨率是320x240QVGA我们的LCD屏分辨率可能也是320x240或者是其他尺寸如240x320。直接显示可能方向不对。我们需要处理两件事方向调整如果LCD是竖屏240x320而图像是横屏320x240就需要旋转90度显示。这可以在LCD驱动层解决通过发送0x36内存访问控制MAC命令来设置屏幕的扫描方向。也可以软件上通过坐标变换实现但效率较低。居中显示如果LCD分辨率大于图像分辨率比如480x320我们可以计算起始坐标让图像居中显示。显示一帧图像的函数流程如下void Display_Image(uint16_t *img_buffer) { // 1. 设置LCD的显示窗口对应要显示图像的区域 // 例如在 (x_start, y_start) 到 (x_end, y_end) 的矩形区域显示 Set_LCD_Window(x_start, y_start, x_startIMAGE_WIDTH-1, y_startIMAGE_HEIGHT-1); // 2. 发送写GRAM命令 (0x2C) LCD_Write_Cmd(0x2C); // 3. 将RGB565数据缓冲区连续写入LCD // 这里可以使用带DMA的SPI传输来加速而不是单字节写入 HAL_SPI_Transmit_DMA(hspi1, (uint8_t*)img_buffer, IMAGE_WIDTH*IMAGE_HEIGHT*2); }5.3 使用DMA加速SPI刷屏上面的Display_Image函数中如果使用HAL_SPI_Transmit阻塞式传输CPU会在发送数据期间被完全占用。对于3202402153600字节的数据即使SPI时钟达到20MHz也需要几十毫秒期间无法处理其他任务严重影响系统实时性。解决方案是使用DMA进行SPI刷屏。调用HAL_SPI_Transmit_DMA后函数立即返回DMA会后台搬运数据到SPI的发送数据寄存器CPU在此期间可以处理其他事务如准备下一帧图像数据。当DMA传输完成会产生一个中断我们在中断里进行缓冲区切换或标志位设置。重要提示同时使用DCMI的DMA和SPI的DMA时要注意它们可能共用同一个DMA控制器如DMA2的不同流Stream。需要仔细规划DMA流和通道的分配避免冲突。STM32CubeMX工具可以很好地帮助可视化分配。6. 系统集成与调试实战经验把所有模块组合起来并让它们稳定工作是最考验耐心和细心的环节。下面分享几个关键的调试步骤和常见问题。6.1 分模块调试确保每个环节独立工作不要试图一次性把所有代码写完并运行。务必分步调试LCD独立测试编写测试程序让LCD显示纯色、渐变色、网格或简单的图形。确保SPI通信、初始化序列、画点函数都是正确的。OV7725寄存器读写测试通过I2C读取OV7725的厂商ID和产品ID寄存器0x0A, 0x0B确认SCCB通信正常。DCMI数据捕获测试不用DMA先配置DCMI但不使能DMA。在DCMI的VSYNC中断或帧中断中点亮一个LED。用手在摄像头前晃动如果LED闪烁频率有明显变化说明DCMI基本能检测到图像信号。然后可以在行中断或数据寄存器非空中断中读取一个固定位置比如图像中心点的数据通过串口打印出来观察数据是否会随着拍摄物体颜色变化而改变。DMA搬运测试使能DMA在DMA传输完成中断中设置一个标志位。在主循环中检查这个标志位并计算帧率例如每100帧打印一次时间间隔。同时可以将缓冲区中某个固定像素的值通过串口打印验证数据是否正确搬运。格式验证与显示将DMA搬运来的原始数据缓冲区直接作为颜色值送给LCD显示假设你已配置为RGB565输出。如果显示的是有规律但色彩奇怪的条纹可能是数据格式不对比如是YUV但当成RGB显示。如果显示完全混乱可能是DCMI的时钟极性配置错误或者DMA传输宽度不匹配。6.2 常见问题与排查思路屏幕全黑或全白无图像检查LCD背光是否点亮。检查DCMI是否成功启动DCMI_Cmd(ENABLE)。检查OV7725的XCLK是否有时钟信号用示波器测PA8引脚。检查DMA是否配置正确内存缓冲区地址是否有效。在DMA完成中断里翻转一个LED看中断是否触发。如果不触发检查DMA或DCMI的中断配置。图像有严重的色彩偏差或条纹最常见原因数据格式不匹配。确认OV7725输出格式RGB565/YUV422与LCD显示和软件处理环节的假设是否一致。尝试修改OV7725的COM7和COM15寄存器强制输出RGB565。检查DCMI的数据位顺序。RGB565数据在内存中的排列是高字节RG高在前还是低字节G低B在前这需要和LCD的驱动IC要求匹配。可以尝试交换字节顺序。检查电源质量摄像头模拟部分供电不稳会导致颜色异常。图像撕裂、闪烁或错位这是双缓冲机制没处理好或缓冲区切换时机不对的典型症状。确保“DMA写入”和“LCD读取”操作的是不同的缓冲区。检查图像缓冲区的大小是否足够。计算公式宽度 * 高度 * 每像素字节数。对于320*240的RGB565需要320*240*2 153600字节。确保你的数组定义足够大且位于DMA可访问的内存区域通常就是普通数组。如果使用单缓冲撕裂是必然的。帧率过低计算理论帧率OV7725的像素时钟PCLK频率除以一行像素数 * 行数。例如PCLK12MHz QVGA下理论最大帧率约12M/(320*240)≈156帧但受限于曝光时间等实际会低很多。在MCU端瓶颈通常在于显示环节。使用HAL_SPI_Transmit阻塞刷屏会占用大量时间。务必启用SPI DMA刷屏。如果进行了软件YUV转RGB计算量巨大。优先尝试配置摄像头直接输出RGB565。降低图像分辨率如从QVGA降到QQVGA 160x120可以显著提升帧率。6.3 性能优化技巧内存布局优化将图像缓冲区定义在CCM RAM如果芯片有或者DTCM RAM中。这些是紧耦合存储器CPU和DMA访问速度最快可以提升数据搬运和处理效率。启用CPU Cache如果使用F7或H7系列合理配置D-Cache和I-Cache能极大提升性能。但要注意DMA操作的内存区域需要配置为Write-through或Non-cacheable以避免缓存一致性问题。降低SPI刷屏时间将SPI时钟分频调到最大在屏幕能接受的范围内参考ILI9341手册通常可达几十MHz。除了使用DMA还可以尝试将SPI配置为16位数据模式如果支持这样传输相同像素数据事务数量减半。如果屏幕支持“写内存”命令后连续写入就不要在每行数据间重复发送地址设置命令。图像处理降频如果不需要每秒30帧的全速显示可以在DMA完成中断中计数每收到2帧或3帧才刷新一次LCD能大大降低CPU和总线负载。整个系统调通后你会看到一个实时动态的世界出现在那块小小的LCD屏上。从硬件连线到寄存器配置再到DMA数据流和显示优化每一步的深入理解都能让你对嵌入式系统有更深刻的把握。这个项目不仅仅是一个图像显示它更是一个经典的“传感器-处理器-执行器”闭环案例其中涉及的思路和方法可以迁移到很多其他嵌入式应用场景中。本文还有配套的精品资源点击获取