前言:之前学习了外部中断,这一次定时器中断相对就好理解了
总共14个定时器,2个基本定时器(TIM6 和TIM7),10个通用定时器(TIM2-TIM5,TIM9-TIM14)以及两个高级定时器(TIM1,TIM8).
注意:定时器其实也就是中断,所以学习定时器时应该带着学习中断的思想。只不过触发条件变为时间到达,所以自然定时器也会有前面学习的抢占式优先级和相应优先级。
基本定时器:就是我们51学习的普通的定时器。
通用定时器:在基本定时器基础上添加了一些功能(输入捕获和输出比较等功能)。
高级定时器又在通用定时器基础上又添加了一些功能。
1.他内置了预分频器,可以将系统的频率进行分频后作为定时器的频率,而51就是固定的。
2.支持向上计数、向下计数方式、中心计数对齐计数。向上计数是指从0数到装载值,向下是指从装载值向下数到0,而中心计数对齐是指从0数到装载值后执行事件,然后又数到零在执行事件
假设我们使用的是通用定时器TIM4。
1.使能定时器时钟
因为tim4挂接在APB1总线上,所以要先打开该总线上的tim4时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//**注意:执行完这个函数后,通用定时器的时钟频率为84MHZ**
2.对定时器的一些参数进行配置,包括重装值,分频系数,计数方式。
配置函数为:
第一个参数是哪个定时器,第二个定时器是一个结构体,所以自然先要求设置这个结构体。
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//建立一个结构体变量
TIM_TimeBaseInitStructure.TIM_Period = pre;//这里是设定重装值的。这里的pre是传递进来参数,因为到时候这些均在time_init()函数中
TIM_TimeBaseInitStructure.TIM_Prescaler = psc;//分频系数,就是把84MHZ分频
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//固定的,不动
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//运行这个函数
3.设置定时器中断类型,并使能
函数为TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
第二个参数为中断类型,有很多类型,这里为更新中断,还有触发中断,输入捕获中断等等。
4.因为定时器也是中断,所以也需要配置nvic
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
注意:自然主函数中的NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
别忘了
5.开启定时器
TIM_Cmd(TIM4,ENABLE);
6.写中断服务函数
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update)==1)
{
//if(GPIO_ReadOutputDataBit(GPIOF,GPIO_Pin_10)==0)
//{
//GPIO_SetBits(GPIOF,GPIO_Pin_10);
//}
//else
//{
//GPIO_ResetBits(GPIOF,GPIO_Pin_10);
//}
//}
GPIO_WriteBit(GPIOF,GPIO_Pin_10,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOF, GPIO_Pin_10)));
}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
注意:分析这一段代码,中断处理函数就是改变当前led的状态。开始我用的是2个if,但是有错,但是改为if else 就没问题。最后我在网上查到一个对io口取反的函数,就是代码中的。
补充:关于GPIO_SETBIT 和 GPIO_WriteBit,,前者可以对多个针脚操作,用|,后者只能每次对一个针脚操作。
led.h
void TIM4_Init(u16 pre,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//ÒòΪtim4¹ÒÔÚapb1×ÜÏßÉÏ£¬ËùÒÔҪʹÄÜ×ÜÏßµÄʱÖÓ.Ϊ84M
TIM_TimeBaseInitStructure.TIM_Period = pre;//ÉèÖö¨Ê±Æ÷µÄÖÜÆÚ£¬Ò²¾ÍÊ£×¢Ò⣺ÕâÀïΪ´«µÄ²ÎÊý
TIM_TimeBaseInitStructure.TIM_Prescaler = psc;//¶¨Ê±Æ÷Ô¤·ÖƵϵÊý
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//ͨ³£²»ÐÞ¸ÄËû£¬¹Ì¶¨µÄ£¬Ò»°ãÂ̲¨µÄʱºòÓÃ
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//ÏòÉϼÆÊý£¬´ÓÁ㿪ʼ¼ÆÊý£¬¼ÆÊýµ½ÖØ×°Öµ
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//³õʼ»¯Ò»ÏÂ
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);//ÅäÖÃÖжÏÀàÐÍ£¬ÕâÀïΪ¸üÐÂÖжÏ
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn;//ÅäÖÃnvic
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM4,ENABLE);//´ò¿ª¶¨Ê±Æ÷
}
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update)==1)
{
//if(GPIO_ReadOutputDataBit(GPIOF,GPIO_Pin_10)==0)
//{
//GPIO_SetBits(GPIOF,GPIO_Pin_10);
//}
//else
//{
//GPIO_ResetBits(GPIOF,GPIO_Pin_10);
//}
//}
GPIO_WriteBit(GPIOF,GPIO_Pin_10,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOF, GPIO_Pin_10)));
}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
main.c
int main()
{
RCC_HSE_Config(8,336,2,7);
Beep_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SysTick_Init(168);
key_init();
LED_Init();
TIM4_Init(5000-1,8400-1);//传的参数给重装值和分频系数
while(1)
{
}
}
重点:关于重装值和分频系数计算定时时间
这里重装值为5000,因为为向上计数,所以计数5000次,因为原先为84MHZ,分了8400后为84000000/8400=10000hz,所以输一次的时间为1/10000=0.0001s=0.1ms,所以5000次为500ms。但在写进函数时都要-1.