蓝牙模块STC程序实战:主从配置、AT指令与串口透传排错指南

发布时间:2026/10/23 23:51:07
蓝牙模块STC程序实战:主从配置、AT指令与串口透传排错指南

简介:资源定位于STC单片机与蓝牙模块的无线通信开发,面向嵌入式初学者或需要快速搭建主从设备互联的开发者。压缩包包含21个文件,以c源文件、h头文件为主,辅以hex固件、uv2工程文件、obj目标文件及调试生成文件,整体仅29KB,结构紧凑,适合直接导入Keil工程阅读或烧录验证。目前已有395人学习下载,属于经过实测验证的参考例程。内容覆盖STC单片机IO配置、定时器与中断处理,以及通过UART串口驱动蓝牙模块的完整流程,并涉及主从设备角色配置、连接建立与数据收发。压缩包中保留了stc例程及main.c、system.c、Uart.c等模块化代码,便于按功能拆解学习;hex文件可用于直接烧录实测,帮助开发者避开协议栈细节,快速完成蓝牙通信功能验证。无论是课程设计还是工程入门,该压缩包都能作为现成的调试蓝本。

1. 蓝牙模块STC程序:主从角色不同,代码和接线完全是两套

把一块HC-05蓝牙模块接到STC单片机上做串口透传,听起来是十几行代码的事,实际一跑就翻车的不少。我拆过一套模拟项目X,帮A同学调过三次蓝牙模块STC程序,前两次都挂在同一类问题上:模块用的是从机,代码却按主机模式写,整个通信链路一直是单向的;第三次更隐蔽,AT指令把波特率改了,串口助手没跟着换,发什么都是乱码。蓝牙模块STC程序看着简单,坑几乎全在模块的角色配置和串口参数上:主模块要主动发起配对,从模块只能被动应答,两边的AT指令参数、绑定地址、波特率完全不同。这篇笔记按选型、接线、AT配置、STC串口程序、排错路径五条线展开,每一条都是可以直接抄作业的配置,适合正在用STC做无线数据透传、手机遥控或者双机通信的开发者。

2. 选型与接线:HC-05还是HC-06,STC的TXD/RXD到底怎么连

2.1 主从模块选型:HC-05和HC-06的定位差异与购买判断

在STC项目里最常见的串口蓝牙模块就两类,HC-05和HC-06。它们底层方案兼容,引脚基本一样,但功能定位差别很大。HC-05是主从一体模块,支持AT+ROLE指令切换角色,既能当主机主动去连接别的蓝牙设备,也能当从机等待被连接。HC-06则是纯从机模块,只能被动地被主机连接,不支持角色切换指令。

选型之前先问自己一个问题:通信的两端里,哪一端需要主动发起连接?如果是手机连单片机,单片机这一侧用HC-06就够了,手机端天然作为主机发起连接,STC这边只需要被动应答;如果是两块STC板子之间做无线数据传输,那必须有一端是主机角色,这一端选HC-05或同类型的主从一体模块,另一端用HC-06或者其他从机都可以。常见的翻车现场是手头只有一块HC-06,却想让它主动去连另一块模块,这从硬件能力上就不成立,不是代码能补救的。

有几个判断技巧可以避免买错模块。第一,看模块丝印或者商家标注有没有“主从一体”字样;第二,到手后用USB转TTL接上,发送AT+ROLE?,有返回说明可主可从,直接返回ERROR或者无响应的基本是纯从机模块。我一般会在下单前就让商家确认支持AT+ROLE,很多时候没问清楚,买回来发现角色固定,整个方案的连接方向就得反过来重新设计,花的时间远比省下的几块钱贵。

还要注意版本的引脚差异:HC-05在不同时期有多个版本,带底座与不带底座的、是否有独立状态指示灯、KEY引脚是单独引出还是和EN共用,都不一样。有些版本自带轻触按键,有些需要短接焊盘。购买时优先选把KEY/EN引脚明确引出的版本,后面对单片机自动控制模块复位或者重连会方便很多。引脚定义不明确的模块,踩坑概率会高不少。

2.2 电平匹配与交叉接线:STC引脚与蓝牙模块的TXD/RXD连接

STC单片机多数型号的I/O口是5V TTL电平,比如STC89C系列,而HC-05、HC-06模块的逻辑电平一般是3.3V。很多人直接拿5V单片机的TXD去接模块的RXD,短时间能用,长期稳定性就没法保证,尤其当模块RXD引脚没有做电平转换时,轻则数据偶尔丢字节,重则烧坏模块内部芯片。稳妥的做法是加一个电阻分压:在STC的TXD输出串一个1K电阻,到模块RXD前再对地接一个2K电阻,把5V分压到约3.3V。

数据方向是交叉连接,这一点看似简单,接错的概率却不低。STC的TXD发出去的数据要进模块的RXD,模块TXD发出的数据要进STC的RXD。如果两条线接成同向,模块和单片机各说各话,串口助手看到的是一片空白。按STC89C52的默认串口引脚P3.0和P3.1来排,接线对应关系如下:

STC89C52引脚蓝牙模块引脚说明
TXD / P3.1RXD单片机发送到模块接收
RXD / P3.0TXD模块发送到单片机接收
GNDGND共地,必须连接
VCC(5V)VCC模块板载稳压后再工作

模块的VCC这边有个容易被忽略的细节:很多HC-05模块板子上已经集成了稳压电路,标注工作电压是3.6V到6V,可以直接接5V;但如果买的是不带稳压的裸模块,就只能接3.3V,接5V大概率冒烟。上电前查一下模块丝印或者商家说明,确认板载是否包含稳压芯片再做供电决定。STC15系列这类新型号支持3.3V供电模式,I/O口可以直接和模块电平匹配,接线省掉分压电阻,但供电电压统一为3.3V后,STC的I/O驱动能力和内部ADC参考也会跟着变,老代码迁移时要一起检查。

共地是另一个高频踩坑点。USB转TTL工具、STC开发板、蓝牙模块三套设备各接各的电,只要地不共,串口数据就会出现随机丢字节、乱码甚至完全无响应。我一般会把USB转TTL的地、STC的地、模块的地用一根线连在一起再做任何调试。这一步成本最低,收益却最直接,很多时候所谓通信不稳定,排查半天最后发现就是共地没接好。

2.3 上电时序与指示灯状态:什么才算模块真的启动

蓝牙模块上电后,指示灯状态能反映当前工作模式。常见情况是:上电后LED快速闪烁,通常是进入了AT指令模式,此时无法正常配对通信;慢速闪烁一般是等待被连接;双闪或交替闪烁通常是可发现配对状态;常亮则是已经建立了蓝牙连接。不同厂商的模块指示灯定义不完全一致,不能只看灯就下结论,要配合AT指令去读取实际状态。

对STC程序而言,上电时序的影响体现在模块初始化的时间差上。STC单片机复位后程序可能立刻就开始向串口发数据,而蓝牙模块从通电到内部协议栈初始化完成往往需要一两秒。如果单片机在这段时间里发的配置帧或者数据帧被模块丢弃,程序里又没有重发机制,通信就会莫名其妙地不通。常见的做法是STC上电后延时2秒再开始串口通信,或者在模块准备好之前先发一遍蓝牙相关的初始化命令,延时后再确认一次。

还有一种情况,单片机通过IO口控制模块的EN引脚做软件复位。踩坑记录里比较典型的是,EN引脚在某些模块上通电瞬间不能拉高,否则会强制进入AT模式,导致正常通信模式进不去。正确做法是等模块稳定上电100ms之后再拉高EN,需要进入AT模式时则保持上电阶段EN为高。这些时序细节模块手册往往写得含糊,我一般会在硬件上电后用串口回环测试把模块的启动时间实测一遍,按实测值而不是手册标注值写延时。

3. AT指令配置:主从绑定、配对码与波特率三件套

3.1 进入AT指令模式:按键上电与指令帧格式

在写STC程序之前,第一步是把蓝牙模块的参数配置正确,这一步通常用USB转TTL工具单独完成。HC-05进入AT指令模式的标准操作是:按住模块上的按键,或者把EN/KEY引脚拉高,再给模块上电,指示灯会以约1秒2次的频率慢闪或快闪,此时AT指令才被识别。

要把两个“模式”分清楚:AT指令模式和透传模式。模块在透传模式下,收到的串口数据会原样通过蓝牙发出去,AT指令不再被解释;只有AT模式下指令才生效。如果发AT没有回显,多半是模块还停在透传模式。判断方法很简单:用串口助手发送一串不带回车的AT,能收到OK说明在指令模式,收不到再查是不是没按住按键上电。

指令帧格式上,绝大多数HC-05/HC-06要求每条AT指令以回车换行结尾,也就是\r\n,有些兼容模块只认\r。串口助手里要把“发送新行”选项打开,否则模块收到一长串“AT”命令根本不会解析。我遇到过不止一次,命令看着没问题,就是没勾选换行,模块一直无响应。

常用指令按执行顺序整理如下:

AT // 测试指令,返回OK表示通信正常 AT+ROLE=0 // 设为从机角色(0=从机,1=主机) AT+ROLE=1 // 设为主机角色(0=从机,1=主机) AT+PSWD="1234" // 设置配对码 AT+UART=9600,0,0 // 设置波特率9600,停止位1,无校验 AT+BIND=0012,34,567890 // 主模块绑定从模块地址 AT+RESET // 软件复位模块,让参数生效

AT+ROLE=0是把模块设置为从机,AT+ROLE=1则设置为主机。PSWD是双方对码用的配对码,主从两侧必须一致,否则搜索到了也连接失败。UART这一条设置模块和单片机之间的串口波特率,三个参数依次是波特率、停止位、校验位,常见组合就是9600,0,0,对应8数据位1停止位无校验。

BIND这条只有主机模块需要配置,作用是让主机只连接指定的从机地址,避免周围其他蓝牙设备干扰配对。地址通常就是模块标签上那一串,和AT+ADDR?读出来的值一致。地址格式在不同版本固件里略有区别,有些要写成带逗号分隔的格式,有些要写成分段格式,配置前先发AT+ADDR?读取当前地址,照着读出来的格式原样写回去最稳妥。

3.2 主从角色绑定:从机地址、配对码与连接策略

做主从配对时,最理想的状态是主机明确知道要连哪台从机,从机也明确允许被这台主机连接。对蓝牙模块来说,这个信任关系分两部分实现:一是配对码一致,二是主机的绑定地址指向从机。

从机侧只需要设置好配对码,保持默认的“允许任意主机连接”状态,也就是不设置绑定地址;主机侧配置AT+BIND指向从机地址,同时把配对码设置成和从机相同。主机上电后会自动搜索指定地址的从机,搜到就发起配对,对码通过后建立连接。

有个隐蔽问题:如果从机也设置了绑定地址指向主机,两块模块会形成固定的点对点关系。这听起来很好,但当主机或从机更换硬件后地址变了,绑定关系就得重新配置。如果只做主机到从机的单向绑定,从机保持开放状态,调试时会灵活很多,也更容易排查问题。我的习惯是第一次调试时全部保持默认,只设置角色和配对码,建立连接后再加BIND,把变量控制到最少。

连接策略方面还要提自动重连和手动重连。HC-05在配对成功后,如果因为断电或距离过远断开,部分固件版本会自动重连上次的设备,有些则需要重新进入搜索流程。自动重连是双刃剑:省了软件重连逻辑,但周围如果有多个同名模块,自动重连可能连到错误设备。对STC这类资源紧张的单片机,一般会在模块参数上开启自动连接,代码里再配合一个简单的状态检测来兜底。

3.3 参数写回与验证:改错波特率后的后悔药与恢复出厂设置

配置AT指令过程中最深的坑,是把模块的串口波特率改了,然后自己忘了。改完AT+UART=115200,0,0,模块在AT模式下立刻以115200波特率工作,电脑上的串口助手还是9600,之后发任何指令都是乱码或无响应。这不算变砖,把串口助手切到新波特率,模块马上恢复正常。

更麻烦的情况是:模块在AT模式下改了波特率,断电重上电后你已忘记改成多少,只能盲猜。常规办法是逐个尝试常用波特率,从9600、19200、38400、57600、115200按顺序扫一遍,每个波特率下发送一次AT,直到收到OK。还有一条后悔药:部分模块按住按键上电时会以固定波特率进入AT模式,常见是38400,这时发AT+ORGL可以把所有参数恢复出厂设置,波特率也回到9600。这招能救回大部分“变砖”的模块。

参数写回验证也很关键。每条AT指令完成后不要急着断电,依次执行AT+ADDR?、AT+ROLE?、AT+UART?、AT+PSWD?,把读回的值和预期值逐一对照。我见过有人把角色设置成主机,但读回后发现还是从机模式,原因是那条指令没带回车换行结尾,模块把它当无效命令丢弃了。读回这一步能第一时间暴露这类错误,避免带着错误参数继续往下做。

4. STC端程序框架:串口初始化、中断收发与一帧数据的解析

4.1 串口初始化:定时器T1与11.0592MHz晶振的关系

STC89C52这类传统型号的串口波特率由定时器T1的溢出率决定,这也是STC系列最经典的一套初始化逻辑。要得到9600波特率,推荐使用11.0592MHz晶振,因为这个频率的整数分频能精确产生常用波特率;12MHz晶振的误差偏大,长时间通信时周期性地出现乱码。重装值按下式计算:波特率等于晶振频率除以12再除以32再除以256减重装值。

以11.0592MHz晶振、定时器T1工作在8位自动重装模式为例,重装值取0xFD:

// STC89C52串口初始化: 9600bps, 8位数据, 1停止位, 无校验 void UART_Init(void) { SCON = 0x50; // 串口模式1: 8位UART, 允许接收REN=1 TMOD = (TMOD & 0x0F) | 0x20; // 定时器1模式2, 8位自动重装 TH1 = 0xFD; // 波特率重装值高8位 TL1 = 0xFD; // 低8位与高8位一致, 溢出后自动重装 TR1 = 1; // 启动定时器1 ES = 1; // 使能串口中断 EA = 1; // 使能总中断 }

SCON设置为0x50,SM0和SM1两位为01表示工作方式1,即8位UART;REN置1后单片机才能接收。TMOD先保留低四位,再把高四位设置为0010,让定时器1工作在方式2,溢出后自动重装TH1的值,波特率稳定且不占用CPU。TH1和TL1都写成0xFD,在11.0592MHz下对应9600波特率。TR1置位启动定时器,ES和EA打开串口中断和总中断后,收发都能靠中断驱动。

如果你的板子用的是22.1184MHz晶振,重装值要相应调整,计算式是TH1等于256减去晶振频率除以2倍波特率再除以32,算下来大约是0xFA。我不建议在蓝牙通信项目里用内部RC振荡器跑串口,尽管STC15系列内部IRC经过校准精度尚可,但蓝牙模块两侧各有晶振误差,两边误差叠加后长数据帧的末尾容易出错。

STC15系列还可以用独立波特率发生器,不占用定时器1,配置方式完全不同,比如用BRT寄存器直接设置波特率,初始化代码更简单,定时器1可以继续做PWM或定时功能。从传统STC89C52迁移到STC15时,串口初始化这部分代码需要重写,不能直接搬。

4.2 帧协议设计:帧头、长度、校验三个字段

串口透传建立后,STC和蓝牙模块之间是一条透明字节流。字节流没有边界,如果发送方连续发出两个数据包,接收方必须从字节流里准确切分每一帧。帧协议就是为了解决这个问题。最简单也最实用的帧格式包含三个字段:帧头、长度和校验。帧头用两个固定字节,取值0xAA和0x55;长度字节表示有效数据的字节数;校验字节对长度和有效数据做累加和。

这样设计的理由很直接:接收方先等帧头,确认头部完整后根据长度字节决定后续收多少数据,收完后用校验和验证完整性。蓝牙空中传输可能丢包或插入干扰数据,只要校验不匹配,这一帧就丢弃,不影响下一帧解析。

可以落地的帧结构定义如下:

#define FRAME_HEAD0 0xAA #define FRAME_HEAD1 0x55 #define FRAME_MAX_LEN 32 // 单帧有效数据最大字节数 typedef struct { uint8_t head0; uint8_t head1; uint8_t len; // 有效数据长度 uint8_t data[FRAME_MAX_LEN]; uint8_t sum; // 累加和校验: head0+head1+len+data } Frame_t;

长度字段限制在32字节以内,是为了让接收缓冲区和控制逻辑保持简单。实际项目里一次要传几百字节的传感器数据时,拆成多帧按序列号重组,而不是把单帧长度无限加大。校验字段用累加和而不用CRC,是因为STC89C52这类8位单片机算CRC的代码长度和CPU开销都偏大,蓝牙串口本身误码率不高,累加和能拦截大部分错误。

4.3 中断收发与状态机解析:从字节流里切出完整的一帧

串口接收采用中断方式,每收到一个字节触发一次串口中断。中断服务程序里不处理业务逻辑,只把字节推进一个状态机。状态机分几个阶段:等待第一个帧头,等待第二个帧头,接收长度字段,接收有效数据,等待校验字。每个阶段有对应状态值,字节到达时按当前状态做不同处理。

// 串口中断: 逐字节解析帧 void UART_ISR() interrupt 4 { uint8_t rx; if (!RI) return; rx = SBUF; // 读取接收缓冲区 RI = 0; // 清除接收中断标志 switch (rx_state) { case RX_STATE_WAIT_HEAD0: if (rx == FRAME_HEAD0) rx_state = RX_STATE_WAIT_HEAD1; break; case RX_STATE_WAIT_HEAD1: if (rx == FRAME_HEAD1) { rx_state = RX_STATE_LEN; } else if (rx != FRAME_HEAD0) { rx_state = RX_STATE_WAIT_HEAD0; // 不是头字节, 重新等待 } // 如果收到的是0xAA, 则保持等待第二个帧头 break; case RX_STATE_LEN: rx_len = rx; // 记录有效数据长度 rx_index = 0; rx_sum = 0; rx_state = rx_len ? RX_STATE_DATA : RX_STATE_CHECK; break; case RX_STATE_DATA: rx_buf[rx_index++] = rx; // 接收有效数据 rx_sum += rx; if (rx_index >= rx_len) rx_state = RX_STATE_CHECK; break; case RX_STATE_CHECK: if (rx_sum == rx) { frame_ready = 1; // 校验通过, 置位通知主循环 } rx_state = RX_STATE_WAIT_HEAD0; break; default: rx_state = RX_STATE_WAIT_HEAD0; break; } }

状态机的关键点在于处理第二个帧头时的边界情况:如果收到的不是0x55,需要判断它是不是又一个0xAA。如果是0xAA,当前字节可能是两个帧头的前一个,要保持等待状态;如果既不是0xAA也不是0x55,就复位到初始状态重新找帧头。校验和的计算范围是有效数据和长度,这里额外把两个帧头累加进去,相当于多了一道检查,因为帧头也在空中传输,同样可能被干扰。

主循环里只需轮询frame_ready标志,一旦置位就表示收到一帧完整数据,把rx_buf中的数据搬到业务缓冲区并清标志。这样中断处理时间很短,不会因为蓝牙数据连续到达而阻塞主流程。蓝牙每秒最多也就几百字节,哪怕STC主频只有12MHz,这个结构也绰绰有余。发送侧用查询TI标志的方式逐字节发送,发完一帧后再等TI置位,避免发送过程中被接收中断打断导致字节交错。

5. 蓝牙通信避坑:五个现象、五个原因与对应排查步骤

5.1 配对成功但收不到数据

现象:手机或另一块蓝牙模块已显示连接成功,STC串口助手却收不到任何数据,发给模块的命令也不回。

原因:最常见是数据方向接反,或者模块仍处于AT指令模式。连接成功只是射频链路建立了,模块的UART数据并没有自动双向打通,还要确认模块已退出AT模式进入透传模式。如果模块一直停在AT模式,业务数据不会通过UART转发出来。

解决:第一步,用USB转TTL单独接模块,去掉STC端,把模块设为透传模式,手机发什么串口助手就该显示什么;第二步,检查TXD/RXD是否交叉,用万用表测引脚电压,正常通信时空闲TXD应有电平变化;第三步,单独测试正常后接回STC,确认STC波特率与模块的AT+UART设置一致。这套顺序能覆盖绝大多数“连接成功但数据不通”的情况。

5.2 接收到的数据全是乱码

现象:数据能收到,但内容全是错乱字符,偶尔能看懂几个字母。

原因:双方波特率不一致。STC串口波特率由定时器重装值决定,模块波特率由AT+UART设定,一处对不上,整个数据流都是乱的。另一个常见原因是共地不良,地线拧得不牢或者三台设备电位不一致。

解决:先读AT+UART?确认模块当前实际波特率,再检查STC代码的TH1、TL1和晶振频率是否匹配。两者都正确就检查连接线,特别是杜邦线接触不良的情况。把波特率降到2400或4800做低速测试,通常能分辨是配置问题还是硬件干扰问题,低速时波形畸变不敏感。

5.3 改完波特率后模块失联

现象:一条AT+UART=115200,0,0发出去,模块就没反应了,串口助手发任何指令都无响应。

原因:模块已经切换到115200波特率工作,串口助手还停在9600。这不是模块坏了,只是两边说话速度不一致。

解决:把串口助手波特率切换到115200再试,一般立刻恢复通信。如果忘记设定值,用按键上电方式进入AT模式,逐个遍历常用波特率试探。最后一条路是AT+ORGL恢复出厂设置,波特率回到9600,但之前设置的自定义参数也会被清掉,需要重新配置。

5.4 主机每次断电后都无法自动重连从机

现象:主机上电后指示灯一直快闪,就是不建立连接,从机侧也一直等待。手机去连从机能连上,主机却连不上。

原因:主机绑定了旧的从机地址,而从机因更换模块或恢复出厂设置地址发生变化;也可能是主机处于可发现状态,但配对码还是默认的1234,和从机设置的不一致。

解决:先读AT+ADDR?分别拿两侧实际地址,重新设置AT+BIND,同时核对两侧AT+PSWD?是否一致。另一个细节:部分模块重新配对后需要执行AT+RESET软复位,否则新参数不生效。

5.5 STC程序里复位模块导致通信卡死

现象:代码里通过IO控制EN引脚复位蓝牙模块,复位后第一次发送数据总是丢,之后才慢慢正常,偶尔整个程序卡死无响应。

原因:EN引脚被拉低后模块内部有几十毫秒复位过程,此时去操作串口,发送的数据全部被丢弃。更麻烦的是,复位过程中模块TXD引脚输出不稳定电平,单片机可能误判为起始位产生错误接收中断,和主程序的延时逻辑卡在一起,任务卡死。

解决:复位模块后延时至少200ms再开始收发;如果仍不稳定,在模块复位期间关闭串口中断,延时结束恢复。复位IO口用开漏输出加外部上拉,比强推挽输出更稳,能避免复位瞬间的电平毛刺。

6. 进阶技巧:用超时心跳和数据缓存把蓝牙链路拉稳

蓝牙串口和有线串口最大的差别是:无线链路随时可能因距离、遮挡、干扰断掉,而且断掉后不会自动恢复。要让整套系统在工作周期内稳定,STC这一侧不能只做初始化配置,还要管理链路状态。这里给一个成本很低的做法:心跳保活加超时重连。

在双向通信的主设备侧,定义一个固定心跳间隔,比如500ms一帧心跳数据。从设备收到心跳后回一帧应答。主设备维护一个计数器,连续三帧心跳没有应答就判定链路断开,主动拉低EN引脚复位蓝牙模块,延时200ms再上电,等待模块自动重连。这个方案不需要模块固件支持,完全由STC端软件实现,兼容性很好:

#define HEARTBEAT_INTERVAL_MS 500 #define HEARTBEAT_MAX_MISS 3 static uint16_t heartbeat_tick = 0; static uint8_t miss_count = 0; void Heartbeat_Poll(void) { if (++heartbeat_tick >= HEARTBEAT_INTERVAL_MS) { heartbeat_tick = 0; if (miss_count >= HEARTBEAT_MAX_MISS) { BT_Reset(); // 拉低EN复位模块, 延时200ms后拉高 miss_count = 0; } else { UART_Send_Frame(FRAME_HEARTBEAT, (uint8_t *)"hb", 2); miss_count++; } } }

这个循环放在主while里配合延时调度器工作。每一帧心跳都带一个递增序号,从设备可以判断当前收到的数据是不是最新帧,避免网络延迟导致处理旧数据。心跳帧同时能持续唤醒从机,减少模块进入低功耗休眠的概率。数据缓存方面,接收端不要只在解析到完整帧时才处理,中断服务里先落到环形缓冲区,主循环再按帧状态机取数据,这样可以避免反复关开中断影响实时性。

一个带心跳、序号、校验和复位流程的蓝牙系统,就不再是简单的串口透传,而是有损链路下的可靠通信。从那以后我每次用STC做蓝牙项目,都会先在PC上模拟一遍断线重连时序,再让代码带上心跳和复位流程,这套习惯帮我省掉了大量现场调试时间。希望帮到你。

本文还有配套的精品资源,点击获取