[STM32学习笔记] 3.TIM

【系列笔记为跟随UP主江协科技学习STM32过程的一些问题,同时方便日后忘记时复习,文中部分内容来源于UP主的PPT同时加入个人理解】

一.TIM简介

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

类型

编号

总线

功能

高级定时器

TIM1、TIM8

APB2

拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能

通用定时器

TIM2、TIM3、TIM4、TIM5

APB1

拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能

基本定时器

TIM6、TIM7

APB1

拥有定时中断、主模式触发DAC的功能

 

 二.定时器中断

1.定时器中断基本结构

 

2.定时器中断常用库函数

 

void TIM_DeInit(TIM_TypeDef* TIMx);//将指定的 TIM 外设重置为默认值。

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//配置 TIM 的时基结构体。

void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//将 TIM 时间基准结构体初始化为默认设置。

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);//使能或禁用指定的 TIM 外设。

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);//使能或禁用指定 TIM 的指定中断。

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);//将内部时钟驱动 TIM 外设。

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);//配置 TIM 的预分频器和自动重装载寄存器的重新加载方式。

void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);//配置 TIM 的计数器模式。

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);//使能或禁用 TIM 的自动重装载寄存器预加载功能。

void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);//设置 TIM 的计数器值。

void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);//设置 TIM 的自动重装载寄存器值。


uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);//获取 TIM 的当前计数器值。

uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);//获取 TIM 的预分频器值。

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//检查 TIM 的指定标志位的状态。

void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//清除 TIM 的指定标志位。

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);//检查 TIM 的指定中断标志位的状态。

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);//清除 TIM 的指定中断标志位。

3.定时器中断初始化

void Timer_EXITInit()
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3, ENABLE); //使能 APB1 时钟
	
	//将定时器2配置为内部时钟模式
	TIM_InternalClockConfig(TIM2);
	TIM_InternalClockConfig(TIM3);
	
	//初始化定时器时间基数
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; 				
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; 		// 设置时钟分频为不分频,对内部时钟无影响
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; 	// 设置计数模式
    TIM_TimeBaseInitStruct.TIM_Period = 10000-1; 					// 设置重载值
    TIM_TimeBaseInitStruct.TIM_Prescaler = 7200; 					// 设置预分频值
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; 				// 设置重复计数器为0,高级定时器参数
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); 				

	//清除中断标志位,避免上电进入中断
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);						
	TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
	
	//启用定时器的更新中断 (TIM_IT_Update 更新(溢出)中断)
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); 						
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); 						
    
	//设置中断优先级组为2位抢占优先级+2位子优先级
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);					
	
	//配置中断管理寄存器
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; 				//选择中断通道为TIM2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 		//设置抢占式优先级为1(0~2^2)
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 				//设置子优先级为1  (0~2^2)
    NVIC_Init(&NVIC_InitStructure);
}

4.定时器中断功能函数

void TIM2_IRQHandler()
{
	if(TIM_GetITStatus(TIM2,TIM_FLAG_Update) == SET)
	{
		

		TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
	}
}

五.TIM输出比较(PWM)

1.OC(Output Compare)输出比较,输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形 每个高级定时器和通用定时器都拥有4个输出比较通道。

2.输出比较模式:

模式

描述

冻结

CNT=CCR时,REF保持为原状态

匹配时置有效电平

CNT=CCR时,REF置有效电平

匹配时置无效电平

CNT=CCR时,REF置无效电平

匹配时电平翻转

CNT=CCR时,REF电平翻转

强制为无效电平

CNT与CCR无效,REF强制为无效电平

强制为有效电平

CNT与CCR无效,REF强制为有效电平

PWM模式1

向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平

向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平

PWM模式2

向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平

向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平

常用模式一/二产生PWM信号。 

3.输出比较基本结构:

 

4.TIM3产生频率1khz,占空比50%PWM信号代码如下:

void PWM_Init()
{
	// 使能TIM3时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	// 使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 配置GPIOA的引脚6为复用推挽输出
	GPIO_InitTypeDef GPIOA_InitStructure;
	GPIOA_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIOA_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIOA_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIOA_InitStructure);
	
	// 配置定时器(TIM3)为内部时钟模式
	TIM_InternalClockConfig(TIM3);
	
	// 配置定时器(TIM3)的时间基准参数
	TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure;
	TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//决定数字滤波器采样频率的参数(输入捕获)
	TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_TimeBase_InitStructure.TIM_Period = 100 - 1; // 频率=72MHz/720/100=1khz
	TIM_TimeBase_InitStructure.TIM_Prescaler = 720 - 1; // 设置预分频值为720,分频后计数器频率为72Mhz/720=100000;
	TIM_TimeBase_InitStructure.TIM_RepetitionCounter = 0;//产生单个周期的PWM信号
	TIM_TimeBaseInit(TIM3, &TIM_TimeBase_InitStructure);
	
	// 配置定时器(TIM3)的输出比较参数
	TIM_OCInitTypeDef TIM_OCInit_InitStructure;
	TIM_OCStructInit(&TIM_OCInit_InitStructure);//不对结构体互补输出成员赋值,先赋默认值
	TIM_OCInit_InitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInit_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//极性选择,高电平有效,若比较器输出高电平则为PWM高电平;低电平有效,若比较器输出低电平则为PWM高电平
	TIM_OCInit_InitStructure.TIM_OutputState = TIM_OutputState_Enable;//定时器通道使能
	TIM_OCInit_InitStructure.TIM_Pulse = 50; // 设置占空比为50%
	TIM_OC1Init(TIM3, &TIM_OCInit_InitStructure);
	
	// 使能定时器(TIM3)
	TIM_Cmd(TIM3, ENABLE);
}

5.运行过程修改预分频数和计数溢出值函数:

void updatePWMFrequency(uint16_t newPrescaler, uint16_t newPeriod) 
{

    TIM_Cmd(TIM3, DISABLE);   //关闭定时器后才可修改
    TIM_PrescalerConfig(TIM3, newPrescaler, TIM_PSCReloadMode_Immediate);// 配置新的预分频值,立即生效
    TIM_SetAutoreload(TIM3, newPeriod);//配置新的溢出值

    TIM_Cmd(TIM3, ENABLE);
}

6.PWM实现呼吸灯:

int main()
{
	OLED_Init();
	PWM_Init();
	delay_init();
	EXTI_LEDInit();
	while(1)
	{
		OLED_ShowString(1,1,"frequency:");
		OLED_ShowNum(1,11,100-Pulse,3);
		OLED_ShowChar(1,14,'%');
		for(i = 0;i <= Pulse;i++)
		{
			TIM_SetCompare1(TIM3,i);
			delay_ms(10);
		}
		for(i = Pulse;i > 0;i--)
		{
			TIM_SetCompare1(TIM3,i);
			delay_ms(10);
		}
	}
}

六.PWMI输入捕获

 1.输入捕获简介:IC(Input Capture)输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器和通用定时器都拥有4个输入捕获通道 可配置为PWMI模式,同时测量频率和占空比 可配合主从触发模式,实现硬件全自动测量。

2.频率测量方法:

        测频法:在时间T内,对上升沿计次,得到N,则频率 f=N / T,适用高频,频率越高标准时间内N越大,误差越小; 

        测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率 f=f c/ N,适用低频,频率越低,周期越长,N越大,误差越小;

        中界频率:测频法与测周法误差相等的频率点 f=sqrt(fc/T)。

3.主从触发模式:

 

         主模式:可以将定时器内部的信号,映射到TRGO引脚,用于触发别的外设,所以这部分叫做主模式。

        从模式:就是接收其他外设或者自身外设一些信号,用于控制自身定时器的运行,也就是被别的信号控制。

        触发源选择:就是选择从模式的触发信号源,触发源选择,选择指定的一个信号,得到TRGI,TRGI去触发从模式,从模式可以在这个列表里,选这择项操作来在自动执行。

相关函数;

void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);

 1.主模式输入信号选择(主模式暂不了解)

void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

2. 从模式输入信号选择,TIM_InputTriggerSource选择通道。(TIM_TS_TI1FP1)

void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);

 3.从模式选择:

复位模式(TIM_SlaveMode_Reset )– 选中的触发输入(TRGI)的 上升沿 重新初始化计数器,并且产生一个更新寄存 器的信号。
门控模式(TIM_SlaveMode_Gated)  – 当触发输入 (TRGI) 为高时,计数器的时钟开启。一旦触发输入变为低,则计
数器停止 ( 但不复位 ) 。计数器的启动和停止都是受控的。
触发模式(TIM_SlaveMode_Trigger )– 计数器在触发输入 TRGI 的上升沿启动 ( 但不复位 ) ,只有计数器的启动是受控
的。
外部时钟模式1( TIM_SlaveMode_External1) – 选中的触发输入 (TRGI) 的上升沿驱动计数器

4.输入捕获基本结构:

TIM3从上升沿开始计数,到达下降沿后触发TI1FP2,CCR2=CNT,到达上升沿后CCR1=CNT,同时触发从模式,CNT重置。频率=fc/CCR1,占空比=CCR2/CCR1。

 TIMx_CH1和TIMx_CH2可同时接入同一捕获寄存器测量不同参数。由TIxFPy进行配置,表示由通道x输入至通道y的捕获寄存器。

5.输入捕获初始化:

void IC_Init(void)
{
    // 使能TIM3定时器时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    // 使能GPIOA端口时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 配置GPIOA的GPIO_Pin_6引脚为上拉输入模式
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置TIM3定时器为内部时钟模式
    TIM_InternalClockConfig(TIM3);
    
    // 配置TIM3定时器的基本参数
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;      //计数器的溢出周期
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;      //设置计数器的时钟频率 1000000
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
    
    // 配置TIM3定时器的输入捕获参数
    TIM_ICInitTypeDef TIM_ICInitStructure;
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;	// 配置通道1
    TIM_ICInitStructure.TIM_ICFilter = 0xF;				// 配置输入滤波器
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;  //配置输入极性为上升沿触发
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;    // 设置输入分频系数为不分频
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;	// 配置输入源为直接映射到TI1
    TIM_ICInit(TIM3, &TIM_ICInitStructure);
    
    TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//配置TI1FP2,自动根据TIM_ICInitStructure配置为与TI1FP1相反,即下降沿触发计数,交叉映射到TI1FP2.
    
    // 选择TIM3从模式输入触发源为TI1FP1,即TI1FP1每次上升沿触发从模式
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
    // 选择TIM3定时器的从模式为自动清零(TI1PF1的上升沿清零CNT)
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
    
    // 启动TIM3定时器
    TIM_Cmd(TIM3, ENABLE);
}

 6.读取频率,占空比

uint32_t IC_GetFreq(void)
{
	return 1000000 / (TIM_GetCapture1(TIM3));
}

uint32_t IC_Getduty(void)
{
	return TIM_GetCapture2(TIM3)*100/TIM_GetCapture1(TIM3);
}

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值