文章目录
前言
本章主要介绍STM32中的定时器外设,因为我个人写文章的主要目的是为了充当笔记的用途,所以我决定减少介绍的比例。(主要参考视频为《STM32入门教程-2023持续更新中》 作者:江协科技)
一、定时器(TIM)
1.1 介绍
定时器可以对输入的时钟进行计数,并在到达计数值时触发中断。
1.2 时基单元
时基单元是定时器的重要组成部分,其主要有以下部分组成:
- 16位计数器:简单来讲就是介绍中计数的部分,每来一个时钟都会使计数器加1,最大为2的16次方,即65536。
- 预分频器:即将输入的时钟进行分频,如果设置的为二分频而时钟为72MHz那么会被分频为36MHz。
- 自动重装寄存器:简单来讲就是存放目标值的寄存器,最大也同样为2的16次方。
1.3 定时器的种类
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
PS:我使用的STM32F103C8T6定时器资源仅有TIM1、TIM2、TIM3、TIM4。
二、通用定时器
上图看上去非常复杂,但是基本可以分为三大块
- 主要是由之前介绍的时基单元组成。
- 主要是内外时钟源的选择和主从触发模式的结构,第一个外部时钟是TIMx_ETR引脚的外部时钟,其复用在了PA0的位置,也就是在PA0接上一个外部方波时钟,然后配置内部极性选择、边沿检测和预分频电路,在配置滤波电路就可以在ETRF进入触发控制器,第二个外部时钟是TRGI即让定时器充当其他定时器的从模式。
- 主要是输入捕获功能和输出比较功能的结构,该内容会在之后进行详细的介绍。
三、定时中断基本结构
PS:在写代码时主要参考该结构图。
四、代码部分
1.1 接线图
1.2 初始化定时器
我们首先根据定时器中断结构来初始化定时器。
- RCC开启时钟
- 时钟源选择内部时钟模式
- 配置时基单元
- 配置输出控制
- 配置NVIC
- 运行控制
1.3 了解定时器库函数
- TIM_DeInit ---- 将TIMx外设寄存器初始化为其默认重置值
- TIM_TimeBaseInit ---- 配置时基单元
- TIM_TimeBaseStructInit ---- 赋予结构体变量默认值
- TIM_Cmd ---- 使能计数器(对应上图的运行控制)
- TIM_ITConfig ---- 对应中断输出控制
- TIM_InternalClockConfig ---- 对应时钟源选择中的内部时钟
- TIM_ITRxExternalClockConfig ---- 对应时钟源选择中的其他定时器
- TIM_TIxExternalClockConfig ---- 对应时钟源选择中的捕获通道
- TIM_ETRClockMode1Config ---- 对应时钟源选择中的外部时钟1
- TIM_ETRClockMode2Config ---- 对应时钟源选择中的外部时钟2
- TIM_ETRConfig ---- 配置ETR引脚的参数
- TIM_PrescalerConfig ---- 单独写入预分频值
- TIM_SetCounter ---- 单独给计数器写入值
- TIM_SetAutoreload ---- 单独写入自动重装寄存器的值
- TIM_GetCounter ---- 获取当前计数器的值
- TIM_GetPrescaler ---- 获取当前预分频器的值
1.4 初始化定时器代码部分
#include "stm32f10x.h" // Device header
extern uint16_t Num;
void Timer_init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启时钟
TIM_InternalClockConfig(TIM2); //选择内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBasestructure;
TIM_TimeBasestructure.TIM_ClockDivision = TIM_CKD_DIV1; //选择不分频
TIM_TimeBasestructure.TIM_CounterMode = TIM_CounterMode_Up; //选择向上计数
TIM_TimeBasestructure.TIM_Period = 10000 - 1; //ARR
TIM_TimeBasestructure.TIM_Prescaler = 7200 - 1; //PSC
// 72MHz/(ARR+1)/(PSC+1) 此处定时1s即1Hz
TIM_TimeBasestructure.TIM_RepetitionCounter = 0; //重复计数器
TIM_TimeBaseInit(TIM2,&TIM_TimeBasestructure);
TIM_ClearFlag(TIM2,TIM_IT_Update); //清楚标志位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
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);
}
1.5 主函数部分
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.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) //定时器2中断函数(在startup_stm32f10x_md.s中寻找)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET) //获取中断标志位
{
Num++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清楚标志位
}
}
五、实验现象
实验结果:每过1s中OLED屏幕中Num+1