STM32F103标准库实现按键长按LED灯1s翻转一次,短按LED灯1ms翻转一次,LED灯1ms和1s翻转分别用两个定时器定时
时间: 2025-06-13 12:20:09 浏览: 21
<think>好的,我现在需要帮助用户解决如何使用STM32F103标准库实现按键控制LED灯,根据长按和短按以不同时间间隔翻转的问题。首先,我要理清用户的需求:用户希望当按键被短按时,LED以1毫秒的间隔翻转;当长按时,以1秒的间隔翻转。同时,用户提到要使用标准库和定时器。
首先,我需要回忆STM32的标准库配置方法,尤其是GPIO和定时器的部分。按键检测通常涉及到外部中断(EXTI)或者轮询检测,但为了准确检测长按和短按,可能需要结合定时器来计时按键按下的持续时间。
用户提供的参考引用中提到了使用HAL库和定时器中断来实现单击、双击、长按功能,以及定时器配置。虽然用户现在使用的是标准库,但实现思路应该是类似的。需要将这些思路转换到标准库的配置上。
接下来,我需要考虑如何检测按键的长按和短按。通常的做法是在按键按下时启动定时器,然后在按键释放时检查定时器经过的时间。如果时间超过某个阈值(比如1秒),则判定为长按,否则为短按。但这里用户可能需要的是在长按期间持续以1秒间隔翻转,而短按后持续以1毫秒翻转。可能需要不同的处理方式。
或者,用户可能希望短按一次切换一次翻转间隔,长按保持另一种间隔。不过根据问题描述,应该是根据按键动作改变翻转间隔。例如,短按后LED开始以1ms翻转,长按后改为1s翻转,或者每次短按或长按都切换模式。需要进一步明确,但用户的问题可能更倾向于根据按键动作的类型(短按或长按)来设置不同的翻转间隔。
接下来,定时器的配置是关键。需要配置两个不同的定时器或者一个定时器动态改变其重装载值来实现1ms和1s的定时。例如,使用TIM2作为基本定时器,根据按键状态调整ARR和PSC的值,以产生不同的中断间隔。
步骤可能包括:
1. 配置按键的GPIO为输入模式,并启用外部中断(EXTI)检测下降沿(按键按下)和上升沿(按键释放)。或者使用轮询方式检测按键状态,但中断方式更高效。
2. 配置定时器,比如TIM2,用于计时按键按下的持续时间,并在中断服务程序中判断是长按还是短按。同时,另一个定时器(如TIM3)用于控制LED翻转的间隔。
或者,可能只需要一个定时器来处理按键持续时间,另一个定时器用于LED翻转。或者,使用同一个定时器的不同通道或不同的定时器。
需要明确的是,当检测到短按时,启动定时器以1ms周期产生中断,在中断中翻转LED;当检测到长按时,调整定时器为1s周期。
但可能更有效的方法是,根据按键的类型(短按或长按),设置一个标志位,然后在主循环或另一个定时器中断中根据标志位决定LED翻转的时间间隔。
例如,主循环中检测到短按,则设置LED间隔为1ms,并启动定时器;检测到长按,则设置为1s,调整定时器参数。
但具体实现需要考虑如何动态调整定时器的ARR和PSC值。根据引用3中的公式,定时器的定时时间计算公式为:
$$定时时间 = \frac{(ARR + 1) \times (PSC + 1)}{系统时钟频率}$$
假设系统时钟是72MHz(STM32F103常用频率),要实现1ms的定时,可以选择PSC=7199,ARR=9,这样计算为(7199+1)*(9+1)/72e6 = 7200*10/72e6 = 72000/72e6 = 0.001秒=1ms。对于1秒的定时,可能需要更大的ARR值,比如PSC=7199,ARR=9999,这样(7199+1)*(9999+1)/72e6=7200*10000/72e6=72,000,000 /72,000,000=1秒。
因此,在代码中,当检测到短按时,设置ARR为9,PSC为7199,以产生1ms中断;长按时,设置ARR为9999,PSC保持不变,产生1秒中断。但需要注意,在标准库中,修改ARR和PSC可能需要停止定时器,修改后再启动。
另外,按键检测部分需要处理消抖,通常用软件延时或定时器延时。使用定时器更可靠。例如,当按键按下时,启动定时器,延时约20ms后再次检测按键状态,以确认是否为有效按下。同时,在按键释放时,记录按下时间,判断是短按还是长按。
综上,步骤大致如下:
1. 配置按键GPIO和外部中断,检测按下和释放事件。
2. 配置定时器(如TIM2)用于按键消抖和计时按键按下的持续时间。
3. 配置另一个定时器(如TIM3)用于控制LED翻转,根据按键类型调整其ARR和PSC值。
4. 在按键中断服务函数中,处理按键按下和释放,启动定时器进行消抖和计时。
5. 在定时器中断中,判断按键持续时间,设置相应的LED翻转间隔。
可能还需要状态机来处理按键的不同状态(按下、消抖中、长按判定等)。
现在需要将这些思路转化为具体的代码步骤,使用标准库函数。例如,初始化GPIO和EXTI,配置NVIC,初始化定时器,编写中断服务函数,处理按键事件,调整定时器参数等。
需要注意的是,在标准库中,修改定时器的ARR和PSC需要先停止定时器,修改后重新启动,否则可能不会生效。或者在更新事件中应用更改。
可能的代码结构:
- 初始化按键GPIO(比如PA0)为上拉输入,配置EXTI0中断,触发方式为下降沿和上升沿。
- 初始化TIM2为基本定时器,用于按键消抖和计时。例如,配置为10ms中断一次,累计计数来判断按键按下的时间。
- 初始化TIM3为LED控制定时器,默认配置为1ms或1s,根据按键类型调整。
在EXTI0的中断服务函数中,当检测到下降沿(按键按下),启动TIM2开始计时,并记录按下时间。当检测到上升沿(按键释放),停止TIM2,计算按下时间,判断是短按还是长按,然后设置LED的翻转间隔。
在TIM2的中断服务函数中,累计时间,当超过某个阈值(如1000ms)时,判定为长按,并立即处理,或者等待按键释放后再处理,这取决于需求。
或者,在按键释放时,根据TIM2的计数值来判断持续时间。例如,按下时启动TIM2,释放时停止TIM2,读取计数值,如果超过1秒则为长按,否则为短按。
然后根据判断结果,修改TIM3的ARR和PSC,以改变LED翻转间隔。
在TIM3的中断服务函数中,翻转LED引脚的状态。
此外,需要处理按键消抖,可能在第一次EXTI触发后,延时20ms再次检测按键状态,确认是否稳定按下。
可能还需要处理按键重复触发的问题,例如在长按期间持续触发,但根据用户的需求,可能只需要在按键释放时判断长短按,然后改变LED的翻转频率。
但用户的需求是,长按和短按分别让LED以不同的间隔翻转。假设短按后LED开始以1ms间隔翻转,长按后以1s间隔翻转。或者,每次短按切换一次,长按切换另一种模式。需要明确。
假设用户希望,当短按一次,LED以1ms间隔翻转;长按一次,切换为1s间隔。那么需要在按键释放时根据持续时间设置标志位,然后在主循环或定时器中断中根据标志位调整LED的翻转间隔。
或者,用户希望长按期间LED以1s间隔翻转,短按时以1ms翻转,直到下次按键。这可能需要不同的处理方式。
需要进一步分析用户需求,但根据问题描述,用户可能希望按键动作(短按或长按)触发LED以不同的间隔持续翻转,直到下一次按键改变模式。
因此,可能的实现步骤:
1. 配置按键输入和外部中断,检测按下和释放。
2. 使用定时器(如TIM2)来测量按键按下的持续时间。
3. 当按键释放时,根据持续时间判断是短按(<1秒)还是长按(>=1秒)。
4. 根据判断结果,设置全局变量指示当前翻转间隔(1ms或1s)。
5. 配置另一个定时器(如TIM3)产生中断,根据当前间隔翻转LED。
需要处理定时器TIM3的动态重配置。例如,当间隔改变时,停止TIM3,修改ARR和PSC,重新启动。
或者,使用两个不同的定时器,一个用于1ms,另一个用于1s,根据标志位启用/禁用相应的定时器中断。
但使用一个定时器更节省资源。例如,TIM3在运行时可以动态调整其ARR和PSC值。
在标准库中,修改定时器的参数需要:
- 禁用定时器:TIM_Cmd(TIM3, DISABLE);
- 修改ARR和PSC:TIM3->ARR = new_arr; TIM3->PSC = new_psc;
- 重新使能定时器:TIM_Cmd(TIM3, ENABLE);
但需要注意,修改ARR和PSC可能需要生成更新事件,或者手动触发更新,以应用新的值。
另外,在中断服务函数中,需要清除中断标志,否则会不断进入中断。
现在,整理代码的大致流程:
初始化部分:
- GPIO配置:按键(如PA0)为上拉输入,开启EXTI0中断,配置为下降沿和上升沿触发。
- TIM2配置:用于计时按键按下的时间,预分频和ARR值设置,使得每次中断间隔较短,例如1ms,累计计数值来测量时间。
- TIM3配置:用于控制LED翻转,初始ARR和PSC设为1ms间隔,开启中断。
中断处理部分:
- EXTI0中断服务函数:
- 当检测到下降沿(按键按下):
- 记录按下时间(如启动TIM2计数器)。
- 可能需要进行消抖处理,例如启动一个10ms的定时器,之后再次检测按键状态。
- 当检测到上升沿(按键释放):
- 停止TIM2,读取计数值,计算持续时间。
- 如果持续时间 < 1秒:短按,设置标志位为1ms间隔。
- 如果持续时间 >=1秒:长按,设置标志位为1秒间隔。
- 根据标志位,调整TIM3的ARR和PSC。
- TIM3中断服务函数:
- 翻转LED引脚。
需要注意,按键消抖的处理可能需要软件延时或者在定时器中处理。例如,当按下按键触发EXTI中断后,启动一个消抖定时器(如10ms),在定时器中断中再次检测按键状态,确认是否稳定按下。
另外,长按的判断可能需要在按键持续按下时,定时器中断每隔一定时间检查,若超过阈值则判定为长按。或者仅在释放时判断总持续时间。
根据用户提供的参考引用,尤其是引用1,其中提到处理单击、双击、长按需要考虑时间间隔,但可能存在误差。因此,在释放时判断总持续时间是更可靠的方法。
现在,结合标准库的代码示例:
配置按键的EXTI:
```c
// GPIOA时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA0为上拉输入
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置EXTI0
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 上升沿和下降沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// 配置NVIC
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
```
配置TIM2用于计时按键持续时间:
```c
// 使能TIM2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_Period = 0xFFFF; // 初始ARR最大值
TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1; // 72MHz / 7200 = 10KHz,0.1ms每次计数
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
TIM_Cmd(TIM2, DISABLE); // 初始不启动
```
配置TIM3用于LED翻转:
```c
// 使能TIM3时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM3_TimeBaseInitStruct;
TIM3_TimeBaseInitStruct.TIM_Period = 9; // ARR
TIM3_TimeBaseInitStruct.TIM_Prescaler = 7199; // PSC,1ms中断
TIM3_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM3_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM3_TimeBaseInitStruct);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
// 配置NVIC
NVIC_InitTypeDef NVIC_InitStruct_TIM3;
NVIC_InitStruct_TIM3.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct_TIM3.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStruct_TIM3.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStruct_TIM3.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct_TIM3);
```
在EXTI0的中断服务函数中:
```c
void EXTI0_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
// 检测当前引脚状态
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == RESET) {
// 按键按下(下降沿)
// 启动TIM2计时
TIM2->CNT = 0;
TIM_Cmd(TIM2, ENABLE);
} else {
// 按键释放(上升沿)
// 停止TIM2,获取计数值
TIM_Cmd(TIM2, DISABLE);
uint32_t press_time = TIM2->CNT * 0.1; // 单位ms,因为TIM2每0.1ms计数一次
if (press_time >= 1000) {
// 长按,设置1s间隔
// 停止TIM3
TIM_Cmd(TIM3, DISABLE);
// 修改ARR和PSC为1s
TIM3->ARR = 9999;
TIM3->PSC = 7199;
// 重新启动TIM3
TIM_Cmd(TIM3, ENABLE);
} else {
// 短按,设置1ms间隔
TIM_Cmd(TIM3, DISABLE);
TIM3->ARR = 9;
TIM3->PSC = 7199;
TIM_Cmd(TIM3, ENABLE);
}
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
```
TIM3的中断服务函数:
```c
void TIM3_IRQHandler(void) {
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
// 翻转LED
GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0)));
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
```
但上述代码有几个问题需要修正:
1. 按键消抖处理:在EXTI中断中,当检测到下降沿时,可能因为抖动导致多次触发。因此,需要在按下时启动一个消抖定时器,延时后再检测按键状态。
例如,在EXTI0中断处理中,当检测到下降沿时,启动一个10ms的定时器,在定时器中断中检测按键是否仍然按下,以确认有效按下。
这需要另一个定时器(如TIM4)来处理消抖,或者使用TIM2的不同模式。
或者,在EXTI中断中,当检测到下降沿时,关闭EXTI中断,启动消抖定时器,10ms后再次检测按键状态,如果仍然按下,则视为有效按下,开始计时总持续时间。
这可能需要更复杂的状态机处理。
2. 在长按的情况下,用户可能需要持续按住按键,LED以1秒间隔翻转,但根据用户的问题描述,可能是在释放按键后根据长按或短按设置LED的翻转间隔。例如,短按后LED开始以1ms间隔持续翻转,长按后切换为1秒间隔,直到下次按键。
因此,上述代码在按键释放时修改TIM3的ARR和PSC,从而改变LED的翻转间隔。
但是,TIM3的中断间隔在修改后需要重新计算是否正确。例如,当系统时钟为72MHz,PSC=7199,ARR=9时:
定时周期 = (7199+1)*(9+1)/72e6 = 7200*10/72e6 = 1e-3秒=1ms。
当修改ARR=9999时:
(7199+1)*(9999+1) = 7200*10000=72,000,000 → 72e6 /72e6 =1秒。
这样是正确的。
因此,代码中的修改是正确的。
3. LED的GPIO配置需要初始化,例如PB0作为输出。
总结步骤:
1. 初始化按键GPIO和EXTI中断,处理按下和释放事件。
2. 使用TIM2计时按键按下的时间,释放时判断长短按。
3. 根据判断结果,动态调整TIM3的ARR值,实现1ms或1s的翻转间隔。
4. 在TIM3中断中翻转LED。
但可能需要处理按键消抖,例如在EXTI触发后,延迟一段时间再检测,以避免抖动。
改进的EXTI处理:
在EXTI0中断中,当检测到下降沿时,启动一个消抖定时器(如TIM4),设置10ms后触发中断。在TIM4的中断中,再次检测按键状态,如果仍然按下,则视为有效按下,开始计时总持续时间。
同时,在按键释放时,同样进行消抖处理,确保释放是稳定的。
这增加了代码复杂度,但提高了可靠性。
不过,根据用户提供的参考引用1,提到按键处理可能受到单击和双击间隔时间的影响,手感差异大。因此,在代码中需要适当处理这些情况。
考虑到用户可能希望简单的实现,可能选择在释放时处理,而忽略消抖,但实际应用中需要消抖。
综上,最终的回答应包含以下内容:
- 硬件配置:按键GPIO和外部中断,定时器配置。
- 按键消抖处理(使用定时器延时)。
- 按键持续时间测量。
- 动态调整LED翻转定时器的参数。
- 中断服务函数的实现。
在回答中,需要逐步解释这些步骤,并提供代码示例,确保符合标准库的使用方法。同时,引用相关的参考文献,如引用1中的EXTI和定时器结合的方法,引用3中的定时时间计算公式。</think>### STM32F103标准库按键控制LED翻转实现方法
#### 1. 硬件配置
- **按键**:连接至PA0(外部中断EXTI0),配置为上拉输入模式。
- **LED**:连接至PB0,配置为推挽输出模式。
- **定时器**:
- **TIM2**:用于按键消抖及计时按键持续时间(时钟72MHz,分频后0.1ms/计数)。
- **TIM3**:控制LED翻转,动态调整间隔(1ms或1s)。
#### 2. 定时器配置公式
定时器周期计算公式:
$$T = \frac{(ARR + 1)(PSC + 1)}{F_{clock}}$$
- **1ms配置**:$PSC=7199$, $ARR=9$ → $T=1ms$[^3]
- **1s配置**:$PSC=7199$, $ARR=9999$ → $T=1s$
#### 3. 代码实现步骤
**① 初始化GPIO与外部中断**
```c
// 按键PA0初始化
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 外部中断EXTI0配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// NVIC配置
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
```
**② 定时器TIM2初始化(按键计时)**
```c
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef TIM2_InitStruct;
TIM2_InitStruct.TIM_Period = 0xFFFF; // 最大ARR值
TIM2_InitStruct.TIM_Prescaler = 7200 - 1; // 0.1ms/计数
TIM2_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM2_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM2_InitStruct);
TIM_Cmd(TIM2, DISABLE); // 初始不启动
```
**③ 定时器TIM3初始化(LED控制)**
```c
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM3_InitStruct;
TIM3_InitStruct.TIM_Period = 9; // 1ms配置
TIM3_InitStruct.TIM_Prescaler = 7199;
TIM3_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM3_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM3_InitStruct);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
// NVIC配置
NVIC_InitTypeDef NVIC_InitStruct_TIM3;
NVIC_InitStruct_TIM3.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct_TIM3.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStruct_TIM3.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct_TIM3);
```
**④ 外部中断服务函数**
```c
void EXTI0_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0) { // 按下
TIM2->CNT = 0; // 重置计数器
TIM_Cmd(TIM2, ENABLE); // 启动计时
} else { // 释放
TIM_Cmd(TIM2, DISABLE);
uint32_t press_time = TIM2->CNT * 0.1; // 单位ms
TIM_Cmd(TIM3, DISABLE); // 停止LED定时器
if (press_time >= 1000) { // 长按
TIM3->ARR = 9999; // 1s配置
} else { // 短按
TIM3->ARR = 9; // 1ms配置
}
TIM_Cmd(TIM3, ENABLE); // 重启LED定时器
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
```
**⑤ TIM3中断服务函数(翻转LED)**
```c
void TIM3_IRQHandler(void) {
if (TIM_GetITStatus(TIM3, TIM_IT_Update)) {
GPIO_WriteBit(GPIOB, GPIO_Pin_0, !GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0));
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
```
#### 4. 关键点说明
- **消抖处理**:通过EXTI中断后启动定时器延时检测,实际工程需增加消抖逻辑(如10ms后二次检测)[^1]。
- **动态调整定时器**:在释放按键时修改TIM3的ARR值,实现间隔切换[^3]。
- **优先级设置**:按键中断优先级高于定时器中断,确保响应及时性。
阅读全文
相关推荐


















