定时器功能 :定时、输出比较、输入捕获、互补输出
定时器分类 :基本定时器、通用定时器、高级定时器
定时器资源 :429有2个高级定时器、10个通用定时器、2个基本定时器
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14-90M
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11—180M
定时器最主要的就是时基部分:包括 预分频器、计数器、自动重装载寄存器。
预分频器:
1-16位的预分频器TIMx_PSC对内部时钟CK_INT进行分频之后,得到计数器时钟CK_CNT=CK_PSC/PSC+1
2-计数器CNT在计数器时钟的驱动下开始计数,计数一次的时间为1/CK_CNT
计数器、自动重装载寄存器:
定时器使能(CEN 置 1)后,计数器 CNT在CK_CNT 驱动下向上计数,当 TIMx_CNT 值与 TIMx_ARR 的设定值相等时就自动生成事件并 TIMx_CNT 自动清零,然后自动重新开始计数,如此重复以上过程。
基本定时器(TIM6、TIM7)功能简介
1-计数器16bit,只能向上计数
2-没有外部的GPIO,是内部资源,只能用来定时
3-时钟来自PCLK1,可实现1~65536分频
定时时间的计算:
1、PSC = 9000-1,定时器频率=90M/(PSC+1)=10000HZ
2、ARR = 4999,从0计数到4999,则计了5000次
3、T = 5000 / 10000 = 0.5S
TIM7初始化以及中断服务函数
void bsp_Init_TIM7(void)
{
NVIC_InitTypeDef NVIC_InitStructure;//中断初始化结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定时器初始化结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//开启TIM7时钟
TIM_TimeBaseStructure.TIM_Prescaler = 9000 - 1; // 频率90M / 9000 = 10K
TIM_TimeBaseStructure.TIM_Period = 5000 - 1; //5000 / 10K = 0.5S一个周期
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数模式,加计数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频因子,但是不用于分频,而是用于滤波
//TIM_TimeBaseStructure.TIM_RepetitionCounter;
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);//初始化TIM7
TIM_Cmd(TIM7, ENABLE);//使能TIM
TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);//开中断 更新时触发
//NVIC_InitTypeDef NVIC_InitStructure;//NVIC结构体赋值
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; //中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_Init(&NVIC_InitStructure);
}
void TIM7_IRQHandler(void)
{
if (TIM_GetITStatus(TIM7, TIM_IT_Update) == SET) //设置的定时时间到
{
bsp_LedToggle(1); //LED1翻转
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);//清除标志
}
}
(输出比较)输出PWM:
void bsp_Init_TIMxPwm(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//开时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
//GPIO结构体赋值初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上拉或下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);
//引脚复用初始化,只要不做为普通IO就需要调用这个函数
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_TIM2);
TIM_TimeBaseStructure.TIM_Prescaler = 90 - 1;// 90M / 90 = 1M
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式为加计数
TIM_TimeBaseStructure.TIM_Period = 10000 - 1; //频率为 1M / 10K = 100Hz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //0-CCR为有效 CCR-ARR为无效
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能
TIM_OCInitStructure.TIM_Pulse = 1000; // ARR是10000 CRR是1000, 占空比10%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效部分为高
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
//时钟使能
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //CRR1寄存器预加载配置
TIM_ARRPreloadConfig(TIM2, ENABLE); //ARR寄存器预加载配置
TIM_Cmd(TIM2, ENABLE); //开启TIM
}
初始化结构体详解:
1-TIM_OCMode:比较输出模式选择,总共有八种,常用的为 PWM1/PWM2。它设定CCMRx 寄存器 OCxM[2:0]位的值。
2-TIM_OutputState:比较输出使能,决定最终的输出比较信号 OCx 是否通过外部引脚输出。它设定 TIMx_CCER 寄存器 CCxE/CCxNE 位的值。
3-TIM_OutputNState:比较互补输出使能,决定 OCx 的互补信号 OCxN 是否通过外部引脚输出。它设定 CCER 寄存器 CCxNE 位的值。(适用于TIM1和TIM8)
4-TIM_Pulse:比较输出脉冲宽度,实际设定比较寄存器 CCR 的值,决定脉冲宽度。可设置范围为 0 至 65535。
5-TIM_OCPolarity:比较输出极性,可选 OCx 为高电平有效或低电平有效。它决定着定时器通道有效电平。它设定 CCER 寄存器的 CCxP 位的值。
6-TIM_OCNPolarity:比较互补输出极性,可选OCxN 为高电平有效或低电平有效。它设定 TIMx_CCER 寄存器的 CCxNP 位的值。(适用于TIM1和TIM8)
7-TIM_OCIdleState:空闲状态时通道输出电平设置,可选输出 1 或输出 0,即在空闲状态(BDTR_MOE 位为 0)时,经过死区时间后定时器通道输出高电平或低电平。它设定CR2 寄存器的 OISx 位的值。(适用于TIM1和TIM8)
8-TIM_OCNIdleState:空闲状态时互补通道输出电平设置,可选输出 1 或输出 0,即在空闲状态(BDTR_MOE 位为 0)时,经过死区时间后定时器互补通道输出高电平或低电平,设定值必须与 TIM_OCIdleState 相反。它设定是 CR2 寄存器的 OISxN 位的值。(适用于TIM1和TIM8)
其他常用函数:
1、设置比较值函数:(CCRX)也就是OC初始化结构体中的Pulse, 即修改占空比
void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Comparex);
函数名中的X表示通道号,TIMX是定时器号,Comparex是修改值
如
TIM_SetCompare1(TIM2, pwm_value);
2、使能输出比较预装载:
void TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
使能CCRx寄存器,函数名的x是通道名,
TIM_OCPreload可选TIM_OCPreload_Enable或TIM_OCPreload_Disable
如
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //CRR1寄存器预加载配置
3、使能自动重装载的预装载寄存器允许位:TIMx的ARR使能
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
如
TIM_ARRPreloadConfig(TIM2, ENABLE); //ARR寄存器预加载配置
输入捕获:
原理:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
初始化结构体详解:
1-TIM_Channel:捕获通道 ICx 选择,可选 TIM_Channel_1、 TIM_Channel_2、
TIM_Channel_3 或 TIM_Channel_4 四个通道。它设定 CCMRx 寄存器 CCxS 位 的值。
2-TIM_ICPolarity:输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触发。它设定 CCER 寄存器 CCxP 位和 CCxNP 位的值。
3-TIM_ICSelection:输入通道选择,捕获通道 ICx 的信号可来自三个输入通道,分别为
TIM_ICSelection_DirectTI、TIM_ICSelection_IndirectTI 或 TIM_ICSelection_TRC
它设定 CCRMx 寄存器的 CCxS[1:0]位的值。
4-TIM_ICPrescaler:输入捕获通道预分频器,可设置 1、 2、 4、 8 分频,它设定 CCMRx寄存器的 ICxPSC[1:0]位的值。如果需要捕获输入信号的每个有效边沿,则设置 1 分频即可。
5-TIM_ICFilter:输入捕获滤波器设置,可选设置 0x0 至 0x0F。它设定 CCMRx 寄存器ICxF[3:0]位的值。一般我们不使用滤波器,即设置为 0。
其他常用函数:
1、 通道极性设置独立函数:
void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
如
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//OC1设置为上升沿捕获
2、获取通道捕获值
uint32_t TIM_GetCapturex(TIM_TypeDef* TIMx);
如
val=TIM_GetCapture2(TIM5);//把当前的捕获值赋给val
2、 计数清零:
void TIM_SetCounter(TIM_TypeDef* TIMx, uint32_t Counter);
如
TIM_SetCounter(TIM5,0); //TIM5计数清0
输入捕获例程:
TIM_ICInitTypeDef TIM5_ICInitStructure;
//定时器5通道1输入捕获配置
//arr:自动重装值(TIM2,TIM5是32位的!!)
//psc:时钟预分频数
void TIM5_CH2_Cap_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //GPIOA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0
GPIO_PinAFConfig(GPIOA,GPIO_PinSource1,GPIO_AF_TIM5); //PA0复用位定时器5
TIM_TimeBaseStructure.TIM_Prescaler=90 - 1; //定时器分频 1us计数器+1
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=0xffffffff - 1; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
//初始化TIM5输入捕获参数
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01 选择输入端 IC1映射到TI1上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //下降沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC2,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
//同时打开溢出中断和捕获中断
TIM_Cmd(TIM5,ENABLE ); //使能定时器5
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
}
//捕获状态
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到低电平;1,已经捕获到低电平了.
//[5:0]:捕获低电平后溢出的次数(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
uint8_t TIM5CH1_CAPTURE_STA=0; //输入捕获状态
uint32_t TIM5CH1_CAPTURE_VAL; //输入捕获值(TIM2/TIM5是32位)
//定时器5中断服务程序
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//最高位为0 还未成功捕获
{
if(TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)//溢出
{
if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到低电平了(捕获下降沿,但没有捕获上升沿)
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//低电平太长了 0011 1111 后六位用来计数
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
}
else TIM5CH1_CAPTURE_STA++;
}
}
if(TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕获1发生捕获事件 !=RESET 就是 == SET
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个上升沿
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次高电平脉宽 1100 0000 表示2次捕获完成
TIM5CH1_CAPTURE_VAL=TIM_GetCapture2(TIM5);//获取当前的捕获值.
TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为下降沿捕获, 开始下一轮捕获 //这个函数是用来修改捕获方式的,不用重新配置结构体
}
else //还未开始,第一次捕获下降沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿 0100 0000
TIM_Cmd(TIM5,DISABLE ); //关闭定时器5
TIM_SetCounter(TIM5,0); //计数清0
TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 设置为上升沿捕获
TIM_Cmd(TIM5,ENABLE ); //使能定时器5
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
}