stm32f103系列共有7个定时器,包括三个通用定时器TIM2,TIM3,TIM4,一个高级定时器(TIM1),两个看门狗定时器,一个systick计数器,这里直接贴出使用库函数的相关的源代码(含注释)。
1.初始化函数,
定时时间(秒) = arr*psc/定时器时钟频率
void TIM5_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //使能定时器时钟
TIM_TimeBaseInitStructure.TIM_Period = arr-1; //自动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc-1; //定时器预分频值
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //定时器时钟分频
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure); //初始化时基函数
TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE); //允许定时器5更新中断
TIM_Cmd(TIM5,ENABLE); //使能定时器五
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn; //定时器五中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
2.中断函数
void TIM5_IRQHandler(void)
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET) //定时器更新标志位置位
{
//中断处理语句
}
TIM_ClearITPendingBit(TIM5,TIM_IT_Update); //清除更新标志位
}
定时器通常有两个用途,一是计时一段时间,然后在定时器中断里面做一些处理,二是用于产生PWM波,产生PWM时要注意,不是任意引脚都可以通过定时器产生,此时要参阅data sheet管脚定义,此处拿PA1产生PWM举例。
通过查阅引脚定义,可以看到PA1可以复用为TIM2的Chanel2,那么PA1是可以产生PWM的,如果某个管脚不能复用为定时器的某个通道,则不能产生PWM。下面是相关的配置函数
1.初始化函数,先配置输出PWM的引脚,再配置定时器
/**
* @brief Init PA1 for pwm
* @param None
* @retval None
*/
void PWM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA, ENABLE);//打开时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //输出PWM波的引脚选择复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);
// config special AF Tim2
GPIO_PinAFConfig(GPIOA,GPIO_PinSource1,GPIO_AF_1); //复用为定时器2
}
2.PWM输出函数
void PWM_Output(uint32_t psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler= (psc -1); //定时器预分频系数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period = 800-1; //自动装载
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
//初始化定时器2通道2
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式为PWM1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //决定波形高低电平的先后顺序
TIM_OCInitStructure.TIM_Pulse = 400; //设置占空比
TIM_OC2Init(TIM2, &TIM_OCInitStructure); //通道二初始化
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能TIM2在CCR1上的预装载寄存器
TIM_ARRPreloadConfig(TIM2,ENABLE);//ARPE使能
TIM_Cmd(TIM2, ENABLE); //使能TIM2
}
高级定时器例如TIM1在配置PWM输出时需要额外的两步才能输出PWM(即参考上面的 PWM_Output函数,初始化通道时会多出一些语句)
TIM_OCStructInit(&TIM_OCInitStructure); //这一步必不可少
/* TIM1 channel1 configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //作用和极性差不多
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //通过本句关闭PWM时记得加上下面第三句初始化一下
TIM_OCInitStructure.TIM_Pulse = 400; /* duty ratio is 50% */
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置占空比前后电平高低
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE); //PWM输出开关控制,TIM1必备
TIM_Cmd(TIM1, ENABLE);
输入捕获:当定时器某通道所连接的引脚发生电平变化时,对应的捕获装置会将当前计数寄存器的值复制到捕获比较寄存器中(你可以开启捕获中断然后在中断处理函数中读出保存的计数值),当再次捕捉到电平变化时,这时计数寄存器中的值减去刚才赋值的值就是这段电平的持续时间,最常用来测频率。
输出比较:这里有两个单元,一个计数单元一个比较单元,计数器不停的计数,并且不停的与比较寄存器中的值进行比较,当计数器的值与比较寄存器的值相等时,可以设置电平跳变。
定时器多通道一般是用来输出多路PWM,并且多路PWM的频率一致,占空比可以不一致,可以用作电机调速。