STM32F1系列学习总结:对定时器学习(标准库方式)

*学习路线指引*:

1.定时器介绍及手册解读--顺势介绍其定时功能、定时触发中断功能

2.定时器的输出比较功能--pwm波的应用

3.定时器的输入捕获功能--测频测周法测量频率(主从模式的应用使用全硬件自动化)

4.定时器的编码器接口硬件资源--编码电机测速(主从模式的应用使用全硬件自动化)

一、我的学习认知程度--定时器的介绍及手册简读

        定时器的介绍:

        (1)定时器实质就是一个计数器,如果是单片机内部的定时器,它的计数频率就由单片机的主频决定,比如stm32f103c8t6最小系统板的主频为72MHZ,那么定时器的计数频率也是72MHZ,也即1秒钟能计72000000个数,那么如果想定时1us,那么就让定时器计数72个。        

        (2)单片机的定时器有不同级别种类,不同级别种类的功能不一样,在使用或者说规划资源时需注意。stm32f1系列单片机定时器分为3种,由级别从高到低分别是:高级定时器、通用定时器、基本定时器,级别高的兼容级别低的定时器的功能。图1是它们的功能图。

                                                图1     不同级别定时器功能介绍

由图表可知,

TIM1、8为高级定时器
TIM2、3、4、5为通用定时器
TIM6、7为基本定时器

级别不一样,功能就不一样
越高级向下包含功能

高级定时器拥有通用和基本定时器功能
通用定时器拥有基本定时器功能

通用定时器拥有输入输出比较功能,所以可以输出pwm,开以进行编码测试。
基本定时器只能用来定时产生中断或者简单时。

!!!举个例子,你如果只想在程序里简单计个时来产生中断或者模拟时钟,那就可以使用基本定时器来满足,如果想输出pwm信号或者进行编码测试,那就使用通用定时器或者高级定时器。!!!

所以,在做项目规划资源使用时要做好划分。

        (3)单片机允许使用内部定时器,也可以接外部定时器,在库函数配置时会由个时钟模式选择,选择好时钟模式后就进行时基单元的配置,这个部分很关键,由预分频器(psc)、计数器(CNT)、自动重装器(ARR)组成,这个单元是时钟运行方式的配置,即以72MHZ分频后的频率计数,记到多少或者溢出,进行重装,并可以选择触发中断。图2为上述系统的流程图。

                                                        图2   配置定时器流程

        (4)结合代码实现:

void Timer_Init(void)
{											
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);       											//开启APB1总线上的TIM2外设时钟
												
	TIM_InternalClockConfig(TIM2);																									//选择内部时钟源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_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
//是否启用预分频缓冲器,是否立即响应重置重装值
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);															//Freq = CK_PSC / (PSC + 1) / (ARR + 1)      //CK_PSC:系统主频,72MHZ
	
	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;																	//开启TIM2中断申请通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;												//抢占优先级:2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;															//响应优先级:1
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);																													//使能TIM2
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		/*
		
		
		中断处理事务代码放在这里
		
		
		*/
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

这里是7200-1分频,即72000000/7200=10000,意思就是定时器每秒计数10000个数,又ARR为10000-1,也即CNT加到10000,就回到0重新计数,并触发中断,相当于1秒触发一次中断,所以,这个外设TIM2可以用来模拟时钟功能。(这个TIMX根据实际选择,最好选择基本定时器,因为我们说过基本定时器只有定时中断功能,我们可以把稀缺的资源留给其他功能)

        手册简读:第13章到第15章。

        重点在于那些寄存器,不过好在有库函数的封装,即把那些寄存器中某些位的置零置一给用宏定义和库函数封装好了,我们只需要在引出结构体变量赋值即可。比如:结构体成员

        TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式

我们跳转定义:

可见TIM_CounterMode_Up = 0000 0000 0000 0000;

        TIM_CounterMode_Down = 0000 0000 0001 0000;

我们再跳转配置函数定义:TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);    

可知,是在配置TIMX->CR1控制寄存器的,然后我们查看手册:

对应2个2跟字节,分析

         TIM_CounterMode_Up = 0000 0000 0000 0000;

        TIM_CounterMode_Down = 0000 0000 0001 0000;

可知,配置位4 DIR既是配置计数模式。

        标准库方式开发总结:用一句话来概括就是:使用某个外设,就要配置某个外设的寄存器,标准库方式配置就是用宏定义赋值结构体成员,然后调用库函数,这样底层电路就会根据我们的设置去置0置那些位,实则是连接那些通道,让电路工作。

二、我的学习认知程度--定时器的输出比较功能--pwm波的应用

        由前面讲述可知,只有通用定时器和高级定时器才有此功能,故使用时应注意!

        输出比较OC(Output Compare)功能原理:

结合图来理解:

先配置好时基单元,让CNT计数器以一定的频率计数,再配置输出比较单元,都配置好后,输出比较器会把CNT的值时刻和设定的比较值CCR比较一下,CNT<=CCR时,输出高电平,反之输出低电平,这样一来,通过设置CCR的值便可控制输出信号的占空比,也即脉冲宽度调制,从而输出pwm波。

结合代码理解:

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);																			//选择内部时钟源TIM2
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;					//不分频
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;			//向上计数模式
	TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;										//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 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;				//开启输出通道1
	TIM_OCInitStructure.TIM_Pulse = 0;																	//占空比初始化,也即CCR
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2, Compare); //设置占空比
}

时钟配置为20ms,这是因为我这个代码是在输出pwm给舵机,了解舵机原理可知,

我们接着说输出比较配置部分:

都有详细注释,我就不多说了,主要提一下,输出比较模式

简单说就是,配置CNT是向上计数还是向下计数,CNT和CCR比较值,CNT<CCR时,是输出高电平还是低电平。

三、我的学习认知程度--定时器的输入捕获功能--测频测周法测量频率(主从模式的应用使用全硬件自动化)

        由前面讲述可知,只有通用定时器和高级定时器才有此功能,故使用时应注意!

        输入捕获IC(Input Capture)功能原理:

结合图理解:

(由于输入捕获和输出比较器是同一个东西,故同一个定时器的同一个通道不能同时使用这两个功能。)配置好时基单元,再配置输入捕获单元,配置好后,从GPIO输入一个信号,比如pwm信号,经过滤波电路去除毛刺信号,这部分无需具体了解如何滤波,然后进入边沿检测,比如高电平检测,一路进入分频器进行分频,也即2分频就是每2个高电平才在第二个高电平边沿进行后续操作,最后控制捕获器捕获第二个高电平边沿时刻的CNT的值,另一路产生主模式触发信号,触发主从模式,对CNT进行清零操作,这个主从模式待会细说。结合左上角的图,就很好理解了,就是输入信号被检测高电平边沿后,捕获此刻CNT的值,同时通过主从模式清零CNT,为下一次测量做准备,得到CNT的值有什么用呢?因为时基单元代表一个已知频率的计数器,它的CNT的值可以换算回时间值,比如,7200分频、10000重装值,那么72000000/7200/10000=1HZ,也即CNT计10000次就是1s,那么捕获到CNT的值后必然可以换算出两个高电平边沿之间的时间,所以取倒数既是频率,所以测得输入信号频率。(利用测周法原理)

        扩展知识:

        测频测周法:

        

        主从触发模式:

        主从触发模式可以使得硬件全自动化,无需软件即程序也即CPU参与,减轻CPU负担,在这里先讲主从触发模式的工作原理,第四部分再讲其应用----编码器接口资源。

        主从触发模式工作原理:也即stm32f1架构系列单片机在设计时,在底层电路用硬件的方式打通它们之间的联系,出于必要的用途。比如,编码器测速,AB相信号作为主模式,发出触发信号TRGO,触发源就是AB相发出脉冲信号TI1FP1、TI2FP2,从模式就是编码器接口,输入信号触发编码器接口去读取CNT的值,实现硬件全自动化,我们只需读取CNT的值即可,减轻CPU负担,流程就是一个信号触发另一个信号,注意,不是所有信号都有该模式,所以要懂得利用它们的长处。

结合程序理解:

void IC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	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);
	
	TIM_InternalClockConfig(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;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	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;     //直入还是交叉,对应通道1输出TI1FP1还是TI2FP2  
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);                        //主模式体选择
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);                       //从模式体选择
	
	TIM_Cmd(TIM3, ENABLE);
}

uint32_t IC_GetFreq(void)
{
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);                          //捕获频率
}

代码有详细注释。

原理:测周法。

四、我的学习认知程度--定时器的编码器接口硬件资源--编码电机测速(主从模式的应用使用全硬件自动化)

        由前面讲述可知,只有通用定时器和高级定时器才有此功能,故使用时应注意!

        还需注意:编码器接口是专门为编码器测速设计的,充分利用资源,同时注意,只有高级定时器和通用定时器的通道1、2才能通往该接口,故需注意!!!

        这部分由于是前面知识的结合,故这部分针对性说明应用。

这里说一下,利用这个主从模式比不使用的优势。因为电机高速旋转,所以CNT的值要快速且频繁读取。

使用的情况:输入信号会控制编码器接口从模式自动去读取CNT的值,全程自动。

不使用的情况:我们需在程序中配置中断信号,不断捕获CNT的值,频繁进入中断的程序的质量,想想可知。

        结合代码理解:

void Encoder_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	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);
		
	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_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);                //全体成员变量均赋初始值,这运用在有些成员变量没有用到,如果不赋值会报错
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;    //定时器3通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;    //定时器3通道2
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);        //配置编码器接口函数
	
	TIM_Cmd(TIM3, ENABLE);
}

int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3, 0);
	return Temp;
}

        编码器工作原理:

编码器接口会将传来的两个信号进行比较,如图,如果A高电平,那么它就会看一下B,B如果是低电平,那么触发从模式,去让CNT加1,表示正转,其余的类似,我们将CNT读出即可测速。

原理是测频法,代码里最后一个函数

int16_t Encoder_Get(void)
{
    int16_t Temp;
    Temp = TIM_GetCounter(TIM3);
    TIM_SetCounter(TIM3, 0);
    return Temp;
}

就是用测频法来测速的,在主函数里delay一段时间作为闸门时间来读取CNT的值,或者用中断获取CNT的值。

五.总结

最后,总结一下:

1.使用定时器前,规划好资源,不同级别定时器功能不同,正确规划,可以充分利用资源。

2.基本定时器:定时触发中断。

3.通用定时器:pwm输出,编码测速、测频。

4.主从模式(硬件触发硬件工作)可以减轻CPU负担,充分利用,一个很好的案例就是编码器接口,不过它只在高级、通用定时器的通道1、2上有,这是32在硬件上的设计。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值