工程可见Github<传送门>
由前述博文《蓝桥嵌入式之 CT117E板载功能介绍》及《STM32F103RBT6》的DataSheet可知,STM32F103RBT6一共有七个定时器,包括1个高级定时器(16-bit),3个通用定时器(16-bit),2个看门狗定时器(16-bit)和1个滴答定时器(24-bit).
本次将要介绍其中的通用定时器中断。当然前提还需要一个STM32的重要知识点,关于中断向量嵌套,如果尚不清楚,可先移步<这里>进行知识补充。
当然还有关于STM32定时器配置相关知识,也可移步<这里>进行补充。
大部分代码和《蓝桥嵌入式之 闪烁LED》一样,这里只贴出不一样的代码
main.c
/*******************************************************************************
* 文件名:main.c
* 描 述:
* 作 者:CLAY
* 版本号:v1.0.0
* 日 期: 2019年1月24日15:19:30
* 备 注:定时器的方式实现PC8对应的LED1隔1s一闪
*
*******************************************************************************
*/
#include "stm32f10x.h"
#include "led.h"
#include "timer.h"
int main(void)
{
LEDInit();
TIM2Init(10000, 7200);
while(1)
{
}
}
timer.c
#include "timer.h"
void NVIC_TIM2Enable(void)
{
NVIC_InitTypeDef NVIC_initstructure;
NVIC_initstructure.NVIC_IRQChannel = TIM2_IRQn; //选择TIM2中断通道
NVIC_initstructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道
NVIC_initstructure.NVIC_IRQChannelPreemptionPriority = 0; //设定抢占优先级为0
NVIC_initstructure.NVIC_IRQChannelSubPriority = 0; //设定响应优先级为0
NVIC_Init(&NVIC_initstructure);
}
void TIM2Init(u16 period, u16 prescaler)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//注意TIM2在APB1总线上
TIM_TimeBaseStructure.TIM_Period = period-1;
TIM_TimeBaseStructure.TIM_Prescaler = prescaler-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
NVIC_TIM2Enable();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//严谨起见,这里清一下0
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//使能中断
TIM_Cmd(TIM2, ENABLE);//使能定时器
}
timer.h
#ifndef _TIMER_H
#define _TIMER_H
#include "stm32f10x.h"
void TIM2Init(u16 period, u16 prescaler);
#endif
stm32f10x_it.c
...
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_FLAG_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);
GPIOC->ODR ^= (1<<8);//PC8不断取反
GPIOD->ODR |= (1<<2);//PD2置1,使能573锁存器
GPIOD->ODR &= ~(1<<2);//PD2清0,关闭573锁存器
}
}
...
通用定时器的配置步骤可总结为:
配置TIM_TimeBaseStructure结构体成员 -> NVIC中断优先级设置 -> 清除中断标志位 -> 中断初始化 -> 使能定时器
1、NVIC_initstructure.NVIC_IRQChannel = TIM2_IRQn; //选择TIM2中断通道
关于NVIC中断通道的确定可在stm32f10x.h
对应的STM32F10X_MD
中找到对应的名称。
2、RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//注意TIM2在APB1总线上
STM32F103的通用定时器和基本定时器在APB1总线,高级定时器APB2总线上。
3、TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//使能中断
前最好清除一下中断标志位TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//严谨起见,这里清一下0
。因为固件库的定时器初始化函数默认会产生更新事件并触发更新中断标志位,如果此时使能中断,程序将立即执行中断函数。
4、在系统时钟为72M的前提下,STM32的AHB和APB2总线最大时钟频率为72M,而APB1时钟的最大频率为36M。TIM2是挂载到APB1总线上的,但是我们在主函数中可以看到,计算定时时间仍然使用72M,这个是为什么呢?可移步<这里>
5、关于中断函数名字TIM2_IRQHandler
是如何确定呢?
51是通过使用interrupt
关键字,通过这个关键字后面的数字来映射中断向量地址。而STM32在启动文件中已经为用户做好了一切,只需要用户编写相应的中断函数时,函数名称和启动文件相对应即可!