stm32定时器(TIM)学习笔记(一)

stm32定时器(TIM)学习笔记

制作不易,求个点赞!

定时器本质上就是一个计数器:

现在小明与小红在一起玩游戏,小明每隔一秒从1数到100,小明在每数两个数之后小红会数一次,但是小红数到5之后又会从零开始数。

例如,小明数从1数到12后,小红会从1数到5之后归零从1开始数。

在这里插入图片描述

在这个游戏中,小明就是输入的时钟,小红就是计数器。

Part.1 TIM定时中断

1.时基单元

  • 计数器CNT :当有时钟源输入时,边开始计数。
  • 预分频器PSC :对于输入的时钟源,选择是每隔几个数计一次数。
  • 自动重装寄存器ARR: 当计数器计到最大值时,清零计数器。

2.定时器类型

在这里插入图片描述

stm32F103C8T6仅仅有TIM 1~4。

3.计数模式

在这里插入图片描述

对于基本计时器,仅仅只有向上计数这一种计数模式。

而通用定时器与高级定时器有向上计数、向下计数、中央对齐的计数模式。

4.

在这里插入图片描述

5.代码实现

5.1 TimerInit

Step 1. 因为Tim2在APB1上,所以开启APB1的外设时钟:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_Tim2,ENABLE);

Step 2.选择输入的时钟源,这里有这么几个函数可供选择:

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
//选择内部时钟源

在这里插入图片描述

void TIM ITRxExternalclockCoffig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
//选择其他定时器作为时钟源

在这里插入图片描述

void TIM_TIxExternalclockConfig(TIM TypeDef* TIMx, uint16_t TIM TIxExternalCLKSource
uint16_t TIM ICPolarity, uint16 t ICFilter);
外部引脚时钟
即同过检测引脚上的电平然后作为时钟源
TIM TIxExternalCLKSource 选择具体的某个引脚
uint16_t TIM ICPolarity, uint16 t ICFilter极性与滤波器
void TIM ETRClockModelConfig(TIM TypeDef* TIMx, uint16 t TIM ExtTRGPrescaler, uint16 t TIM E
uint16 t ExtTRGFilter);
//ExtTRGPrescaler再做一次分频率

在这里插入图片描述

void TIM ETRClockMode2Config(TIM TypeDef* TIMx, uint16 t TIM ExtTRGPrescaler,
uint16 t TIM ExtTRGPolarity, uint16 t ExtTRGFilter);
//和CLOCK1一样,可以互换

在这里插入图片描述

void TIM ETRConfig(TIM TypeDef* TIMx, uint16 t TIM ExtTRGPrescaler, uint16 t TIM ExtTRGPolar
uint16 t ExtTRGFilter);
//单独配置Prescaler之类的东西

由于我们这里选择使用内部时钟,所以直接输入如下代码即可

TIM_InternalClockConfig(TIM2);

Step 3.时基单元的配置

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
//定义初始化结构体
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 时钟分分频,可以滤除波动的干扰,可以取值1,2,4
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 配置计数器的模式。有Up,Down,CenterAligned3种。这选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
//周期的配置

TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
// 预分频的配置

/* 
假使我们要有一个一秒定时器,那么要怎么配置呢?

这里可以使用如下公式:

多少秒计数一次 =  时钟源/(预分频+1)(自动重装值+1)

这里设置为1秒一次,那么 1 = 72*10^6/10000/7200
*/
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
//高级计数器重复计数功能,实现多个周期后才进行一次中断的操作
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

5.2 TIM_ITconfig

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

使用该命令可以开启定时器中断

5.3 NVIC的配置

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//选择分组2,这里不懂的可以等过几天作者写出来关于中断的笔记,不过感觉大家伙应该都不是很能从作者这里收获到知识,这样吧,点赞破50就更新NVIC
	
	NVIC_InitTypeDef NVIC_InitStructure;
//定义NVIC结构体
	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);
//定义结构体
	

5.4 TIM_Cmd

	TIM_Cmd(TIM2, ENABLE);

打开TIM

5.5 配置中断函数

每个中断函数都不能由自己定义,都是由stm32自己定义的。如果想要编写中断函数,我们需要做的是查询到这个函数的名称,然后继续写入这个函数。

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

6.全代码:

Timer.c文件:

#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	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);
}

Tim.h文件

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

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);
	}
}

这里需要注意,我们所引用的Num变量在两个文件中出现过,这种情况要么是在另外一个文件中加上extern int num,要么是把中断函数移动到main.c中。

此外,在初始化TIM后,程序会立即启动TIM的中断一次,为了防止这一现象,应该加上clearflag这句话。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值