通用定时器
定时器功能:(经过一定时间后执行一定事情)设定一个时间,达到时间后产生一个中断信号,执行相应的中断函数;
stm32的定时器有很多,不同的定时器挂在不同的时钟上;2-7常用定时器挂在APB1总线上,时钟是PCLK1。1\8 定时器挂APB2总线下:如下图
image-20220114224730383
通用定时器是一个通过可编程预分频器(PSC)驱动的16位自动重装载计数器(CNT)构成的。
分析:有一个可编程预分频器,有1个计数器和一个和他同大小的寄存器保证可以重装载。
简单使用STM3通用定时器的相关寄存器:
寄存器 | 功能 |
---|---|
TIMxCR1控制寄存器 | 使能定时器、请求源、单脉冲,计数方向,对其方式,自动充装载、分频因子 |
TIMx_ DIER 中断允许寄存器 | 第0位是更新中断允许位 |
TIMx_PSC 预分频器寄存器 | 对时钟进行分频,调整定时时间 |
TIMx_CNT | 计数器,记录当前定时器的数值 |
TIMx_ARR | 自动重装载寄存器(有两个寄存器),和配置有关系具体查看《stm32库函数编程手册》 |
寄存器图片:
image-20220114230517559
image-20220114230556405
image-20220114230624548
[图片上传失败...(image-873db9-1642175186152)]
库函数TIM3定时开关led灯案例
// 定时器实验
#include <stm32f10x_tim.h>//包含了TIM定时器的部分函数
#include <stm32f10x.h>//有中断通道
#include <led_my.h>
#include <key_my.h>
void TIM3_IRQHandler(){//定时器中断函数
//检查TIM中断是否发生,判断ITM3的(类似中断标识寄存器中的TIM_IT_Update更新中断位是否为1)
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET){
LedTurn();//开关led
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清空掉中断挂起的位。便于下次进入的时候判断
}
}
void InitTIM3(uint16_t pre,uint16_t period){//TIM3定时器初始化;
NVIC_InitTypeDef nvicinitconfig;//由于有中断函数,所以要配置中断优先级
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//TIM3挂在APB1时钟上。所以使用APB1开启TIM3时钟。
TIM_TimeBaseInitTypeDef tim_timebaseinitconfig;//TIM定时器配置结构
tim_timebaseinitconfig.TIM_Prescaler=pre;//72*(10^6)/7200=1000次\s,也就是跳一次一毫秒;配置预分频
tim_timebaseinitconfig.TIM_CounterMode=TIM_CounterMode_Down;//配置计数方式;(注意计数方式和对其方式同时配置的)
tim_timebaseinitconfig.TIM_ClockDivision=TIM_CKD_DIV1;//不知道为什么是这个值,他是定时器时钟和数字滤波器时钟之间的分频比例
tim_timebaseinitconfig.TIM_Period=period;//计数周期值,就是记几个数(跳变几次)(等同于于51(溢出值-初值))
TIM_TimeBaseInit(TIM3,&tim_timebaseinitconfig);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//选择开启的定时器中断通道;定时器有过个通道,(更新通道指的是上/下有溢出值被更新)
// 配置NIVC中断优先级
nvicinitconfig.NVIC_IRQChannel=TIM3_IRQn;//由于是TIM3所以使用TIM3中断通道;在 stm32f10x.h中的 #ifdef STM32F10X_HD宏中查看;
nvicinitconfig.NVIC_IRQChannelCmd=ENABLE;
nvicinitconfig.NVIC_IRQChannelPreemptionPriority=2;
nvicinitconfig.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&nvicinitconfig);
TIM_Cmd(TIM3,ENABLE);//开启TIM3定时器
}
int main(int argc, char const *argv[])
{
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
LedInit();
delay_init();
LedClsoe();
InitTIM3(7199,9999);
while (1){
};
return 0;
}
定时器的时间计算方法
Tout=((arr+1)*(psc+1))/TCLK;
//Tout是溢出时间
//arr是计数周期
//psc是预分频器中的值
//TCLK是驱动定时器的时钟,像TIM3是在APB1中的在<system_stm32f10x.h>中的 void SystemInit (void);和static void SetSysClockTo72(void);函数已经将系统时钟设置完成了,当前这块板子的系统时钟是72Mhz,APB1使用了二分频,当APB1使用二分频时挂载在其上的TIM的时钟将是APB1的两倍;如下图:
image-20220114233512621
下面是配置72Mzh的系统时钟频率函数可以看到APB1的时钟配置;
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK/2 */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;//这一行配置PCLK1是HCLK的一半就是二分频。可以在《stm32中文参考手册中》6.32节中查看CFGR寄存器的位含义;