一.定时器简介
1.基本定时器
2.通用定时器
滤波器可以滤掉信号的抖动和干扰,其工作原理:在一个固定的时钟频率f下进行采样,如果连续n隔采样点都为相同的电平,那就代表输入的信号稳定了。如果采样值不全都相同,那就说明信号有抖动,这时就保证上一次的输出,或者直接输出低电平也行,这样就能保证输出信号在一定程度上的滤波,采样频率f和采样点数N都时滤波器的参数
频率越低,采样点数越多,滤波效果就越好,信号延迟就越大
采样频率f可以由内部时钟分频而来,由参数ClockDivision决定
3.高级定时器
4.定时器基本结构
上图对应函数
5.计数器时序
5.时钟树
二.代码实现
一.定时器定时
<1>显示屏自动计时
(1)跨文件使用变量
timer.c
#include "stm32f10x.h" // Device header
extern uint16_t Num;//告诉编译器,在其他地方已经定义了Num的值,自己去找
void Timer_Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/*选择时钟函数*/TIM_InternalClockConfig(TIM2);//也可以不写,因为定时器上电以后默认就是内部时钟/*配置时基单元*/TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period=10000-1;//周期,就是ARR自动重装器的值TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//PSC预分频器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚初始化完就进入中断TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断,更新中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);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);TIM_Cmd(TIM2,ENABLE);//启动定时器
}
void TIM2_IRQHandler(void)
{if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET){Num++; TIM_ClearITPendingBit(TIM2,TIM_IT_Update);}
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
uint16_t Num;
int main()
{OLED_Init();OLED_ShowString(1,1,"NUM:");Timer_Init();while(1){OLED_ShowNum(1,5,Num,3);OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5);}
}
(2) 将中断函数放在主函数里面
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
uint16_t Num;
int main()
{OLED_Init();OLED_ShowString(1,1,"NUM:");Timer_Init();while(1){OLED_ShowNum(1,5,Num,3);OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5);}
}
void TIM2_IRQHandler(void)
{if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET){Num++; TIM_ClearITPendingBit(TIM2,TIM_IT_Update);}
}
Timer.c
#include "stm32f10x.h" // Device header
extern uint16_t Num;//告诉编译器,在其他地方已经定义了Num的值,自己去找
void Timer_Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/*选择时钟函数*/TIM_InternalClockConfig(TIM2);//也可以不写,因为定时器上电以后默认就是内部时钟/*配置时基单元*/TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period=10000-1;//周期,就是ARR自动重装器的值TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//PSC预分频器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚初始化完就进入中断TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断,更新中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);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);TIM_Cmd(TIM2,ENABLE);//启动定时器
}//void TIM2_IRQHandler(void)
//{
// if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
// {
//
// TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
// }
//}
<2>对射式红外计数
Timer.c
#include "stm32f10x.h" // Device header
extern uint16_t Num;//告诉编译器,在其他地方已经定义了Num的值,自己去找
void Timer_Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);/*初始化GPIO*/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);/*选择时钟函数*///第二个参数:外部触发预分频器;第三:外部触发极性(上升或下降触发);第四:外部触发滤波器(这里启动滤波防止CNT计数时发生跳变)TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x0f);/*配置时基单元*/TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period=10-1;//周期,就是ARR自动重装器的值TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//PSC预分频器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚初始化完就进入中断TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断,更新中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);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);TIM_Cmd(TIM2,ENABLE);//启动定时器
}
uint16_t Count(void)//返回计数器的值
{return TIM_GetCounter(TIM2);
}//void TIM2_IRQHandler(void)
//{
// if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
// {
//
// TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
// }
//}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
uint16_t Num;
int main()
{OLED_Init();OLED_ShowString(1,1,"NUM:");OLED_ShowString(2,1,"CNT:");Timer_Init();while(1){OLED_ShowNum(1,5,Num,3);OLED_ShowNum(2,5,Count(),5);}
}
void TIM2_IRQHandler(void)
{if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET){ Num++; TIM_ClearITPendingBit(TIM2,TIM_IT_Update);}
}
当外部输入信号功率很小,而IO内部的上拉电阻可能会影响到输入信号,可以使用浮空输入来防止影响外部输入的电平
二.定时器输出比较
三.定时器输入捕获
四.定时器的编码器 接口