定时器及相关应用
STM32相关定时器(原理部分)
stm32的定时器十分常用,以下为32的定时器相关数据:
定时器一般用于输入捕获和输出比较,32位定时器相对于16位定时器的精度更佳高,而根据实际情况我们选择不同的计数方式(仅输出比较而言,上或下技术和仅能够向上计数可以实现不同功能)
定时器有三种计数模式:
1.向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
2.向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
3.中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
下图为32定时器原理图(TIM2-TIM5,四个通道,如果是9-14的话下方仅有两个通道)
上边的框图可以分为4个部分:
1.时钟选择部分
2. 时基单元
3. 输入捕获
4. 输出比较
(1)时钟选择部分:
1.TIMxCLK_INT,即内部时钟CK_INT;
2.外部捕获比较引脚,引脚TI1FP1和TI1F_ED,外部引脚TI2FP2
3.外部触发输入ETR
4.内部触发输入,来自于另一个定时器的输出,对应于框图中的TRGO
(2)时基单元
其中包括:1.PSC分频器,分频后产生CK_CNT;2.CNT计数器,负责技术;3.自动重装载器,在相关事件触发后,将寄存器中的值装载到计时器中。
(3)输出比较(即PWM)
图为输出比较部分的示意图(4通道)
图中的计数模式为向上计数,使用PWM模式2,有效电平高(极性高)。具体的模式如下:
(4)输入捕获
使用时候需要以下步骤:
(1)设置输入捕获滤波器
(2)设置输入捕获极性
(3)设置输入捕获映射通道
(4)设置输入捕获分频器
(5)捕获到有效信号可以开启中断
代码部分
定时器中断代码
1.初始化部分
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); 使用定时器3的时钟
TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //波特率
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //分频为1
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//定时器初始化
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //定时器3溢出中断
TIM_Cmd(TIM3,ENABLE); //使能定时器3
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3的中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1ÇÀÕ¼ÓÅÏȼ¶1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //响应优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//中断使能
NVIC_Init(&NVIC_InitStructure);
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
{
LED1=!LED1;
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //发生溢出中断后要清除中断标志位
}
}
这里有两个函数查看中断状态标志位,
TIM_GetITStatus和TIM_GetFlagStatus
TIM_GetITStatus 函数中会先判断这种中断是否使能,使能了才去判断中断标志位,而TIM_GetFlagStatus 直接用来判断状态标志位。
PWM输出代码
1.初始化部分
检测高电平持续时间
void TIM14_PWM_Init(u32 arr,u32 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;//输出比较用的结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOF,&GPIO_InitStructure); //
TIM_TimeBaseStructure.TIM_Prescaler=psc; //
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上技术
TIM_TimeBaseStructure.TIM_Period=arr; //
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM1输出
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //有效电平为低
TIM_OC1Init(TIM14, &TIM_OCInitStructure); //通道1初始化,其实按理说不同通道的比较值可以不一样,但是要用到TIM_SetCompare1
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); //CCRx寄存器使用
TIM_ARRPreloadConfig(TIM14,ENABLE);//ARR寄存器使能
TIM_Cmd(TIM14, ENABLE);
}
---------------------------------------------------------------------------
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//
delay_init(168);
TIM14_PWM_Init(500-1,84-1);
while(1)//呼吸灯程序
{
delay_ms(10);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
TIM_SetCompare1(TIM14,led0pwmval); //改变通道一比较值,修改占空比
输入比较代码
void TIM14_PWM_Init(u32 arr,u32 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOF,&GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Prescaler=psc;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //
TIM_TimeBaseStructure.TIM_Period=arr;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OC1Init(TIM14, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM14,ENABLE);
TIM_Cmd(TIM14, ENABLE); //发出脉冲的部分
}
TIM_ICInitTypeDef TIM5_ICInitStructure;
void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5);
TIM_TimeBaseStructure.TIM_Prescaler=psc;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period=arr;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到T1上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
TIM_Cmd(TIM5,ENABLE );
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
u8 TIM5CH1_CAPTURE_STA=0;
u32 TIM5CH1_CAPTURE_VAL;
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)
{
if(TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40)
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)
{
TIM5CH1_CAPTURE_STA|=0X80;
TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕获到高电平,前提是捕获到低电平
TIM5CH1_CAPTURE_STA|=0X80;
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //极性改变为上升沿
}else
{
TIM5CH1_CAPTURE_STA=0; //每次遇到高电平就归零
TIM5CH1_CAPTURE_VAL=0;
TIM5CH1_CAPTURE_STA|=0X40; //捕获到高电平的标志
TIM_Cmd(TIM5,DISABLE);
TIM_SetCounter(TIM5,0);//清零,开始进入
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //把极性改变为下降沿
TIM_Cmd(TIM5,ENABLE );
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);
}