定时器顾名思义就是用来计算时间。
1.STM32F40x系列总共最多有14个定时器:
本次主要使用讲解通用定时器
高级定时器:TIME1 、TIME8
通用定时器: TIME2-TIME5,TIM9-TIM14
基本定时器: TIME6 、 TIME7
2.计数器模式
通用定时器计数模式有:向上计数、向下计数、中央对齐(向上向下双向计数模式)。
①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
③中央对齐模式(向上/向下计数):计数器从0开始计数到自动重装载值,产生一个计数器溢出事件,然后从自动重装载值向下计数到0并且产生一个计数器溢出事件;然后再从0开始重新计数。
2.1.编写过程简要
公式:Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk
T=1/f; T为s,f为Hz
arr:自动重装值 psc:时钟预分频数
Tclk:TIMX 的输入时钟频率(单位为 Mhz) Tout:TIMX溢出时间。
若arr=1000,psc=8400;定时器时钟84M,分频系数8400,那么Tclk84M/8400=10Khz
T=1/10000,T=0.1ms。0.1ms*1000=1s;
①使能定时器时钟。
RCC_APB1PeriphClockCmd();
②初始化定时器参数,设置自动重装值,分频系数,计数方式等。
TIM_TimeBaseInit();
③ 使能定时器。
TIM_ITConfig(); 允许定时器XX中断
TIM_ClearITPendingBit(); 清除中断标志位
TIM_Cmd();
④ 开启定时器中断,配置NVIC。
NVIC_Init();
⑥ 编写中断服务函数。
TIMx_IRQHandler();
//实现精准定时
//基本定时器计时
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
TIM_TimeBaseInitStructure.TIM_Period=5000-1; //自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=8400-1; //定时器分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInit(TIM6,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);//允许定时器2更新中断
NVIC_InitStructure.NVIC_IRQChannel=TIM6_DAC_IRQn; //定时器2中断
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00;
NVIC_Init(&NVIC_InitStructure);
}
3.输出比较PWM模式
若定时器为向上计数 PWM1模式且有效电平为低电平
注:PWM1模式下CNT<CCR,通道有效,否则无效
可见0-t1时间段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平(有效电平)。
t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平。
使用带比较通道的定时器
①在定时器的基础上加入输出比较结构体。
TIM_OCInitTypeDef
②配置输出比较参数,设置比较输出使能,比较输出模式,输出极性、脉冲宽度等。
TIM_OCxInit();
③ 使能预加载值配置
TIM_OCxPreloadConfig();(x为通道1-4)
注:若分频系数:84-1 arr值:2000-1 比较值:480-1
输送给定时器4的时钟频率为:(42MHz)APB1时钟频率*2/84=42*2/84=1Mhz
PWM周期为:在1Mhz的时钟频率下。1/1Mhz*2000=2ms
占空比为:高电平时间/PWM周期=480/2000=480/2000=24%
pwm频率为:1/pwm周期 = 1/2ms=500Hz f=1/t;
具体代码为:
//初始化GPIO端口
void PWM_GPIO_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //使能GPIOF总线
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //9号引脚
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; //上拉模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz; //响应速度100MHz
GPIO_Init(GPIOF,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //将GPIOF端口复用为功能TIM14
}
//配置定时器和输出比较通道
void PWM_CH1_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE); //使能定时器TIM14总线
TIM_TimeBaseInitStructure.TIM_Period=1000-1; //ARR 自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=84-1; //PSC 定时器分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数模式为向上计数
TIM_TimeBaseInit(TIM14,&TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; //模式为PWM1
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low; //低电平有效
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; //使能输出状态
TIM_OCInitStructure.TIM_Pulse=800-1;
TIM_OC1Init(TIM14,&TIM_OCInitStructure);
//TIM_OC1PolarityConfig(TIM14,TIM_OCPolarity_High); //可使能有效电平为高或低
TIM_OC1PreloadConfig(TIM14,TIM_OCPreload_Enable); //使能预加载值配置
TIM_Cmd(TIM14,ENABLE);
}
4.输入捕获模式
输入捕获模式可以用来测量脉冲宽度或者测量频率。
测量脉冲宽度:产生上升沿捕获并在下一个下降沿同时产生下降沿捕获
测量频率:当出现第二次上升沿时,发生第二次捕获。
输入通道(TIx) 会占用两个捕获通道(ICx)
信号由输入通道TI1 进入,信号会被分为两路,一路是 TI1FP1,另外一路是TI2FP2。其中一路是周期,另一路是占空比。配置为选定输入通道,确定触发信号,然后设置触发信号的极性(一旦设置好触发输入的极性,另外一路硬件就会自动配置为相反的极性捕获,无需软件配置)且模式控制器配置为复位模式
具体配置为:
//捕获输入定时器4的GPIO值
void PWM_IC_GPIO_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //使能GPIOD的时钟总线
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12; //选择引脚12
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN; //下拉模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz; //100MHz响应速度
GPIO_Init(GPIOD,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM4); //将GPIOD.12口复用为TIM4
}
//捕获输入定时器4通道1的值
void PWM_IC_CH1_init(void)
{
//PWM_IC_GPIO_init();
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能TIM4时钟
TIM_TimeBaseInitStructure.TIM_Period=10000; //自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=84-1; //预分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //选择TIM4通道1
TIM_ICInitStructure.TIM_ICFilter= 0x00; //无滤波
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising; //极性上升沿
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //不分频
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//不直连 进不去
TIM_ICInit(TIM4,&TIM_ICInitStructure);
TIM_PWMIConfig(TIM4,&TIM_ICInitStructure); //使能TIM IC配置
NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn; //中断为TIM4
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02; //响应优先级
NVIC_Init(&NVIC_InitStructure);
TIM_SelectInputTrigger(TIM4, TIM_TS_TI1FP1); //选择输入触发器
TIM_SelectSlaveMode(TIM4,TIM_SlaveMode_Reset); //选择从属模式为复位模式
TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable); //主从使能
TIM_ITConfig(TIM4,TIM_IT_CC1,ENABLE); //TIM捕获比较1中断源
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1); //清除比较1中断标志位
TIM_Cmd(TIM4,ENABLE); //使能定时器4
}
//测量脉宽和频率
float Duty_cycle=0;
float Frequency=0;
u16 CC1=0;
u16 CC2=0;
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_CC1)==SET) //检测TIM4比较1中断标志位是否发生
{
CC1=TIM_GetCapture1(TIM4); //获取TIM4 Input Capture 1值
CC2=TIM_GetCapture2(TIM4); //获取TIM4 Input Capture 1值
if(CC1!=0)
{
Duty_cycle=(float)(CC2+1)/(CC1+1)*100;
Frequency= (84000000/84)/(float)CC1;
}
else
{
CC1=0;
CC2=0;
}
}
TIM_ClearITPendingBit(TIM4,TIM_IT_CC1);
}