【STM32】定时器1:定时中断与外部时钟的使用方法
(基于江科大STM32教程)
一、理论部分
使用定时器模块基本流程如上:
1、时钟及时钟模式选择
(1)使用内部时钟
如TIM2,先初始化TIM2在APB1总线
然后用TIM_InternalClockConfig()使能TIM2的内部时钟即可。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
//void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
TIM_InternalClockConfig(TIM2);
(2)使用外部时钟模式1
(3)使用外部时钟模式2
如TIM2配置外部时钟模式2,TIM2的ETR引脚固定为PA0,不可随意更改
那么先需要初始化PA0的Rcc,设定GPIO,其中Mode选择上拉(参考手册8.1.11)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0f);
然后使用TIM_ETRClockMode2Config,外部时钟模式二,最后一个参数配置滤波器,0x0f消抖
参数定义如下:
/**
* @brief Configures the External clock Mode2
* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
* @param TIM_ExtTRGPrescaler: The external Trigger Prescaler.
* This parameter can be one of the following values:
* @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF.
* @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2.
* @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4.
* @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8.
* @param TIM_ExtTRGPolarity: The external Trigger Polarity.
* This parameter can be one of the following values:
* @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active.
* @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active.
* @param ExtTRGFilter: External Trigger Filter.
* This parameter must be a value between 0x00 and 0x0F
* @retval None
*/
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,
uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter)
2、配置时基单元
使用TIM_TimeBaseInit(),参数定义如下:
/**
* @brief Initializes the TIMx Time Base Unit peripheral according to
* the specified parameters in the TIM_TimeBaseInitStruct.
* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
* @param TIM_TimeBaseInitStruct: pointer to a TIM_TimeBaseInitTypeDef
* structure that contains the configuration information for the
* specified TIM peripheral.
* @retval None
*/
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
类似于GPIO的配置,第二个参数也是结构体,包含四个参数:
(1)TIM_ClockDivision
表示分频,采样频率=Rcc频率/分频;
(2)TIM_CounterMode
表示计数方式,主选向上;
(3)TIM_Period、TIM_Prescaler
用来控制计数,前者为频率,后者为计数周期,计算时要+1,
采样频率/(TIM_Period+1)(TIM_Prescaler+1)=溢出时间;
(4)TIM_RepetitionCounter
表示重复计数器,高级定时器应用;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=7200-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=10000-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
(5)TIM_ClearFlag()
根据TIM_TimeBaseInit的函数声明的更新中断的方式:Generate an update event to reload the Prescaler and the Repetition counter values immediately
在复位重装时,发送一个更新事件来重装寄存器,也就会触发一次中断,用于解决缓冲寄存器的问题,副作用是复位上电时也会导致触发一次中断。所以在init前清空一次寄存器可以使得复位上电时寄存器清零。
3、配置NVIC
如下:
//NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
4、中断函数模板
判断标志位后,清除标志位寄存器,执行中断函数。
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
//执行内容,尽量无延时
}
}
二、项目实践
1、项目内容
为同时训练到外部时钟、定时器时钟,设计如下:
计数秒表:
通过红外触发计数,模拟所需计时时间(秒、分,进位实现)
设定完成(按下按键)后,秒表开启,到达时间报警(亮灯)
2、代码实现
(1)TIM
首先编写TIM,先写两个TIM的init:
TIM2通过PA0,使用外部时钟模式2,计数60次溢出,即TIM_Period=60-1;TIM_Prescaler=1-1;
TIM3使用内部定时器时钟,1Hz。
TIM2通过counter取出的值为sec_set(设定的秒),中断执行是min_set++(设定的分),通过sec_set计数60次溢出,可实现秒向分的进位;
TIM3中断执行是sec++(秒表的秒)。
uint16_t Get_set(void)
{
return TIM_GetCounter(TIM2);
}
uint16_t Get_sec(void)
{
return sec;
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
min_set++;
}
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
sec++;
}
}
(2)其他外设
设定按键定义在PA2,指示灯定义在PA4
(3)main
int main(void)
{
OLED_Init();
Key_Init();
Timer2_Init();
LED_Init();
while(1)
{
OLED_ShowNum(1, 1, min_set, 2); //min_set
OLED_ShowNum(1, 4, Get_set(), 2); //sec_set
while(Key_Judge2()==1)
{
Timer3_Init();
while(1)
{
OLED_ShowNum(1, 1, min_set, 2); //min_set
OLED_ShowNum(1, 4, Get_set(), 2); //sec_set
OLED_ShowNum(2, 1, Get_sec(), 4);
if(Get_sec()==min_set*60+Get_set())
{
LED_Action(1);
while(1);
}
}
}
}
}
3、功能记录
正常计数
累加到60在分位进一
按下PA2后开始计时
计时到达报警
作者:Silveryyy