STM32定时器定时中断学习打卡(代码注释)
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
uint16_t Num;
int main(void)
{
OLED_Init();
Timer_Init();
OLED_ShowString(1, 1, "Num:");
while (1)
{
OLED_ShowNum(1, 5, Num, 5);
}
}
//void TIM2_IRQHandler(void)
//{
// if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
// {
// Num ++;
// TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
// }
//}
Timer.c
#include "stm32f10x.h" // Device header
extern uint16_t Num;//使用extern声明主函数的Num变量,可在本程序中直接使用Num变量
/*定时中断基本结构
第一步:RCC开启时钟
第二步:选择时基单元的时钟源(对于定时中断选择内部时钟源)
第三步:配置时基单元(包括预分频器、自动重装器、技术模式等)
第四步:配置输出中断控制,允许更新中断输出到NVIC
第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级
第六步:运行控制
整个模块配置好后还需要使能一下计数器
定时器使能后,计数器开始计数,当计数器更新时,触发中断
最后写中断函数,该函数每隔一定时间自动执行一次*/
/*本程序采用TIM2,即通用计时器*/
void Timer_Init(void)
{
//第一步,RCC开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开启时钟
//这里注意需要使用APB1开启时钟(TIM2(通用时钟)是APB1总线的外设)
//第二步,选择时基单元的时钟源(对于定时中断选择内部时钟源)
TIM_InternalClockConfig(TIM2);//选择内部时钟,TIM2的时基单元由内部时钟驱动
//第三步,配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义结构体变量
//引出各个变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数的模式
//溢出频率=72M/(PSC+1)/(ARR+1)
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//周期设定(ARR,自动重装器的值)
//计10000个数,ARR从0自增到9999
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//PSC,预分频器的值
//对72MHz进行7200分频,得到10K的计数频率,在10K的频率下计10000个数,即1秒
//预分频器和计数器都有一个数的偏差,故减1
//注意:PSC和ARR的取值应当在0~65535之间,不要超出范围
//PSC和ARR的取值不唯一
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器的值,在高级定时器中才需要
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//第四步:配置输出中断控制,允许更新中断输出到NVIC
TIM_ClearFlag(TIM2, TIM_FLAG_Update);//防止复位后(按下复位键)
//立即自动执行一次中断(初始化完就进行更新中断)
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//使能中断
//第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC优先级分组
NVIC_InitTypeDef NVIC_InitStructure;//结构体变量定义
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);//启动定时器
}
/*
中断函数:
当定时器产生更新中断时,此函数会自动进行*/
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//获取中断标志位,检查中断标志位
{
Num++;//此处采用的方法是使用extern将主函数的变量Num声明后使用,
//也可以将本中断函数置于主函数main.c中
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除中断标志位
}
}
/*
相关函数:
TIM_DeInit()函数:恢复缺省设置
TIM_TimeBaseInit()函数:时基单元初始化
TIM_TimeBaseStrructInit()函数:把结构体变量赋一个默认值
TIM_Cmd()函数:使能计数器(运行控制)
TIM_ITConfig()函数:使能外设中断输出信号(中断输出控制)
TIM_InternalClockConfig()函数:选择内部时钟
TIM_ITRxExternalClockConfig()函数:选择ITRx其他定时器的时钟,选择要配置的定时器
InputTriggerSource()函数:选择要接入哪个其他的定时器
TIM_TIxExternalClockConfig()函数:选择TIx捕获通道的时钟
TIM_ETRClockMode1Config()函数:选择ETR通过外部时钟模式1输入的时钟
TIM_ETRClockMode2Config()函数:选择ETR通过外部时钟模式2输入的时钟
TIM_ETRConfig()函数:单独用来配置ETR引脚的预分频器、极性、滤波器的参数
初始化结构体内有关参数,比如自动重装值和预分频值等,
为了在初始化后更改需要,而不必再次初始化函数,故使用一些单独的函数方便地更改关键参数
TIM_PrescalerConfig()函数,用于单独写预分频值
TIM_CounterModeConfig()函数,用来改变计数器的计数模式
TIM_ARRPreloadConfig()函数,用于自动重装器预装功能配置
TIM_SetCounter()函数,给计数器写入一个值
TIM_SetAutoreload()函数,给自动重装器写入一个值
TIM_GetCounter()函数,获取当前计数器的值
TIM_GetPrescaler()函数,获取当前的预分频器的值
*/
Timer.h
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
#endif