第19章 TIM-通用定时器
第十九章 TIM-通用定时器
1. 通用定时器简介
STM32F103的通用定时器有4个,为了更好的区别各个定时器的特性,我们列了一个表格,如下所示:
由上表知道:该 STM32 芯片的计数器都是 16 位的。 通用定时器和高级定时器其实也就是在基本定时器的基础上,添加了一些其他功能,如: 输入捕获、 输出比较、输出 PWM 和单脉冲模式等。 而通用定时器数量较多,其特性也有一些的差异,但是基本原理都一样。
2. 通用定时器框图
如上图,通用定时器的框图比基本定时器的框图复杂许多,为了方便介绍,我们将其分成六个部分讲解:
2.1 时钟源
通用定时器时钟可以选择下面四类时钟源之一:
-
内部时钟(CK_INT)
-
外部时钟模式 1:外部输入引脚(TIx), x=1, 2(即只能来自于通道 1 或者通道 2)
-
外部时钟模式 2:外部触发输入(ETR)
-
内部触发输入(ITRx):使用一个定时器作为另一定时器的预分频器
通用定时器时钟源的设置方法如下表所示:
2.1.1 内部时钟(CK_INT)
STM32F1 系列的定时器 TIM2/TIM3/TIM4/TIM5/ TIM6/TIM7 都是挂载在 APB1 总线上,这些定时器的内部时钟(CK_INT)实际上来自于 APB1 总线提供的时钟。但是这些定时器时钟不是由 APB1 总线直接提供,而是要先经过一个倍频器。在 HAL 库版本例程源码的 sys.c 文件中,系统时钟初始化函数 sys_stm32_clock_init 已经设置 APB1 总线时钟频率为 36MHz, APB1 预分频器的预分频系数为 2,所以这些定时器时钟源频率为 72MHz。因为当 APB1 预分频器的预分频系数≥2 分频时, 挂载在 APB1 总线上的定时器时钟频率是该总线时钟频率的两倍。这个和基本定时器一样,可回顾基本定时器这部分内容。
2.1.2 外部时钟模式(TI1、TI2)
外部时钟模式 1 这类时钟源,顾名思义时钟信号来自芯片外部。时钟源进入定时器的流程如下:外部时钟源信号→IO→TIMx_CH1(或者 TIMx_CH2),这里需要注意的是:外部时钟模式 1 下,时钟源信号只能从 CH1 或者 CH2 输入到定时器, CH3 和 CH4 都是不可以的。从 IO到 TIMx_CH1(或者 TIMx_CH2),就需要我们配置 IO 的复用功能,才能使 IO 和定时器通道相连通。
时钟源信号来到定时器 CH1 或 CH2 后,需要经过什么“关卡”才能到达计数器作为计数的时钟频率的,下面通过外部时钟模式 1 框图给大家解答。
时钟源信号到达 CH2 后,那么这里我们把这个时钟源信号用 TI2 表示,因为它只是个信号,来到定时器内部,那我们就按定时器内部的信号来命名,所谓入乡随俗。
TI2 首先经过一个滤波器,由 ICF[3:0]位来设置滤波方式,也可以设置不使用滤波器。
接着经过边沿检测器,由 CC2P 位来设置检测的边沿,可以上升沿或者下降沿检测。
然后经过触发输入选择器,由 TS[4:0]位来选择 TRGI(触发输入信号)的来源。可以看到图中框出了 TI1F_ED、 TI1FP1 和 TI2FP2 三个触发输入信号(TRGI)。 TI1F_ED 表示来自于 CH1,并且没有经过边沿检测器过滤的信号,所以它是 CH1 的双边沿信号,即上升沿或者下降沿都是有效的。 TI1FP1 表示来自 CH1 并经过边沿检测器后的信号,可以是上升沿或者下降沿。 TI2FP2 表示来自 CH2 并经过边沿检测器后的信号,可以是上升沿或者下降沿。这里以CH2 为例,那只能选择 TI2FP2。如果是 CH1 为例,那就可以选择 TI1F_ED 或者 TI1FP1。
最后经过从模式选择器,由 ECE 位和 SMS[2:0]位来选择定时器的时钟源。这里我们介绍的是外部时钟模式 1,所以 ECE 位置 0, SMS[2:0] = 111 即可。 CK_PSC 需要经过定时器的预分频器分频后,最终就能到达计数器进行计数了。
2.1.3 外部时钟模式2(ETR)
外部时钟模式 2,顾名思义时钟信号来自芯片外部。时钟源进入定时器的流程如下:外部时钟源信号→IO→TIMx_ETR。从 IO 到 TIMx_ETR,就需要我们配置 IO 的复用功能,才能使IO 和定时器相连通。
时钟源信号来到定时器 TIMx_ETR 后,需要经过什么“关卡”才能到达计数器作为计数的时钟频率的,下面通过外部时钟模式 2 框图给大家解答。
可以看到在外部时钟模式 2 下,定时器时钟信号首先从 ETR 引脚进来。
接着经过外部触发极性选择器,由 ETP 位来设置上升沿有效还是下降沿有效,选择下降沿有效的话,信号会经过反相器。
然后经过外部触发预分频器,由 ETPS[1:0]位来设置预分频系数,系数范围: 1、 2、 4、 8。
紧接着经过滤波器器,由 ETF[3:0]位来设置滤波方式,也可以设置不使用滤波器。 fDTS由TIMx_CR1 寄存器的 CKD 位设置。
最后经过从模式选择器,由 ECE 位和 SMS[2:0]位来选择定时器的时钟源。这里我们介绍的是外部时钟模式 2,直接把 ECE 位置 1 即可。 CK_PSC 需要经过定时器的预分频器分频后,最终就能到达计数器进行计数了。
2.1.4 内部触发输入(ITRx)
内部触发输入是使用一个定时器作为另一个定时器的预分频器,即实现定时器的级联。下面以 TIM1 作为 TIM2 的预分频器为例,给大家介绍。
上图中, TIM1 作为 TIM2 的预分频器,需要完成的配置步骤如下:
-
TIM1_CR2 寄存器的 MMS[2:0]位设置为 010,即 TIM1 的主模式选择为更新(选择更新事件作为触发输出 (TRGO))。
-
TIM2_SMCR 寄存器的 TS[2:0]位设置为 000,即使用 ITR1 作为内部触发。 TS[2:0]位用于配置触发选择,除了 ITR1,还有其他的选择,详细描述如下图所示:
上图中的触发选择中,我们在讲解外部时钟模式 1 的时候说过 TI1F_ED、TI1FP1 和 TI2FP2,以及外部时钟模式 2 讲的 ETRF,它们都是属于外部的,其余的都是内部触发了。那么这内部触发都代表什么意思呢?大家打开《STM32F10xxx 参考手册_V10(中文版) .pdf》 的 285 页,就可以找下面这个表。
在步骤 2 中, TS[2:0]位设置为 000,使用 ITR1 作为内部触发,这个 ITR1 什么意思?有表可以知道,当从模式定时器为 TIM2 时, ITR1 表示主模式定时器就是 TIM1。这里只是TIM2~5 的内部触发连接情况,其他定时器请查看参考手册的相应章节。
-
TIM2_SMCR 寄存器的 SMS[2:0]位设置为 111,即从模式控制器选择外部时钟模式 1。
-
TIM1 和 TIM2 的 CEN 位都要置 1,即启动计数器。
定时器的时钟源这部分内容是非常重要的,因为这计数器工作的基础。虽然定时器有四类时钟源之多,但是我们最常用的还是内部时钟。
2.1.5 STM32F103通用定时器时钟源简明解释
- 内部时钟 (CK_INT):
- 这是定时器的默认时钟源,来自于定时器所在的 APB 总线时钟。它是最常用的时钟源,提供稳定的时钟信号。
- 外部时钟模式 1:
- 通过外部输入引脚(如 TIMx_CH1 或 TIMx_CH2)提供时钟信号。仅限于通道 1 或 2。这种模式通常用于需要外部信号驱动的应用场景,比如计数外部事件。
- 外部时钟模式 2:
- 使用外部触发输入(ETR)作为时钟源。这种模式可以接收外部脉冲信号作为定时器的时钟源,适用于需要更高精度的外部时钟源的情况。
- 内部触发输入 (ITRx):
- 允许一个定时器的输出作为另一个定时器的时钟源。这种配置用于复杂的计时应用,其中一个定时器的输出可以作为其他定时器的时钟源,提供更灵活的计时解决方案。
2.2 控制器
控制器包括:从模式控制器、编码器接口和触发控制器(TRGO)。从模式控制器可以控制计数器复位、启动、递增/递减、计数。编码器接口针对编码器计数。触发控制器用来提供触发信号给别的外设,比如为其它定时器提供时钟或者为 DAC/ADC 的触发转换提供信号。
2.3 时基单元
时基单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)。这部分内容和基本定时器基本一样的,大家可以参考基本定时器的介绍。
不同点是:通用定时器的计数模式有三种: 递增计数模式、 递减计数模式和中心对齐模式; TIM2 和 TIM5 的计数器是 32 位的。递增计数模式在讲解基本定时器的时候已经讲过了,那么对应到递减计数模式就很好理解了。就是来了一个计数脉冲,计数器就减 1,直到计数器寄存器的值减到 0,减到 0 时定时器溢出,由于是递减计数,故而称为定时器下溢,定时器溢出就会伴随着更新事件的发生。然后计数器又从自动重载寄存器影子寄存器的值开始继续递减计数,如此循环。最后是中心对齐模式, 字面上不太好理解。该模式下,计数器先从 0 开始递增计数,直到计数器的值等于自动重载寄存器影子寄存器的值减 1 时,定时器上溢,同时生成更新事件,然后从自动重载寄存器影子寄存器的值开始递减计算,直到计数值等于 1 时,定时器下溢,同时生成更新事件,然后又从 0 开始递增计数,依此循环。每次定时器上溢或下溢都会生成更新事件。计数器的计数模式的设置请参考 TIMx_CR1 寄存器的位 CMS 和位 DIR。
下面通过一张图给大家展示定时器工作在不同计数模式下,更新事件发生的情况。
上图中,纵轴表示计数器的计数值,横轴表示时间, ARR 表示自动重载寄存器的值,小红点就是更新事件发生的时间点。举个例子,递增计数模式下,当计数值等于 ARR 时,计数器的值被复位为 0,定时器溢出,并伴随着更新事件的发生,后面继续递增计数。递减计数模式和中心对齐模式请参考前面的描述。
2.4 输入捕获
图的第④部分是输入捕获,一般应用是要和第⑤部分一起完成测量功能。TIMx_CH1~ TIMx_CH4 表示定时器的 4 个通道,这 4 个通道都是可以独立工作的。 IO 端口通过复用功能与这些通道相连。配置好 IO 端口的复用功能后,将需要测量的信号输入到相应的IO 端口,输入捕获部分可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常见的测量有:测量输入信号的脉冲宽度、测量 PWM 输入信号的频率和占空比等。后续有相应的实验。
下面简单说一下测量高电平脉冲宽度的工作原理,方便大家的理解:一般先要设置输入捕获的边沿检测极性,如:我们设置上升沿检测,那么当检测到上升沿时,定时器会把计数器 CNT的值锁存到相应的捕获/比较寄存器 TIMx_CCRy 里, y=1~4。然后我们再设置边沿检测为下降沿检测,当检测到下降沿时,定时器会把计数器 CNT 的值再次锁存到相应的捕获/比较寄存器TIMx_CCRy 里。最后,我们将前后两次锁存的 CNT 的值相减,就可以算出高电平脉冲期间内计数器的计数个数,再根据定时器的计数频率就可以计算出这个高电平脉冲的时间。如果要测量的高电平脉宽时间长度超过定时器的溢出时间周期,就会发生溢出,这时候我们还需要做定时器溢出的额外处理。低电平脉冲捕获同理。
上面的描述是第④部分输入捕获整体上的一个应用情况,下面我们来看第④部分的细节。当需要测量的信号进入通道后,需要经过哪些“关卡”?我们用图给大家讲解。
这里是以通道 1 输入捕获为例进行介绍,其他通道同理。
待测量信号到达 TIMx_CH1 后,那么这里我们把这个待测量信号用 TI1 表示,原因在讲解外部时钟模式 1 的时候说过,所谓“入乡随俗”。
TI1 首先经过一个滤波器,由 ICF[3:0]位来设置滤波方式,也可以设置不使用滤波器。 fDTS由 TIMx_CR1 寄存器的 CKD 位设置。
接着经过边沿检测器,由 CC1P 位来设置检测的边沿,可以上升沿或者下降沿检测。 CC1NP是配置互补通道的边沿检测的,在高级定时器才有,通用定时器没有。
然后经过输入捕获映射选择器,由 CC1S[1:0]位来选择把 IC1 映射到 TI1、 TI2 还是 TRC。这里我们的待测量信号从通道 1 进来,所以选择 IC1 映射到 TI1 上即可。
紧接着经过输入捕获 1 预分频器,由 ICPS[1:0]位来设置预分频系数,范围: 1、 2、 4、 8。
最后需要把 CC1E 位置 1,使能输入捕获, IC1PS 就是分频后的捕获信号。这个信号将会到达图的第⑤部分。
如下图所示:
图中,灰色阴影部分是输出比较功能部分,讲到第⑥部分输出比较的时候再介绍。左边没有阴影部分就是输入捕获功能部分了。
首先看到捕获/比较预装载寄存器,我们以通道 1 为例,那么它就是 CCR1 寄存器,通道 2、通道 3、通道 4 就分别对应 CCR2、 CCR3、 CCR4。在图中就可以看到 CCR1~4 是有影子寄存器的,所以这里就可以看到图中有捕获/比较影子寄存器,该寄存器不可直接访问。
图左下角的 CC1G 位可以产生软件捕获事件,那么硬件捕获事件如何产生的?这里我们还是以通道 1 输入为例, CC1S[1:0] = 01,即 IC1 映射到 TI1 上; CC1E 位置 1,使能输入捕获;比如不滤波、不分频, ICF[3:0] = 00, ICPS[1:0] = 00;比如检测上升沿, CC1P 位置 0;接着就是等待测量信号的上升沿到来。当上升沿到来时, IC1PS 信号就会触发输入捕获事件发生,计数器的值就会被锁存到捕获/比较影子寄存器里。当 CCR1 寄存器没有被进行读操作的时候,捕获/比较影子寄存器里的值就会锁存到 CCR1 寄存器中,那么程序员就可以读取 CCR1 寄存器,得到计数器的计数值。检测下降沿同理。
2.5 输入捕获和输出比较公用部分
该部分需要结合第④部分或者第⑥部分共同完成相应功能。
2.6 输出比较
第⑥部分是输出比较,一般应用是要和第⑤部分一起完成定时器输出功能。TIMx_CH1~ TIMx_CH4 表示定时器的 4 个通道,这 4 个通道都是可以独立工作的。 IO 端口通过复用功能与这些通道相连。
下面我们按照输出信号产生过程顺序给大家介绍定时器如何实现输出功能的?首先看到第⑤部分的“放大版”图,如下图所示:
色阴影部分是输入捕获功能部分,前面已经讲过。这里我们看到右边没有阴影部分就是输出比较功能部分了。下面以通道 1 输出比较功能为例给大家介绍定时器如何实现输出功能的。
首先程序员写 CCR1 寄存器,即写入比较值。这个比较值需要转移到对应的捕获/比较影子寄存器后才会真正生效。什么条件下才能转移?图中可以看到 compare_transfer 旁边的与门,需要满足三个条件: CCR1 不在写入操作期间、 CC1S[1:0] = 0 配置为输出、 OC1PE 位置0(或者 OC1PE 位置 1,并且需要发生更新事件,这个更新事件可以软件产生或者硬件产生)。
当 CCR1 寄存器的值转移到其影子寄存器后,新的值就会和计数器的值进行比较,它们的比较结果将会通过第⑥部分影响定时器的输出。
下面来看看第⑥部分通道 1 的“放大版”,如下图所示:
上图中,可以看到输出模式控制器,由 OC1M[2:0]位配置输出比较模式,该位的描述请参考《STM32F10xxx 参考手册_V10(中文版) .pdf》 相关定时器章节的 TIMx_CCMR1 寄存器。F1 系列有 8 种输出比较模式之多,后面用到再来介绍。
oc1ref 是输出参考信号,高电平有效,为高电平时称之为有效电平,为低电平时称之为无效电平。它的高低电平受到三个方面的影响: OC1M[3:0]位配置的输出比较模式、第⑤部分比较器的比较结果、还有就是 OC1CE 位配置的 ETRF 信号。 ETRF 信号可以将 Oc1ref 电平强制清零,该信号来自 IO 外部。
一般来说,当计数器的值和捕获/比较寄存器的值相等时,输出参考信号 oc1ref 的极性就会根据我们选择的输出比较模式而改变。如果开启了比较中断,还会发生比较中断。
CC1P 位用于选择通道输出极性。CC1E 位置 1 使能通道输出。
OC1 信号就会从 TIMx_CH1 输出到 IO 端口,再到 IO 外部。
3. 重点回顾
3.1 输入捕获
1. 输入捕获的基本概念
输入捕获功能通过定时器的输入通道捕捉外部信号的变化,并记录这些变化的时间戳。每当外部信号在指定的边沿(上升沿或下降沿)到达时,定时器的计数值会被捕获到一个捕获寄存器中。
2. 输入捕获的主要步骤
- 配置输入通道:
- 选择输入通道:STM32F103 的通用定时器(如 TIM1、TIM2、TIM3、TIM4)通常具有多个输入通道(如 TIMx_CH1、TIMx_CH2 等)。选择其中一个或多个通道用于输入捕获。
- 配置输入引脚:确保引脚的模式设置为输入,通常为复用功能模式。
- 配置捕获模式:
- 选择触发边沿(上升沿、下降沿或双边沿),以确定在何种条件下进行捕获。
- 设置捕获寄存器用于存储捕获的计数值。
- 启用输入捕获:
- 配置定时器的输入捕获功能,包括设置捕获/比较寄存器和控制寄存器。
- 启用定时器的中断或 DMA 传输(如果需要)以处理捕获事件。
3. 输入捕获配置寄存器
以下是配置输入捕获功能所涉及的一些关键寄存器和位:
- TIMx_CCER(捕获比较使能寄存器):配置捕获通道的极性(上升沿、下降沿)以及使能输入捕获。
- TIMx_CCRx(捕获比较寄存器):存储捕获的计数值。
- TIMx_SMCR(从属模式控制寄存器):配置输入捕获的触发模式和同步设置。
- TIMx_PSC(预分频器寄存器):设置计数器的时钟源,以影响捕获的精度。
4. 示例:配置输入捕获
假设你想用 TIM2 捕获在引脚 TIM2_CH1 上的信号的周期:
- 配置 GPIO:
- 设置 TIM2_CH1 引脚为输入模式,复用功能。
- 初始化 TIM2:
// 使能 TIM2 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 配置 TIM2
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_InitStructure.TIM_Period = 0xFFFF; // 自动重载寄存器
TIM_InitStructure.TIM_Prescaler = 0; // 不使用预分频
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_UP;
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
// 配置输入捕获
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 捕获上升沿
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
// 启用 TIM2
TIM_Cmd(TIM2, ENABLE);
- 处理中断(可选):
- 启用 TIM2 的中断,并在中断处理程序中读取捕获值。
// 配置中断
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
// 在中断处理程序中
void TIM2_IRQHandler(void) {
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) {
uint16_t capturedValue = TIM_GetCapture1(TIM2);
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
// 处理捕获值
}
}
5. 应用
- 频率测量:通过测量周期,计算信号的频率。
- 脉宽测量:测量信号的高电平时间或低电平时间。
- 事件计数:统计外部事件的发生次数。
3.2 输出比较
1. 输出比较的基本概念
输出比较功能通过将定时器的计数值与预设的比较值进行比较,生成特定的输出信号。当定时器计数器的值与比较寄存器中的值匹配时,定时器会触发一个事件来改变输出引脚的状态(如设置或复位)。
2. 输出比较的主要步骤
- 配置输出比较通道:
- 选择输出通道:STM32F103 的通用定时器(如 TIM1、TIM2、TIM3、TIM4)通常具有多个输出通道(如 TIMx_CH1、TIMx_CH2 等)。
- 配置输出引脚:确保引脚的模式设置为复用功能输出。
- 配置输出比较模式:
- 设置比较值:指定当计数器的值与比较寄存器中的值匹配时输出信号的行为。
- 选择比较输出模式:可以是脉冲输出、PWM 输出等。
- 启用输出比较:
- 配置定时器的输出比较功能,包括设置比较寄存器和控制寄存器。
- 启用定时器及其相关的输出通道。
3. 输出比较配置寄存器
以下是配置输出比较功能时涉及的一些关键寄存器和位:
- TIMx_CCER(捕获比较使能寄存器):配置输出通道的极性(高电平或低电平)以及使能输出比较。
- TIMx_CCRx(捕获比较寄存器):存储比较值,用于与计数器的值进行比较。
- TIMx_CCMR1/2(捕获比较模式寄存器):配置输出比较模式和相关设置。
- TIMx_EGR(事件生成寄存器):用于生成事件,以更新寄存器的值。
4. 示例:配置输出比较
假设你想用 TIM2 的通道 1(TIM2_CH1)生成一个频率为 1 kHz 的 PWM 信号:
- 配置 GPIO:
- 设置 TIM2_CH1 引脚为输出模式,复用功能。
- 初始化 TIM2:
// 使能 TIM2 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 配置 TIM2
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_InitStructure.TIM_Period = 999; // 设定周期值 (ARR)
TIM_InitStructure.TIM_Prescaler = 71; // 设置预分频器 (PSC),假设系统时钟为 72 MHz
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_UP;
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
- 配置输出比较模式:
// 配置输出比较通道 1
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置 PWM 模式 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 499; // 设置脉宽值 (CCR)
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
// 使能 TIM2
TIM_Cmd(TIM2, ENABLE);
- 生成更新事件(确保寄存器更新)
5. 应用
- PWM 信号生成:通过调整比较寄存器中的值来生成不同的占空比,以控制电机速度、亮度调节等。
- 脉冲输出:生成特定宽度的脉冲信号,适用于定时事件触发。
- 时间延迟:通过输出比较生成的定时脉冲可以用作延迟信号。
6. 输出比较模式
输出比较可以配置为以下几种模式:
- 比较匹配:当计数器值与比较寄存器匹配时,改变输出状态。
- PWM 输出:定时器周期内,根据比较寄存器的值生成 PWM 信号。
- 强制输出状态:强制设置或重置输出引脚状态。
2024.9.11 第一次修订,后期不再维护
2025.1.25 修补内容
本文作者:hazy1k
本文链接:https://www.cnblogs.com/hazy1k/p/18408211
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步