4STM32(stdl)TIM定时器

一、定时器的介绍

定时器的作用:对输入的时钟脉波进行计数,在计数达到预定值时触发中断。

分类:高级定时器,通用定时器,基本定时器。

(高级定时器的功能主要面向三相无刷电机)

(STM32F103C8T6只有定时器TIM1~TIM4)

其他功能:选择内外时钟源,输入捕获,输出比较,编码器接口,主从触发模式。

二、定时器的结构

(一)基本定时器

1.定时器的计时系统

预分频器,计数器,自动重装载寄存器。(注意:预分频器的值为:输入/值+1==输出,最大设置值为65535)当计数器==自动重装寄存器时,发送中断信号(更新中断),这个信号到达NVIC

2.DAC主从触发模式

更新中断信号直接通过TRGO映射到DAC,使其执行相应的电平变换。

(二)通用定时器

外部时钟:(1)ETR引脚---ETRF{外部时钟模式2};(2)ETR引脚---TRGI{外部时钟模式1}

定时器级联:ITR输入;

(三)高级定时器

三、定时器中断的基本结构

中断输出控制:判断中断来源,确定是否有效。

四、定时器中断模式

(一)定时器中断模式的标准库函数

cpp 复制代码
//恢复TIM初始状态
void TIM_DeInit(TIM_TypeDef* TIMx);

//时基初始化(预分频器、自动重装载值)
//结构体参数:计数模式、滤波频率、分频器、预分频器、重复计数次数(pwm使用)
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

//给结构体变量赋一个默认值
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

//定时器控制(开关)
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

//使能中断输出信号(中断输出控制)
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

//时钟选择
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
                                uint16_t TIM_ICPolarity, uint16_t ICFilter);
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                             uint16_t ExtTRGFilter);
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
                             uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,

//手动清零中断标志位
TIM_ClearFlag(TIM2,TIM_FLAG_Update);

//返回定时器计数器值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);

//检查定时器指定中断的挂起标志位
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);

//清除定时器指定中断的挂起标志位
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

五、TIM输出比较模式

(一)介绍

输出比较:OC output compare

比较计数器和CCR寄存器的值,控制电平输出一定频率的波形,可以用于PWM

每个通用和高级定时器都有4个输出比较通道

(二)PWM基本结构

(三)STM32的配置

开启时钟(TIM和GPIO),配置时基单元,配置输出比较单元,配置GPIO,配置运行控制

(四)使用的库函数

复制代码
//初始化配置输出比较单元
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

//给输出比较单元配置一个默认值
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);

//设置CCR的值,控制占空比
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);

(五)实例

cpp 复制代码
void PWM_Init()
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    TIM_InternalClockConfig(TIM2);//内部时钟(默认)
    //GPIO初始化
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);//置高电平,默认熄灭


    //时基单元
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//外部时钟滤波使用,这里非外部可直接不分频
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
    TIM_TimeBaseInitStructure.TIM_Period=100-1;//1s   //ARR
    TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;     //PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    
    //初始化输出比较单元
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse=0;     //CCR
    TIM_OC1Init(TIM2,&TIM_OCInitStructure);

    //启动定时器
    TIM_Cmd(TIM2,ENABLE);
}


int main()
{
    OLED_Init();
    PWM_Init();
    
    
    
    while (1)
    {
        for ( i = 0; i < 100; i++)
        {
            PWM_SetCompare1(i);
            Delay_ms(1);
        }
        for ( i = 0; i < 100; i++)
        {
            PWM_SetCompare1(100-i);
            Delay_ms(1);
        }
    }
}

题外:引脚重映射

使用AFIO修改引脚名称对应的引脚。

AFIO:全称Alternate Function I/O(复用功能输入 / 输出),主要解决单片机引脚资源有限、外设引脚冲突问题。

cpp 复制代码
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

不建议尝试,存在调试端口无法连接的风险。

映射后需要将使用的引脚解除调试。

六、定时器输入捕获模式

(一)介绍

IC(input Campture)输入捕获

作用:输入的电平发生指定变化时,CNT计数器的值进入CCR捕获比较寄存器。

通用和高级定时器有4个通道。

PWMI(PWM输入模式)模式下可以同时测量信号的频率和占空比。

可接入主从触发模式。

(二)频率的测量方法

1.测频法(平均)

在时间T内,测量上升沿次数,f=n/T

2.测周法(瞬时)

两个上升沿(一个周期)内,用标准频率测量,看标准频率的周期数,f=f标/n

(三)结构

(四)主从触发模式

(五)使用

开启总线时钟:TIM和GPIO口

GPIO初始化

打开TIM的时钟(内部或外部)

时基单元初始化

输入捕获初始化/PWMI模式初始化

选择触发源和从模式

TIM使能

cpp 复制代码
void IC_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	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);							//将PA6引脚初始化为上拉输入
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM3);		//选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;               //预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置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;	//输入信号交叉,选择直通,不交叉
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	
	/*选择触发源及从模式*/
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);					//触发源选择TI1FP1
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);					//从模式选择复位
																	//即TI1产生上升沿时,会触发CNT归零
	
	/*TIM使能*/
	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行
}

计算频率和占空比

cpp 复制代码
uint32_t IC_GetFreq(void)
{
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);		//测周法得到频率fx = fc / N,这里不执行+1的操作也可
}

/**
  * 函    数:获取输入捕获的占空比
  * 参    数:无
  * 返 回 值:捕获得到的占空比
  */
uint32_t IC_GetDuty(void)
{
	return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);	//占空比Duty = CCR2 / CCR1 * 100,这里不执行+1的操作也可
}

七、编码器接口

(一)介绍

高级定时器和通用定时器都有1个编码器接口,借用输入捕获通道1,2

两个通道捕获两个有相位差的信号,按照二者的先后规则可以判断正负方向

(二)结构

(三)使用

开启总线时钟:tim和GPIO

GPIO初始化

时基单元初始化

输入捕获初始化

编码器接口配置

TIM使能

cpp 复制代码
void Encoder_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA6和PA7引脚初始化为上拉输入
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
	
	/*输入捕获初始化*/
	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
	TIM_ICStructInit(&TIM_ICInitStructure);							//结构体初始化,若结构体没有完整赋值
																	//则最好执行此函数,给结构体所有成员都赋一个默认值
																	//避免结构体初值不确定的问题
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;				//选择配置定时器通道2
	TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动
	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
	
	/*编码器接口配置*/
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
																	//配置编码器模式以及两个输入通道是否反相
																	//注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相
																	//此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置
	
	/*TIM使能*/
	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行
}

使用定时中断读速度

cpp 复制代码
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		Speed = Encoder_Get();								//每隔固定时间段读取一次编码器计数增量值,即为速度值
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}
相关推荐
Love Song残响13 小时前
NVIDIA显卡终极优化指南
stm32·单片机·嵌入式硬件
qq_6725927514 小时前
电源芯片为什么发热
单片机·嵌入式硬件
天天爱吃肉821814 小时前
【跨界封神|周杰伦×王传福(陶晶莹主持):音乐创作与新能源NVH测试,底层逻辑竟完全同源!(新人必看入行指南)】
python·嵌入式硬件·算法·汽车
国科安芯14 小时前
抗辐照MCU在精密时频系统中的单粒子效应评估与可靠性验证
单片机·嵌入式硬件·架构·制造·安全性测试
森焱森14 小时前
嵌入式硬件工程师应知 白银快速分析报告
linux·c语言·arm开发·嵌入式硬件·去中心化
czhaii14 小时前
单片机最佳入门多线程示例讲解
c语言·单片机
BackCatK Chen1 天前
第 8 篇:TMC2240 电机正反转实现|DIR 引脚控制 + 代码优化(稳定不抖动)
stm32·单片机·嵌入式硬件·保姆级教程·电机正反转·tmc2240·dir引脚控制
星马梦缘1 天前
EDA彩灯电路绘制
单片机·嵌入式硬件·物联网·pcb·eda·嘉立创
Forsete1 天前
LINUX驱动开发#9——定时器
linux·驱动开发·单片机