重新开始学stm32(4)定时器中断实验

今天我们要来回顾的实验是定时器中断实验,我们直接跳过了看门狗,因为看门狗这个东西我在项目里或者平时的使用里面没有用到过,所以就暂时跳过它,如果后面有小伙伴想看或者我有时间的话会做仪器看门狗实验的回顾。回到今天定时器这个实验,这是我们第一次接触定时器这个东西,但是后面我们有很多东西都会用到定时器,比如做一个小车的项目,我们就可以使用定时器输出PWM来控制我们的轮子转动了。好了,废话不多说,马上进入正题。

 

实验目的

在这个实验我们将学习如何使用通用定时器的基本使用。

实验内容

因为我在初学的时候,按照正点原子的讲解视频,先了解寄存器再学习对应的函数,发现这样的学习顺序会导致在了解寄存器这一块会很蒙,因为对于大多数初学者来说,寄存器是一个很陌生很晦涩的东西,包括现在的我在寄存器这方面都有很多不懂的地方,所以我认为我们应该从我们熟悉的函数入手,再深入进去了解寄存器,同时让我们一起进步!!!

首先就是使能时钟,这里我们实验使用的是通用定时器TIM3。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

然后就是初始化我们要使用的定时器,这里我们初始化定时器使用的函数是TIM_TimeBaseInit(),然后再根据我们的需要配置定时器的参数,如自动装载值、预分频系数、计数方式等。其中我们的定时器的定时周期由自动装载值和预分频系数共同决定,具体的计算公式是Tout = ((arr+1)*(psc+1))/Tclk

arr是自动装载值;psc预分频系数;tclk是定时器的输入时钟频率,在stm32f1中是72MHz。

老规矩,我们先来看看TIM_TimeBaseInit()函数里用到的结构体TIM_TimeBaseInitTypeDef。

typedef struct
{
  uint16_t TIM_Prescaler;
  uint16_t TIM_CounterMode;
  uint16_t TIM_Period;
  uint16_t TIM_ClockDivision;
  uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;

第一个成员变量是预分频系数的设置;第二个成员变量是计数方式的选择;第三个成员变量是自动重装载值的设置;第四个成员变量是时钟分割的设置;最后一个参数 TIM_RepetitionCounter 是高级定时器才有用的,是配置高级定时器的重复计数功能。我们实验的配置如下。

TIM_TimeBaseStructure.TIM_Period = arr;                        //设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc;                      //设置预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;        //设置时钟分割(这里没有用到)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    //向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

配置完我们的定时器,下面就要使能相应的中断了,使能定时器中断我们使用的是TIM_ITConfig()函数,实验这里使用的是更新中断。

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);

其中第二个参数可以选择的有如下这些,都被定义在头文件stm32f10x_tim.h里边。

#define TIM_IT_Update                      ((uint16_t)0x0001)
#define TIM_IT_CC1                         ((uint16_t)0x0002)
#define TIM_IT_CC2                         ((uint16_t)0x0004)
#define TIM_IT_CC3                         ((uint16_t)0x0008)
#define TIM_IT_CC4                         ((uint16_t)0x0010)
#define TIM_IT_COM                         ((uint16_t)0x0020)
#define TIM_IT_Trigger                     ((uint16_t)0x0040)
#define TIM_IT_Break                       ((uint16_t)0x0080)

接下来就是配置中断的优先级了,这些都是老操作了,就不用进行代码示例了。

定时器配置的最后一步,使能相应的定时器。定时器使能函数是TIM_Cmd()。

TIM_Cmd(TIM3, ENABLE);

当然了,还有一步是编写中断服务函数,在中断服务函数里面写我们要周期进行的操作。而且要记得上一期我们讲到的,必须要先清中断标志位。

void TIM3_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		LED1=!LED1;
	}
}

讲完了函数的使用,我们就在这基础上进一步来了解认识一下寄存器,看看函数是怎么操作寄存器的,在这里我尽可能简单地讲,让大家都能理解其中的操作。

 首先,我们来了解控制寄存器1(TIMx_CR1),这个寄存器各个位的功能描述如图。

 

我们先看位4、5、6,是用来配置我们的计数方式的,在TIM_TimeBaseInit()函数里面我们输入的是TIM_CounterMode_Up。

#define TIM_CounterMode_Up                 ((uint16_t)0x0000)

在函数里面就是通过位操作把位4、5、6都置为0,就是对应的我们要设置的向上计数模式了。

tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;

TIMx->CR1 = tmpcr1;

再看位1,是用来配置我们计数器是否使能的,在TIM_Cmd()函数里面我们输入的是ENABLE。 

if (NewState != DISABLE)
{
    TIMx->CR1 |= TIM_CR1_CEN;
}
else
{
    TIMx->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
}

其中的 TIM_CR1_CEN有以下定义。

#define  TIM_CR1_CEN                         ((uint16_t)0x0001)

 在函数里面也是通过位操作把位1置为1,就使能计数器了。

再看第二个与实验有关的寄存器DMA/中断使能寄存器(TIMx_DIER),在这里我们看这个寄存器的第0位,这一位的更新中断允许位。在TIM_ITConfig()函数里面我们输入了参数TIM_IT_Update和ENABLE,同样也是通过位操作把这个位置为1,来允许更新产生中断。

if (NewState != DISABLE)
{
    TIMx->DIER |= TIM_IT;
}
else
{
    TIMx->DIER &= (uint16_t)~TIM_IT;
}

其他的寄存器在函数了的配置也是大同小异,其实我们使用函数就是在配置对应的寄存器来设置相应的功能。学会看懂寄存器和看懂库函数中对寄存器的操作,可以提高我们对代码的底层理解喔,这对我们的学习是很有帮助的,而且单片机的学习应用的最终归宿就是寄存器的学习应用。

这一期的实验主要就是要熟悉掌握定时器的配置使用,为后面的定时器进一步学习建立基础。

这一期实验的内容就到此结束了,喜欢的伙伴记得点赞关注加收藏喔!!!

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值