STM32F103 实例应用(5)——基本定时器


一、定时器简介

STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器通用定时器高级定时器
基本定时器 TIM6TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。
通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。
高级定时器 TIM1/8是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。
在这里插入图片描述

1.1 基本定时器功能

在这里插入图片描述

  1. ①时钟源
    定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M
  2. ②计数器时钟
    定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)
  3. ③计数器
    计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
  4. ④自动重装载寄存器
    自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。

1.2 基本定时器时基

基本定时器的核心是时基,不仅基本定时器有,通用定时器和高级定时器也有。基本定时器与通用定时器的时基有3个(TIMx_CNTTIMx_PSCTIMx_ARR)。高级定时器的时基有4个(TIMx_CNTTIMx_PSCTIMx_ARRTIMx_RCR)。

二、基本定时器使用流程

2.1 NVIC 设置

/**
 @brief NVIC初始化(使用TIM6基本定时器)
 @param 无
 @return 无
*/
void BASIC_TIM_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	// 设置中断组为 0
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	// 设置中断来源
	NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn ;
	// 设置主优先级为 0
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	// 设置抢占优先级为 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

2.2 定时器中断配置

在这里插入图片描述

/**
 @brief 定时器中断配置(使用TIM6基本定时器)
 @param 无
 @return 无
*/
void BASIC_TIM_Config(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	/*
	可以从上图看出基本定时器和通用定时器使用APB1总线,
	高级定时器使用APB2总线。
	*/
	// 开启定时器时钟,即内部时钟 CK_INT=72M
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

	/*
	预分频将输入时钟频率按1~65536之间的值任意分频,分频值决定了计数频率。
	计数值为计数的个数,当计数寄存器的值达到计数值时,产生溢出,发生中断。
	如系统时钟为72MHz,预分频 TIM_Prescaler = 71,
	计数值 TIM_Period = 1000,
	则 TIM_Period * (TIM_Prescaler + 1) / 72000000 = 0.001,
	即每1ms产生一次中断。
	*/
	// 自动重装载寄存器周的值(计数值)
	TIM_TimeBaseStructure.TIM_Period = 1000;
 
	// 累计 TIM_Period 个频率后产生一个更新或者中断
	// 时钟预分频数为 71,
	// 则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M
	TIM_TimeBaseStructure.TIM_Prescaler = 71;

	// 时钟分频因子 ,基本定时器没有,不用管
	//TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;

	// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
	//TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;

	// 重复计数器的值,基本定时器没有,不用管
	//TIM_TimeBaseStructure.TIM_RepetitionCounter=0;

	/*
	完成时基设置
	*/
	// 初始化定时器
	TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

	/*
	为了避免在设置时进入中断,这里需要清除中断标志位。
	如果是向上计数模式(基本定时器采用向上计数),
	则采用函数 TIM_ClearFlag(TIM6, TIM_FLAG_Update),
	清除向上溢出中断标志。
	*/
	// 清除计数器中断标志位
	TIM_ClearFlag(TIM6, TIM_FLAG_Update);

	// 使能计数器
	TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);

	// 开启计数器
	TIM_Cmd(TIM6, ENABLE);

	// 暂时关闭定时器的时钟,等待使用
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, DISABLE);
}

2.3 中断服务程序

#define BASIC_TIM_IRQHandler TIM6_IRQHandler
// 1ms发生一次中断,time 记录中断次数
uint16_t time;

void BASIC_TIM_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
	{
		time++;
		TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update);
	}
}

三、设计实例

board_timer.h

#ifndef BOARD_TIMER_H
#define BOARD_TIMER_H

/**************************************************
 * INCLUDES
 */
#include "stm32f10x.h"

/**************************************************
 * DEFINITIONS
 */
#define BASIC_TIM_IRQHandler TIM6_IRQHandler

/**************************************************
 * API FUNCTIONS
 */
void BASIC_TIM_Config(void);
void BASIC_TIM_NVIC_Config(void);

#endif

board_timer.c

#include "board_timer.h"

/**************************************************
 * GLOBAL VALUE
 */
uint16_t time;

/**************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief NVIC初始化(使用TIM6基本定时器)
 @param 无
 @return 无
*/
void BASIC_TIM_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	// 设置中断组为 0
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	// 设置中断来源
	NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn ;
	// 设置主优先级为 0
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	// 设置抢占优先级为 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

/**
 @brief 定时器中断配置(使用TIM6基本定时器)
 @param 无
 @return 无
*/
void BASIC_TIM_Config(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	/*
	可以从上图看出基本定时器和通用定时器使用APB1总线,
	高级定时器使用APB2总线。
	*/
	// 开启定时器时钟,即内部时钟 CK_INT=72M
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

	/*
	预分频将输入时钟频率按1~65536之间的值任意分频,分频值决定了计数频率。
	计数值为计数的个数,当计数寄存器的值达到计数值时,产生溢出,发生中断。
	如系统时钟为72MHz,预分频 TIM_Prescaler = 71,
	计数值 TIM_Period = 1000,
	则 TIM_Period * (TIM_Prescaler + 1) / 72000000 = 0.001,
	即每1ms产生一次中断。
	*/
	// 自动重装载寄存器周的值(计数值)
	TIM_TimeBaseStructure.TIM_Period = 1000;
 
	// 累计 TIM_Period 个频率后产生一个更新或者中断
	// 时钟预分频数为 71,
	// 则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M
	TIM_TimeBaseStructure.TIM_Prescaler = 71;

	// 时钟分频因子 ,基本定时器没有,不用管
	//TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;

	// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
	//TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;

	// 重复计数器的值,基本定时器没有,不用管
	//TIM_TimeBaseStructure.TIM_RepetitionCounter=0;

	/*
	完成时基设置
	*/
	// 初始化定时器
	TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

	/*
	为了避免在设置时进入中断,这里需要清除中断标志位。
	如果是向上计数模式(基本定时器采用向上计数),
	则采用函数 TIM_ClearFlag(TIM6, TIM_FLAG_Update),
	清除向上溢出中断标志。
	*/
	// 清除计数器中断标志位
	TIM_ClearFlag(TIM6, TIM_FLAG_Update);

	// 使能计数器
	TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);

	// 开启计数器
	TIM_Cmd(TIM6, ENABLE);

	// 暂时关闭定时器的时钟,等待使用
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, DISABLE);
}

main.c

#include "board_timer.h"

extern uint16_t time;

int main()
{
	/* 基本定时器 TIMx,x[6,7] 定时配置 */
	BASIC_TIM_Config();

	/* 配置基本定时器 TIMx,x[6,7]的中断优先级 */
	BASIC_TIM_NVIC_Config();
 
	/* 基本定时器 TIMx,x[6,7] 重新开时钟,开始计时 */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
 
	while(1)
	{
		if(time == 1000) 
		{ 
			/* 1000 * 1 ms = 1s 时间到 */
			time = 0;
			/* LED1 取反 */
			static uint8_t tmp = 0;
			/*LED1 反转*/
			if(tmp == 0)
			{
				// 该函数在GPIO输出章节中
				UseLibSetOutput(GPIOB, GPIO_Pin_0,0);
				tmp = 1;
			}
			else
			{
				// 该函数在GPIO输出章节中
				UseLibSetOutput(GPIOB, GPIO_Pin_0,1);
				tmp = 0;
			}
		}
	}
	return 0;
}

• 由 青梅煮久 写于 2021 年 01 月 06 日

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值