ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

STM32F103实战:ADC电压采集+LCD显示+串口通信完整教程

STM32F103实战:ADC电压采集+LCD显示+串口通信完整教程 简介基于STM32F103ZET6的实践工程围绕模拟数字转换器采集电压、液晶屏显示和串口通信发送三个核心功能展开适合希望快速掌握STM32标准外设库驱动与数据通信的嵌入式学习者。压缩包共88个文件其中C源码与头文件共75个另含Hex固件、Keil工程配置、汇编启动文件及说明文档压缩后仅241KB目录按硬件、系统、用户等功能模块划分便于直接查看与烧录验证。目前已有12000余人学习浏览例程可用于多通道模拟采样、液晶显示驱动移植以及串口打印调试等常见场景。整体以可运行例程为基础保留完整外设初始化与数据处理代码能清晰展示从模拟电压采集、液晶屏刷新显示到串口上送主机的完整数据链路适合初学者对照学习也便于二次开发。 搞嵌入式开发有一个项目我特别推荐新手亲手做一遍用 STM32F103 的 ADC 采集电压把数值同时送到 LCD 液晶屏显示再通过串口发到电脑上。这个题目看起来基础但一次把单片机开发里三个最常用的外设全串起来了——ADC 模拟采集、LCD 显示、UART 串口通信每一个在后续实际项目里几乎都会碰到。完成这个项目你对 STM32F103 的认知基本就从一个会点灯的芯片升级到了能采集、能显示、能上报的小系统。对于刚开始接触 STM32F103 的朋友来说这个项目最大的价值在于它把模拟世界和数字世界打通了。你把一个电位器的输出电压接到单片机上ADC 负责把电压变成数值LCD 负责把数值变成人眼能直接读到的内容串口则负责把同一份数据交给电脑处理。整个过程相当于做了一个最简化版的数据采集终端哪怕你以后去做环境监测、电池电压检测、传感器数据读取核心结构也还是这些东西。这篇文章我会从硬件准备讲到具体代码再讲到调试过程中容易踩的坑全程使用标准外设库StdPeriph_Lib来实现。涉及 ADC 采样周期、参考电压、LCD 中文显示、串口乱码这些高频关键词对应的实际问题我都会结合自己的经验一一拆开来讲。1. 项目整体设计与硬件准备1.1 为什么选 STM32F103 来做这个采集显示系统STM32F103 是我见过最皮实的入门级 ARM 单片机之一。它基于 Cortex-M3 内核主频 72MHz片内集成 12 位逐次逼近型 ADC、多个 UART、I2C、SPI 等丰富外设价格也足够便宜。网上资料堆积如山从最小系统电路图到标准库函数说明一搜一大把遇到问题非常容易找到参考。最关键的还是它内核稳定可用的中文参考手册和例程极多对新手非常友好。选择 STM32F103 搭配ADC LCD 串口这套组合其实对应着实际工程里最典型的一条数据链路传感器或信号源被 ADC 采集主控处理后一方面本地显示另一方面通过串口上报给上位机或云端网关。整条链路练熟了后面做 Modbus 采集模块、电池管理系统、医用小设备的数据面板基本都是同一套骨架。1.2 最小系统搭建与器件清单做这个项目之前要先有一块能跑起来的 STM32F103 最小系统板。最小系统其实不复杂核心就四部分3.3V 电源、8MHz 外部晶振也可以只用内部 HSI但为了串口波特率准确还是建议外接晶振、复位电路、BOOT 启动配置。现在市面上卖的 STM32F103 核心板基本都是画好的最小系统直接插上 USB 就能供电和下载程序省去了自己画板的麻烦。如果要自己搭最小系统需要注意给 VDD 和 VDDA 引脚都接上 0.1uF 去耦电容位置要尽量靠近芯片引脚。VCAP 引脚通常要接一个 2.2uF 钽电容到地这个很容易被忽略但它影响内部稳压器工作接不好芯片可能压根启动不了。复位脚 NRST 用 10k 电阻上拉到 3.3V再接一个 100nF 电容到地按键按下拉低复位即可。器件清单我建议这样准备器件型号/规格用途主控STM32F103C8T6 核心板系统控制核心电位器10k 多圈精密电位器提供 0~3.3V 可调电压源LCD 屏LCD1602 字符液晶可选 OLED本地显示电压值串口模块USB 转 TTLCH340 芯片连接电脑串口杜邦线若干公对公/公对母连接各模块电源5V USB 供电 AMS1117-3.3给核心板供电这里我特别提醒一点输入给 ADC 的电压绝对不能超过 VDDA即 3.3V否则轻则读数不准、重则烧掉 ADC 引脚。如果需要采集 5V 或更高电压务必加分压电阻把电压按比例降到 3.3V 以内。1.3 LCD 和串口模块怎么接IO 分配建议LCD1602 是很常用的字符液晶屏适合显示电压这种纯文本数据。接线方式有两种8 位并行模式和4 位并行模式。8 位模式一次传一个字节需要的 GPIO 多4 位模式分两次传输高四位和低四位能省 4 个 IO速度略慢但对静态显示完全够用。我的建议是直接用 4 位模式把宝贵的 IO 留给后续扩展。我实际用的接线分配如下LCD 的 RS 接 PA1、RW 接 PA2、EN 接 PA3数据口 D4~D7 接 PA4~PA7。这个分配没有硬性限制方便布线即可。需要注意 RW 脚如果确定只用写入方向可以直接接地省掉一个 GPIO。VO 对比度调节引脚接一个 10k 电位器到地调整出清晰的显示效果。串口模块的核心是 USB 转 TTL 芯片。CH340 是最常见、驱动安装最方便的一种兼容性好在 Windows 下装好驱动后会自动识别出一个 COM 口。接线时把 CH340 模块的 RX 接 STM32F103 的 PA9USART1_TXTX 接 PA10USART1_RX地线必须共地——这是新手最容易漏掉的一步模块和开发板各供各的电串口怎么调都是乱码或无数据。电位器的三个引脚接线也很简单两端分别接 3.3V 和 GND中间抽头接 PA0ADC1 通道 0。这样旋转电位器时PA0 上的电压就从 0V 到 3.3V 线性变化正好对应 ADC 的量程。2. ADC 采集核心原理与配置2.1 12 位逐次逼近型 ADC 的工作逻辑STM32F103 的 ADC 是12 位逐次逼近型SAR转换器它内部有一个比较器和一个由 DAC 生成的参考电压通过二分法逐步逼近输入电压。概念上很像猜数字游戏你先猜一个中间值然后看比目标大还是小不断折半逼近。12 位分辨率意味着转换结果用 0~4095 的数字表示 0~参考电压范围内的模拟值所以当参考电压是 3.3V 时每个最小数字代表 3.3V / 4096 ≈ 0.8mV。ADC 采样还有个容易混淆的概念——采样周期。STM32F103 的 ADC 采样周期可配置为 1.5、7.5、13.5、28.5、41.5、71.5、239.5 个 ADC 时钟周期。采样周期越长采样保持电容的充电时间越充裕对于内阻较大的信号源来说读数更准确但相应地转换速度会变慢。对于采集电位器这种信号信号源内阻一般也就几 k 欧姆用默认的 7.5 或 13.5 周期完全没问题。我实际项目里给 NTC 热敏电阻采样时会用 55.5 或 239.5 周期因为 NTC 接分压网络后的等效内阻通常更高采样时间不足会导致读数明显偏小。ADC 时钟也有讲究。STM32F103 的 ADC 最高时钟是 14MHz而 APB2 时钟一般是 72MHz所以 ADC 预分频最低只能选 6 分频72/612MHz不能选 2 分频72/236MHz 超出上限。很多人第一次写代码时把 ADC 时钟配到 36MHz虽然程序能跑但转换结果的线性度和稳定性都会变差。2.2 采样周期与参考电压参数怎么选才靠谱参考电压直接决定 ADC 读数和真实电压的换算公式。STM32F103 的最小系统板通常把 VREF 引脚直接接 VDDA也就是 3.3V。这时换算公式就是实际电压V ADC读数 × 3.3 / 4095如果追求更高精度可以用外部基准源给 VREF 提供一个精确电压比如 2.5V 或 3.0V 的高精度基准。但大多数学习和一般测量场景下直接用 3.3V 就够了只要确认核心板上的稳压芯片输出的确实是 3.3V 就行。ADC 有规则通道和注入通道两类普通单通道采集只用规则通道就够。规则通道可以配置为单次转换或连续转换模式。单次转换模式下每次触发只转换一次读完结果后需要再次触发连续转换模式下ADC 会不断循环采样并更新数据寄存器对实时监控场景更方便。我建议本项目的初始版本先用单次转换轮询逻辑简单调试方便。2.3 基于标准库的 ADC 初始化配置代码STM32F103 的 ADC 库函数主要涉及 GPIO 和 ADC 外设两个部分。GPIO 需要把 PA0 配置为模拟输入注意是模拟输入而不是浮空输入或上拉输入否则内部电路结构会干扰模拟信号。ADC 配置代码如下void ADC_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, GPIO_InitStructure); } void ADC_Config(void) { ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode DISABLE; ADC_InitStructure.ADC_ContinuousConvMode DISABLE; ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel 1; ADC_Init(ADC1, ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_13Cycles5); ADC_Cmd(ADC1, ENABLE); }读取 ADC 数值的代码很简洁启动一次转换等 EOC 标志位置位后直接取数据寄存器uint16_t ADC_GetValue(void) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) RESET); return ADC_GetConversionValue(ADC1); }这里我再强调一点每次读取后都要重新软件触发下一次转换这是很多人调试时困惑的地方——为什么数据一直不变因为你读完之后没有重新启动转换ADC 就停在原地不动了。3. LCD 显示电压数据3.1 屏幕选型LCD1602 还是 OLED显示部分我用过 LCD1602 也用过 0.96 寸 OLED。两者各有侧重LCD1602 是字符屏只能显示 ASCII 字符和一些日文假名、自定义符号胜在尺寸大、可视角度好、成本低工业控制面板上经常见到。OLED 能显示中文和图形对比度高体积小但刷新率偏低而且早期模块如果驱动电压极性接反容易烧屏。对于本项目的需求——显示电压数字LCD1602 其实最合适。16 列 2 行的布局足够显示Voltage: 1.234V这样的信息而且学习并行时序还能帮你理解 LCD 的工作原理。如果以后做菜单交互界面再用 OLED 或 TFT 屏也不迟。3.2 GPIO 模拟并口时序驱动 LCD1602LCD1602 的驱动时序本质上是并口写数据的操作。你先把要写入的数据放到 D0~D7 上然后根据是写命令还是写数据设置 RS最后给 EN 引脚一个下降沿脉冲数据就被锁存进屏幕控制器了。虽然 STM32F103 的 FSMC 接口可以硬件驱动 LCD但对于 1602 这种慢速设备GPIO 模拟完全足够代码也更直观。我写了一个精简的 LCD1602 驱动库核心就三个函数写命令、写数据、初始化。下面是使用 4 位模式时的写命令函数void LCD1602_WriteCmd(uint8_t cmd) { LCD_RS_LOW(); LCD_RW_LOW(); LCD_D4_SET(cmd 0x01); LCD_D5_SET(cmd 0x02); LCD_D6_SET(cmd 0x04); LCD_D7_SET(cmd 0x08); LCD_EN_PULSE(); LCD_D4_SET((cmd 4) 0x01); LCD_D5_SET((cmd 4) 0x02); LCD_D6_SET((cmd 4) 0x04); LCD_D7_SET((cmd 4) 0x08); LCD_EN_PULSE(); }这里用的是宏定义控制引脚电平先把低四位放上去EN 拉高再拉低完成一次锁存然后再发高四位。写完数据之后注意留出足够的延时我一般会加 2~5ms 的延时因为 LCD1602 内部控制器处理数据需要时间操作太频繁会丢数据。初始化时序也容易踩坑上电后要等 40ms 以上然后连续写三次 0x308 位模式命令再切换到 4 位模式。很多人的 LCD1602 不显示就是因为初始化时电平和延时时序不对。3.3 屏幕显示效果的细节中文、亮度与极化问题LCD1602 本身无法直接显示中文因为它内置的字库就是 ASCII 字符集。如果非要在 1602 上显示中文只能通过自定义字符发生器 CGRAM 来实现最多存 8 个 5x8 点阵的自定义图案而且一个汉字通常要拆成两个 5x8 的字符拼接比较麻烦。对Voltage:这种英文标识加数字的方式直接用 ASCII 就足够了。LCD 极化这个词是我在实际调试中才深有体会的。LCD 屏的显示原理依赖液晶分子的偏转对环境温度和驱动电压都很敏感。LCD1602 的 VO 对比度引脚如果电压不对屏幕要么全黑要么看不到任何字迹。我调试时遇到过屏幕完全没显示但程序正常的现象最后发现就是 VO 引脚悬空了。接上一个 10k 电位器一端接地一端接 VO调节到合适对比度问题立刻解决。另外LCD1602 的背光 LED 一般串一个 220 欧姆电阻后接 5V 或 3.3V不串电阻直接接电源的话背光电流过大很容易烧坏背光 LED。这一点在 OLED 屏上也类似注意模块额定电压是 3.3V 还是 5V别直接怼上去。等到液晶屏能正常显示之后显示电压值就很简单了。先把 ADC 整数转换为浮点电压值再用sprintf格式化到字符串然后定位到屏幕第二行写入char buf[16]; float voltage (float)adc_value * 3.3f / 4095.0f; sprintf(buf, Voltage: %.3fV, voltage); LCD1602_SetCursor(0, 1); LCD1602_WriteString(buf);这里建议把电压格式化成3 位小数因为 12 位 ADC 配合 3.3V 量程理论分辨率就是 0.8mV 左右显示 3 位小数刚好匹配显示太多位只是假精度。4. 串口发送与上位机数据查看4.1 UART 参数设置与 printf 重定向STM32F103 的 USART1 挂在 APB2 总线上配置时先设置波特率、数据位、停止位和校验位。最常用的配置是115200-8-N-1即波特率 1152008 个数据位无校验1 个停止位。波特率计算由硬件自动完成底层有一个 16 倍过采样的分频器库函数封装得比较干净void USART1_Config(uint32_t baud) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate baud; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_RX | USART_Mode_TX; USART_Init(USART1, USART_InitStructure); USART_Cmd(USART1, ENABLE); }串口发送数据最方便的方式是重定向 printf。在 MDK/Keil 里勾选 Use MicroLIB 后重写fputc函数把单个字符直接送到 USART1 发送寄存器之后就能直接用printf输出格式化信息了int fputc(int ch, FILE *f) { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, (uint8_t)ch); return ch; }这样主程序里写printf(ADC: %d, Voltage: %.3fV\r\n, adc_value, voltage);就能把数据直接发到串口调试助手的窗口里。我记得第一次重定向成功时还挺激动因为从此以后打印调试信息就变得很方便不用再手写一个个字符串发送函数了。4.2 CH340 模块与串口调试助手的配合硬件上STM32F103 的 USART1 输出的是 TTL 电平0~3.3V电脑串口是 RS232 电平正负电压范围两者不能直接连。利用 CH340 模块做 USB 转 TTL 转换是最省事的方法单片机侧是 3.3V TTL 电平USB 侧插进电脑识别成 COM 口。安装好 CH340 驱动后打开设备管理器确认端口号。串口调试助手的选择比较灵活网上有很多免费工具基本的操作逻辑都一样选择串口号、设置波特率 115200、数据位 8、停止位 1、无校验然后打开串口就能看到接收区不断滚动的电压数据。比如ADC: 2048, Voltage: 1.650V ADC: 2054, Voltage: 1.655V ADC: 2060, Voltage: 1.660V如果你装了虚拟串口工具甚至可以把数据转发给 Python 脚本或 LabVIEW 处理这块后续可玩的空间很大。4.3 发送间隔与数据格式设计电压数据发送频率要结合场景考虑。如果只做人眼观察每秒发 5~10 次就够了发太快窗口刷屏严重。如果后续要画电压曲线、做数据分析每秒发 50~100 次也来得及。最简单的方式是在循环里加一个延时控制发送间隔更规范的情况下会用定时器置一个标志位主循环检测到标志置位后再发送。我最初版本就是while(1){ 采集 - 显示 - printf - Delay(100ms); }足够学习使用。数据格式上建议一定带上单位并用\r\n结尾。带单位方便对读数时人眼判断\r\n则是为了让串口助手自动换行显示。如果你后续想用串口直接控制其他设备格式就按对方的协议来但先把这个最简单的文本格式跑通了再去扩展也不晚。5. 数据滤波与 ADC 校准5.1 采样值为什么一直跳真实测量中的波动ADC 读数在屏幕上跳动是新手最容易困惑的现象之一。明明电压稳定为什么最后两三位一直变其实是正常的。第一参考电压本身有噪声板载稳压芯片输出不可能绝对稳定第二信号源有内阻和噪声杜邦线本身就像一根小天线周围环境电磁干扰会被 ADC 敏感地捕捉第三软件处理频率高每一次采样都是独立的快照抖动自然就显示出来了。解决跳动的思路有两类一是硬件上加强滤波比如在 ADC 引脚对地并联一个 100nF 电容形成低通滤波能滤掉高频噪声二是软件上做数字滤波多次采样取平均或取中值。对于 50Hz 工频干扰还可以考虑采样间隔取 20ms 的整数倍利用同步采样削弱干扰。5.2 经典的中值 均值滤波代码实现我在实际项目里最常用的组合是先去掉最大最小值再取平均。原理是多次采样中如果出现个别毛刺最大值和最小值可能是异常值先剔除可以防止它们把平均结果拉偏。实现起来也不复杂uint16_t ADC_Filter(void) { uint32_t sum 0; uint16_t i, max 0, min 4096; for (i 0; i 8; i) { uint16_t val ADC_GetValue(); if (val max) max val; if (val min) min val; sum val; } return (uint16_t)((sum - max - min) / 6); }这个函数采样 8 次剔除 1 个最大值和 1 个最小值剩下 6 个数取平均。实测下来电压数据跳动从原来的 ±10 个 LSB 降到 ±2 个 LSB 左右效果非常明显。滤波的代价是每次读值的时间变长但在这个场景下完全可接受。5.3 外部三点校准把读数做得更准即使做了滤波读数仍然可能和万用表测量值有偏差。原因是多方面的参考电压不是严格 3.3V实际可能是 3.28V 或 3.32VADC 本身有失调误差和增益误差。外部校准是提升精度的硬核手段。所谓三点校准就是用三个已知标准电压源比如 0V、1.65V、3.3V用精密可调电源产生分别记录 ADC 读数然后建立实际电压与 ADC 读数之间的直线关系。校准公式本质是一个线性映射实际电压 k × ADC读数 b其中 k 和 b 可以通过最小二乘法拟合得到。三个点取平均能减少单点误差的影响比简单做读数×3.3/4095更接近真实值。实际做一次就能感受到差别用万用表量出来 1.234V校准前显示 1.187V校准后显示 1.231V精度提升非常明显。校准得到的 k 和 b 可以写死在程序里也可以存储到 Flash 中掉电保存具体取决于你的产品是否允许通过串口命令在线修改校准参数。对于这个学习项目先把固定系数写到代码里就足够了。6. 常见问题与排查技巧实录6.1 高频问题速查表我在调试这个项目以及帮人排查问题时遇到的高频故障基本集中在下面这几类现象可能原因解决办法串口助手无任何数据串口模块接线接反或未共地交换 RX/TX确保 GND 连接开发板 GND串口收到乱码波特率不匹配确认代码和串口助手都设置成 115200LCD 白屏或全黑对比度 VO 电压不对或初始化时序不对接 10k 电位器调节 VO检查初始化延时LCD 只有第一行显示第二行起始地址写错第二行起始地址是 0x40需加上LCD1602_SetCursor处理ADC 读数异常跳变采样周期太短或滤波不够增大采样周期软件加中值和均值滤波电压显示总是 3.30V 不变电位器接线错误或采样引脚下拉/接死检查电位器抽头是否接 PA0确认没有和其他短路其中串口乱码最常见的原因就是波特率不一致其次是模块没共地。你查这些问题时可以先怀疑最常见、最便宜的原因不要一上来就怀疑单片机坏了。6.2 一次典型故障的排查思路我印象很深的一次调试LCD1602 能显示串口却一直收不到数据。检查代码没问题后来用万用表量 PA9 引脚电平发现一直是高电平说明 TX 没有拉低发送起始位。再往模块查——CH340 模块的 TX 和 STM32 的 PA9 之间杜邦线断了接触不良。换了一根线立刻正常。这类接触性故障真的占了调试问题的一半以上所以排查时先从物理连接入手再怀疑软件逻辑。还有一次是电压值总是偏小万用表量出 1.8V程序读出来只有 1.2V。最后发现是采样周期设成了 1.5 个周期采样保持电容充电不足。把采样周期改为 13.5 后再测数值就对了。这就是采样周期影响采样精度的最直观案例。6.3 扩展建议DMA、多通道与 FreeModbus如果这个基础版本跑通了我建议你继续往下面几个方向扩展多通道采样 DMA。ADC 四个通道同时采集时用 DMA 自动把转换结果搬到内存数组CPU 不用频繁进入中断效率和实时性都会更好。这也是实际工程中非常常见的做法。添加 Modbus RTU 从站功能。串口通信的意义不只是发数据到电脑看还能配合 FreeModbus 协议栈做成工业现场的标准通讯从站。STM32F103 通过 RS232/RS485 接口基于 FreeModbus 移植就能和组态软件、触摸屏、PLC 直接交换数据。这个玩法我强烈推荐它能把一个简单的电压采集板变成真正的工业设备。用 Python 做上位机接收。C 端发出来的串口数据用 Python 的 pyserial 读取后可以实时画曲线看到 ADC 数值随电位器旋转的波形变化理解数据链路会有质的提升。最后再说几句我用 STM32F103 做这个 ADC 采集显示串口发送项目已经很多次之前带新人时也经常让他们从这套组合入手。现在回头看这个项目的意义不在于代码本身有多复杂而在于它把单片机的三大基础外设串联成了一个完整的闭环系统。整条链路——从模拟信号到数字量从数字量到屏幕文字再从屏幕到串口报文——正是很多真实产品的基本骨架。如果你在调试中遇到问题我个人的建议是不要急着猛调代码先用万用表量引脚电平再检查物理连接最后再审视逻辑。这个排查顺序能帮你避开绝大多数新手会走的弯路。最后分享一个小技巧你在 LCD 显示的电压值旁边加上一个不断闪烁的*字符可以直观判断主循环到底有没有在正常运行——这比任何 printf 调试信息都更直观。本文还有配套的精品资源点击获取
返回列表