stm32之定时器中断

前言:之前学习了外部中断,这一次定时器中断相对就好理解了


一、stm32的定时器组成

总共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.

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值