0x04 TIM

本文的大部分内容来自B站up主 江协科技, 此文只供本人学习记录用途, 侵删

一、TIM

  • TIM(Timer)定时器定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
  • 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
  • 由于高级定时器还没玩明白,所以本博客只涉及通用寄存器

image-20231031172717705

二、计时器原理

image-20231031173538770

CK_PSC进来经过分频,输出CK_CNT到计数器CNT,CNT++到和自动重装寄存器ARR相等后,CNT=0,然后将TIM_IT_Update置位,并请求中断

原理不难,说几个注意点

  1. 带黑框的是影子寄存器,也叫缓冲寄存器,如果开启,当你往里写新的值时不会立刻生效,等到CNT被清0后新一轮周期开始时才填入新值

  2. CK_CNT=CK_PSC/(PSC+1)

    溢出频率:

    CK_CNTOV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)(ARR+1)

    也就是说,当你想要使溢出频率为1hz

    需要满足:1=72*10^6/(PSC+1)(ARR+1)

    也就是(PSC+1)(ARR+1)=72*10^6

    可以使PSC=7200-1,ARR=10000-1(不固定)

三、库函数

做一个计数器,只需要以下几个库函数

image-20231031175042513

image-20231031175020663

image-20231031180940727

image-20231031175051778

image-20231031175134972

四、常用配置代码

配置框图:

image-20231031175336615

内部时钟源时钟:

void Timer_Init(void){
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启TIM2时钟
	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;//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//PSC
	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=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);//初始化NVIC
	//开启时钟
	TIM_Cmd(TIM2, ENABLE);
}

//中断服务函数
void TIM2_IRQHandler(void){
	if(TIM_GetITStatus(TIM2, TIM_IT_Update)==SET){
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

外部时钟源时钟:(代码都是差不多的,只多了GPIO和外部时钟源配置)


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;
	//PA0复用功能为TIM2_CH1_ETR(也就是TIM2的外部时钟源引脚)
	//初始化PA0为上拉输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, 	TIM_ExtTRGPolarity_NonInverted, 0x0F);
    /*
    	参数:
    	TIM2选择定时器2
    	TIM_ExtTRGPSC_OFF关闭外部触发预分频器
    	TIM_ExtTRGPolarity_NonInverted选择极性,这里上升沿有效
    		TIM_ExtTRGPolarity_Inverted的话就是下升沿有效
    	0x0f 外部滤波器的值0x00-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_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);
}

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

五、SysTick

systick是一个基于M3、M4内核的一个简单的24bit,倒计时,自动重装载定时器,倒计时结束会产生一个中断。常用于做延时,在实时系统中做心跳时钟,用于任务的切换。

systick定时器,就是系统滴答定时器
24位自动重装载倒计时定时器
当倒计时到0时,将从RELOAD寄存器中自动重装载初值
只要不清除SysTick控制及状态寄存器的使能位,就永不停息,在睡眠模式下也能工作
systick倒计时结束,会产生一个中断,且中断优先级可以设置

在这里插入图片描述

void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;				//设置定时器重装值
	SysTick->VAL = 0x00;					//清空当前计数值
	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}


void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}`
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值