STM32定时器中断原理及模板代码
———————————————————————————————————————————
主要关注预分频器和中断重装载寄存器和计数器,这三个寄存器合称为时基单元
基本定时器只能使用内部时钟(频率为72MHz)
预分频器:
可以用预分频器将72MHz分频
将预分频器设置为0时,表示1分频(或不分频),设置为1时,表示2分频
分频系数 = 预分频值 + 1
取值范围:16位(0~65535)
分频范围:0~65536
自动重装载寄存器:
当计数器里的计数值大于自动重装载值时,将会产生更新中断(UI(Updata Interrupt))信号,
该信号会发往NVIC,要NVIC处理该中断信号要配置好NVIC的定时器中断通道。
也会产生一个更新事件(U)信号,该信号不会触发中断,但会触发其他电路工作
同理,要某个设备处理该更新事件信号也要配置好该设备的事件通道
自动重装载寄存器也可以由更新事件(U)信号来控制
——————————————————————————————————————————
通用定时器中间有一个时基单元
红色框框柱的部分是内外时钟源选择和主从触发模式的结构
ETR引脚上的就是外部时钟源,由引脚定义表可以看出TIM2_CH1_ETR在PA0口上
ETR后要经过极性选择、边沿检测、预分频、滤波器的配置
信号经过滤波器之后兵分两路,如果直接经过ETRF,就可以直接作为时基单元的时钟了
在STM32中这一路称为外部时钟模式2
当TRGI(可以当时钟使用,也可以当触发输入(主要)使用,可以触发定时器从模式)当做外部时钟使用的时候,这一路就称为外部时钟模式1。
TRGI可以选择用ETR、ITR(这部分时钟信号来自其他定时器,ITR0到ITR3分别来自其他4个定时器的TRGO输出,可以实现定时器级联)、TL1F_ED(从CH1引脚获取时钟,ED是边沿的意思,也就是这个引脚输入的时钟上升沿下降沿均有效)、TL1FP1(CH1引脚上的时钟,只能选一个边沿)、TL2FP2(CH2引脚上的时钟,只能选一个边沿)
TRGO是定时器的主模式输出:
可以将更新事件映射到该引脚,用于触发DAC(数字模拟转换器,主要功能是将数字信号转换为模拟信号)或ADC(模数转换器,主要功能是将连续的模拟信号转换为离散的数字信号)。可以接到其他定时器的ITR引脚上,来实现定时器级联,全过程不需要CPU参与
主从怎么分!主动输出信号就是“主”,被动输入信号就是“从”
———————————————————————————————————————————
高级定时器左上这一大部分都是通用定时器的结构,没有发生变化
发出更新信号的地方多了一个重复计数寄存器,有了这个计数器之后就可以实现每隔几个计数周期才发生一次更新信号
———————————————————————————————————————————
定时器简图:
预分频器的时序:
CK_PSC是时钟源信号,PSC是预分频寄存器的值
图中有阴影的寄存器都是有缓冲寄存器(影子寄存器)的,真正起作用的是影子寄存器,这个影子寄存器用或不用是可以自己设置的
计数器时序:
APR是自动重装载寄存器的值
———————————————————————————————————————————
RCC时钟树:
系统时钟是所有外设的基础,所以系统时钟也是最先要配置的。
程序主函数之前还会执行一个SystemInit函数,这个函数就是用来配置这个时钟树的
可以先将此图分为两部分,左边是系统时钟的产生电路,右边是系统时钟的分配电路
———————————————————————————————————————————
使用内部时钟产生中断模板代码:
#include "stm32f10x.h"
uint16_t Timer_Count = 0;//定义中断计数值
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimerBaseInitStructure;//定义时基单元初始化传参结构体
NVIC_InitTypeDef NVIC_InitStructure;//定义NVIC初始化传参结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//使能定时器2
TIM_InternalClockConfig(TIM2);//给TIM2使用内部时钟
TIM_TimerBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//滤波器的时钟(采样频率,不稳定就保持上次输出,稳定了才输出)分频设置为TIM_CKD_DIV1(不分频)
TIM_TimerBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数模式设置为向上计数
TIM_TimerBaseInitStructure.TIM_Period = 10000 - 1;//自动重装值(0~65535)
TIM_TimerBaseInitStructure.TIM_Prescaler = 7200 - 1;//预分频值(0~65535)
TIM_TimerBaseInitStructure.TIM_RepetitionCounter = 0;
//重复计算器值(高级寄存器才有,TIM2是通用寄存器没有这个)
TIM_TimeBaseInit(TIM2,&TIM_TimerBaseInitStructure);//传入参数
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清除TIM2的更新中断标志位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能定时器TIM2更新中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置优先级分组模式
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//选择TIM2的中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//打开TIM2的中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级
NVIC_Init(&NVIC_InitStructure);//传入参数
TIM_Cmd(TIM2,ENABLE);//打开TIM2
}
void TIM2_IRQHandler(void)//中断处理函数
{
if (TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//判断当TIM2的更新中断标志位为SET的时候
{
Timer_Count++;//计数值+1
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标准位
}
}
uint16_t Timer_Count_Get(void)//传参函数,将头文件的变量值传回给主函数
{
return Timer_Count;//返回计数值
}
——————————————————————————————————————————
使用外部时钟产生中断模板代码:
void Timer_Init_ETR(void)
{
TIM_TimeBaseInitTypeDef TIM_TimerBaseInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//PA0引脚是ETR,所以要使能GPIOA端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//默认为上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//引脚0
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIOA口
TIM_ETRClockMode1Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_Inverted,0x0F);
//使用外部时钟模式2配置,外部时钟预分频器设置为关闭,外部触发极性设置为下降沿有效,滤波器配置
值为0X0F
TIM_TimerBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimerBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimerBaseInitStructure.TIM_Period = 2-1;//(0~65535)
TIM_TimerBaseInitStructure.TIM_Prescaler = 1 - 1;//(0~65535)
TIM_TimerBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&TIM_TimerBaseInitStructure);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
//其他没注释的或没写出来的和内部时钟中断的代码一样
作者:cykaw2590