前言
本篇文章属于stm32单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。
STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili
一、TIM简介
二、定时器类型
三、基本定时器框图
向上的箭头UI表示,计数值等于重装值产生的中断称为“更新中断”,之后会通往NVIC,再配置好NVIC的定时器通道,定时器更新中断就能得到CPU的响应了
向下的箭头U表示,“更新事件”,其不会触发中断,但能触发内部其它电路的工作
可以将U更新事件映射到TRGO上,然后TRGO就会直接去触发DAC了,实现硬件自动化
四、通用定时器框图
通用定时器支持向上计数模式和向下计数模式和中央对齐模式
向上计数模式是从0自增,增到重装值(基本定时器仅支持这一模式)
向下计数模式是从重装值自减,减到0
中央对齐模式是先从0自增,增到重装值,再从重装值自减,减到0
ETRF提供外部时钟,就是“外部时钟模式2”
当TRGI当作外部时钟来使用时,就是“外部时钟模式1” ,ITR是来自其它定时器的时钟信号(具体连接关系参考下表),实现定时器的级联
五、定时中断基本结构
六、预分频器时序
预分配缓冲器(影子寄存器) 才是真正起作用的,预分频控制寄存器的供我们读写的,作用是当计数值计到一半时,改变分频系数,其计数频率不会立马发生改变,而是在下一个计数周期才真正改变频率
七、计数器时序
更新中断标志(UIF)需要我们在中断程序中手动清零
1. 计数器无预装时序
2.计数器有预装时序
有预装就是启用了影子寄存器,作用与分频器的影子寄存器类似,不过这里对应的是重装值
八、RCC时钟树
九、实例一(定时器定时中断)
1.开启内部时钟
2.设置为内部时钟模式
3.时基单元初始化
4.清除系统启动产生的中断标志位(不然一启动就会产生一个中断事件)
5.中断输出控制
6.NVIC分组及初始化
7.运行控制(开启计数)
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 = 1000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//清除系统启动产生的中断标志位
TIM_ClearFlag(TIM2, TIM_IT_Update);
//中断输出控制
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
//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)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
*/
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);
OLED_ShowNum(2,5,TIM_GetCounter(TIM2),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
/**
* @brief 定时器2初始化
* @param 无
* @retval 无
*/
void Timer_Init(void)
{
//开启内部时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//初始化GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//设置为外部时钟模式2
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
//时基单元初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//清除系统启动产生的中断标志位
TIM_ClearFlag(TIM2, TIM_IT_Update);
//中断输出控制
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
//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);
}
/**
* @brief 获取TIM2的计数值
* @param 无
* @retval 计数值
*/
uint16_t Timer_GetCounter(void)
{
return TIM_GetCounter(TIM2);
}
/**
* @brief 定时器2中断函数
* @param 无
* @retval 无
*/
/*
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
*/
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:");
OLED_ShowString(2,1,"CNT:");
while (1)
{
OLED_ShowNum(1,5,Num,5);
OLED_ShowNum(2,5,Timer_GetCounter(),5);
}
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
{
Num++;
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}