STM32定时器笔记

stm32F103C8T6

基于江科协议的教程做的笔记

定时器中断

定时器简介

TIM(Timer)定时器

•定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断

•16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时

•不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能

•根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

STM32定时器支持级联功能,

stm32c8t6具有四个定时器:TIM1、TIM2、TIM3、TIM4

定时器结构

基本定时器

上图有三个最重要的寄存器,预分频器、计数器、自动重装载寄存器,它们构成了最基本的计数计时电路,所以这一块电路叫做时基单元,预分频之前,连接的就是基准计数时钟的输入,然后来到控制器复位,由于基本定时器只能选择内部时钟,可以认为CK—PSC连接到了CK—INT,内部时钟的来源是RCC_TIMxCLK,这里的频率值一般是系统的主频72MHz,PSC预分频器,可以对72MHZ的计数时钟进行预分频,如这个寄存器写0就是不分频,或者就是1分频,这时候输出频率等于输入频率等于72MHz,写1就是2分频,输出就等于72/2=36Mhz,依次类推,所以预分频的值和实际分频系数相差了1,即实际分频系数 = 预分频系数 + 1。这个预分频器是16位的,所以最大值是65535,也就是65536分频。这就是预分频器对输入的基准频率提前进行一个分频的操作。

然后是计数器,计数器可以对预分频后的计数时钟进行计数,计数时钟每来一个上升沿,计数器的值就加1,这个计数器也是16位的,可以从0一直加到65535。自动重装寄存器,存储目标值,这个寄存器也是16位的,存的就是我们写入的计数目标。右边的向上折线箭头,达到计数值后,就出触发中断,一般叫这个为更新中断,这个更新中断之后就会通往NVIC,我们在配置NVIC的定时器通道,那定时器的更新中断就能得到CPU的响应了。向下的线头,代表会产生一个事件,这里对应的事件就叫做更新事件,更新事件不会触发中断,但会触发内部其他电路的工作。

主从触发模式:它能让内部的硬件在不受程序的控制下实现自动运行,在某些情景下,将会极大的减轻CPU的工作负担,在使用DAC的时候,可能会用DAC输出一段波形,那就需要每隔一段时间来触发DAC,让它输出下一个电压点。使用这个主模式,可以把这个定时器 的更新事件映射到这个触发TRGO的位置,然后TRGO直接接到DAC的触发转换引脚上,这样,定时器的更新就不需要再通过中断来触发DAC转换了。仅需要把更新事件通过主模式映射到TRGO,然后TRGO就会直接触发DAC。

通用定时器

首先中间最核心的部分还是时基单元,这里和基本定时器是一样的,由预分频器、计数器、自动重装寄存器组成,每部分的工作流程基本和定时器一样,预分频器对时钟分频,计数器计数,自动重装寄存器设置计数的目标,达到计数目标时,计数器清零、更新中断、更新事件。通用定时器不仅支持向上计数,还支持向下计数和中央对齐模式。

时基单元上面的部分是内外时钟源选择和主从触发模式的结构,通用定时器,时钟源不仅支持选择内部的72MHZ时钟,还可以选择外部时钟,如:来自TIMx_ETR引脚上的时钟,ETR的位置参考引脚表。ETR引脚上可以接一个外部时钟,然后配置一下内部的极性选择、边沿检测和预分频器电路,再配置一下滤波电路,这些电路可以对外部时钟进行整形,最后,滤波后的信号分两路,上面一路ETRF进入触发控制器,紧跟着就可以选择作为时基单元的时钟了,这一路当做外部时钟来使用的时候,叫做外部时钟2。除了外部ETR引脚可以提供时钟,下面一路TRGI也可以提供时钟,主要用作触发输入来使用,可以触发定时器的从模式,这一路当作外部时钟的时候,叫做外部时钟1。通过这一路的外部时钟有:第一个ETR引脚,ETR即可以通过ETRF当做时钟,也可以通过TRGI当作时钟。第二个是ITR信号,这一部分的时钟信号是来自其他定时器的,这里可以看出,主模式的TRGO可以通往其他定时器的,通往其他定时器的时候,就接到了其他定时器的ITR引脚上,ITR0~ITR3来自其他四个定时器的TRGO,通过这一路可以实现计时器级联的功能。第三个还可以选择TI1F-ED,这里连接了输入捕获单元的CH1引脚,也就是从CH1引脚获得时钟,后缀+ED就是边沿的意思,通过这一路的时钟,上升沿和下降沿均有效。第四个,还可以通过TI1FP1和TI2FP2获得,其中TI1FP1连接到了CH1引脚的时钟,TI2FP2连接到了CH2引脚的时钟。总结:外部时钟模式1的输入可以是ETR引脚、其他定时器、CH1引脚的边沿、CH1引脚、CH2引脚。最右上边TRGO就是定时器的主模式输出,这部分可以把一些事件映射到TRGO引脚上,用于触发其他定时器、DAC、ADC。

时基单元下右面的一部分是输出比较电路,总共四个通道,分别对应CH1和CH4,可以用于输出PWM波形,驱动电机,左边则是输入捕获电路,也有四个通道,对应的也是CH1~CH4,可以用于测输入方波的频率,中间的寄存器是捕获/比较寄存器,是输入捕获和输出比较电路共同的,输入捕获和输出比较不能同时使用。

高级定时器

相对于通用定时器,高级定时器只有一小部分变化(黄线部分),申请中断的地方加了一个重复次数计数器,可以实现每隔几个计数周期,才发生中断、事件,相当于对输出信号进行了一次分频,DTG是死区生成电路,右边的输出电路变为了两个互补的输出,可以输出一对互补的PWM波,是为了驱动三相无刷电机。

定时器中断基本结构配置

定时中断和时钟源选择,重要的还是PSC预分频器、CNT计数器、ARR自动重装器,下面是运行控制,左边是为时基单元提供时钟的部分,可以选择RCC提供的内部时钟,也可以选择ETR提供的外部时钟模式2,还可以选择触发输入当作外部时钟,即外部时钟模式1,对应的有ETR外部时钟,ITRx其他定时器、Tix捕获通道,最后还有一个编码器模式,一般时编码器独用的模式,普通时钟用不到。右边中断输出控制、NVIC,这里就是计时时间到,产生更新中断后的信号去向,如果时高级定时器的话,还会多一个重复计数器,这里中断信号会现在状态寄存器置一个标志位,这个标志位会通过中断输出控制,到NVIC申请中断。这个中断输出控制就是一个中断输出的允许位,需要某个中断就需要允许一下。

配置步骤:

第一步:RCC开启时钟

第二步:选择时基单元的时钟源。

第三步:配置时基单元 //PSC、ARR、计数模式

第四步:配置输出中断配置,允许中断输出到NVIC //打开更新中断

第五步:配置NVIC,在NVIC里打开定时器通道,并分配一个优先级 //NVIC分组、NVIC配置

第六步:运行控制

代码实例(定时1s)

#include "stm32f10x.h"                  // Device header


void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	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; //重装值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200-1;  //预分频
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;  //重复计数
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);

	TIM_ClearFlag(TIM2,TIM_FLAG_Update);		//清除原有标志位
	TIM_ITConfig(TIM2,TIM_FLAG_Update,ENABLE);		//打开更新中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //NVIC分组
	
	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);
}

OC简介

OC(Output Compare)输出比较

输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形

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

高级定时器的前3个通道额外拥有死区生成和互补输出的功能

PWM简介

PWM波形是一个数字输出信号,也是由高低电平组成,是连续变化的电平信号,使用这个PWM波形,是用来等效地实现一个模拟信号地输出。PWM地应用场景必须是一个惯性系统,上左图高低电平跳变地数字信号,可以等效为中间这个虚线所表示地模拟量。上面时间电平长一点,下面时间短一点地时候,等效模拟量偏向于上面,上面短一点,下面长一点,等效模拟量偏向于下面。

Ts:代表高低电平变换周期的时间。倒数就是频率。

占空比:Ton/Ts Ton就是高电平的时间,Ts是一个周期的时间,一般用百分比表示,例如:50%,那就是一个高电平占一个周期的一半,占空比20%,那就是高电平占整个周期的20%。占空比越大,那等效的模拟电压就越趋近于高电平,占空比越小,那等效的模拟电压就越趋近于低电平。

分辨率:它等于占空比变化边距,就是占空比变化的精细程度。

输出比较通道

左边是CNT计数器和CCR1第一路的捕获/比较寄存器,它两进行比较,当CNT>CCR1,或者当CNT == CCR1,就会给输出模式控制寄存器传一个信号,然后输出模式控制寄存器就会改变它输出OC1REF的高低电平,REF信号实际上就是指这里信号的高低电平,上面还有一个ETRF输入,是定时器的一个小功能,接着REF信号可以去主模式控制器,可以把REF映射到主模式的TRGO输出上。第二路REF到达极性选择,给CC1P写0或者写1实现电平信号反转或者不反转。接着是输出使能,最后是OC1引脚,就是CH1通道的引脚。

输出比较模式

输出比较的8种模式,也就输出模式控制器里面的执行逻辑,这个模式控制器的输入是CNT和CCR的大小关系,输出是REF的高低电平,可以选择多种模式更加灵活地控制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配置结构

首先是左上角,是时基单元和控制部分,再左边是时钟源选择,下面是输出比较单元,一共有四路,输出比较单元的开始是CCR捕获/比较寄存器,CCR是自己设置的,CNT不断自增运行,同时它两还在不断进行比较,后面就是输出模式控制器,这里是PWM1的执行逻辑,CNT<CCR时,REF置有效电平,CNT>=CCR时,REF置无效电平。后面的REF,就是一个频率可调,占空比也可调的PWM波形,最终再通过极性选择输出使能,最终通向GPIO口。

参数计算

PWM频率: Freq = CK_PSC/(PSC+1)/(ARR+1)

PWM占空比:Duty = CCR/(ARR+1)

PWM分辨率:Reso = 1/(ARR+1)

例如:CCR从0一直加到ARR,比如:ARR是99,那CNT总共计100个数,高电平时间从0到(30-1),从30~99就是低电平时间,所里这里占空比就是30/100=30%,分辨率就是占空比变化的步距,CCR的值应该设置到0到ARR+1这个范围内。ARR的值越大,CCR的范围就越大,对应的分辨率就越大,。

OC配置

第一步:打开时钟 //开启相关时钟

第二步:打开GPIO //打开相关GPIO

第三步:选择内部时钟源

第四步:配置TIM时基单元 //计数方向(向上还是向下)、ARR、PSC、分频系数

第五步:配置OC输出比较 //初始化、配置PWM模式、极性、CRR

第六步:打开定时器

代码:

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
		
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		//复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	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 = 100-1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;		//重复计数
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
    //OC配置
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);		//初始化配置
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;		//PWM模式1
	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);		//OC通道1
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);		//OC通道2
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);		//OC通道3
	
    //打开控制
	TIM_Cmd(TIM2,ENABLE);
}

IC简介

C:Input Capture,输入捕获的意思,4个输入捕获和输出比较通道,共用4个CCR寄存器,另外4个CH1到CH4的通道引脚,也是共用的,所以对于同一个定时器,输入捕获和输出比较,只能使用其中一个,不能同时使用,

输入捕获模式下,当通道输入引脚出现指定电平跳变,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。CH1~CH4边沿信号输入引脚,一旦电平跳变,后面的边沿滤波和边沿检测电路就会检测到这个上升沿,让输入捕获电路产生动作,让当前CNT的值锁存到CCR中,对比输出比较,输出比较,引脚是输出端口,输入捕获,引脚是输入端口;输出比较,是根据CNT和CCR的大小关系来执行动作的,输入捕获,是接收到输入信号,执行CNT锁存到CCR的动作;

每个高级定时器和通用定时器都拥有四个输入捕获通道。可以配合PWMI模式,同时测量频率和占空比,PWMI模式就是PWM的输入模式,专门为测量PWM频率和占空比设计的,可配合主从触发模式,来实现硬件自动测量。

频率测量

这里测量的是数字信号,如果测量一个正弦波(sin),还需要搭建一个信号预处理信号,如:可以用运放搭建一个比较器,把模拟信号转换为数字信号,如果测量的信号电压非常高,还要考虑隔离问题,如:用隔离放大器,电压互感器,隔离高压和低压,保证电路安全。总之,要给STM32的信号,必须是数字信号,高电平3.3V,低电平0V。

测量方法

测频法:在闸门时间T内,对上升沿计次,得到N,则频率: f(x) = N/T

原理:自定义一个闸门时间T,通常设置为1s,在一秒时间内,对上升沿计次,每来一个上升沿计次+1,其实就是来了一个周期的信号,在一秒时间内,来了多少上升沿就等于多少频率。

频率的定义:1s内出现了多少个时钟周期。

测周法:两个上升沿内,以标准频率fc计次,得到N,频率:fx=fc/N

原理:周期的倒数就是频率,测出一个周期的时间,在取个倒数就是频率。捕获信号的两个上升沿,测量两个之间持续的时间,实际上,我们没有一个精度无穷大的表,测量方法,定时器计数,使用已知的标准频率fc的计次时钟,来驱动计数器,从一个上升沿开始计数,计数器从0开始,一直计到下一个上升沿,计一个数的时间是1/fc,N个数,就是N/fc, N/fc就是周期,取个倒数就是fc/N,

两种方法区别

测频法:适合测量高频信号,测周法适合测量低频信号,测频法:在闸门时间内,最好多出现一些上升沿,计次数量多一些,有助于减少误差。测频法测量结果更新的慢一些,数值相对稳定。 测周法:信号频率低一些。低频信号,周期比较长,计次就会比较多,有助于减少误差,测周法更新的快,数据跳变非常快。测频法在闸门时间内的多个周期,所以自带均值滤波,如果在闸门时间内波形频率有变化,那得到的其实是闸门时间的平均频率。所以测频法结果更新慢,测量结果是一段时间的平均值,值比较平滑。测周法,只测量一个周期就得出频率,所以结果的速度取决于待测信号的频率。一般来说:待测信号都是几千几百Hz,测周法更新频率很快。由于只测量一个周期,结果值波动比较大。

正负1误差:

测频法、测周法,计次数量N尽量大,N越大相对误差越小,在这些方法中,计次可能存在正负1误差,如:测频法,闸门时间内,并不是每个周期信号都是完整的,在最后时间里,一个周期可能出现了一半,只有半个周期,只能当作一个周期或者半个周期直接舍弃掉,因为计次只有整数,没有计半个数的情况,这种情况多计数一个或者少计数一个,叫做正负1误差。在测周法里也有这种情况,一个数刚计了一半,计时就结束了,这半个数也只能当作一个数或直接舍弃掉。这两种方法都有正负1误差。想要减少这种影响,就多计数,N越大,正负1误差影响越小。

输入捕获部分电路

从左往右看,最左边是四个通道的引脚,引脚进来有一个三输入的异或门,异或门的输入接在了输入捕获引脚的1、2、3端口,异或门的执行逻辑:当三个引脚的任何一个有电平反转时,输出引脚就产生一次电平反转,之后输出通过数据选择器,到达输入捕获通道1,数据选择器选择上面一个,那输入捕获通道1的输入,就是三个引脚的异或值,如果选择下面一个,那么异或门就没有用,4个引脚各用各的引脚。设计这个异或门,主要用于三相无刷电机。

输入信号来到输入滤波器和边沿检测器,输入滤波器可以对信号进行滤波,避免一些高频的毛刺信号误触发,边沿检测器,可以选择高低电平触发,出现指定电平时,边沿检测就会触发后续电路执行动作。另外,这里设计了两套滤波和边沿检测电路,第一套电路,经过滤波和极性选择得到TI1FP1,输入给通道1的后续电路,第二套电路,经过另一个滤波和极性选择得到TI1FP2,输入给下面通道2的后续电路,TI2信号同理,也经过两套滤波和极性选择,得到TI2FP1、TI2FP2,其中TI2FP1给上面,TI2FP2给下面,这里两个信号可以各走各的,也可以进行交叉,让CH2引脚给CH1,让CH1引脚给CH2,这样做的目的:第一:灵活切换 后续捕获电路的输入,第二:可以把一个引脚的输入,同时映射到两个捕获单元。 第一个捕获通道,使用上升沿触发,用来捕获周期,第二个通道使用下降沿触发,用来捕获占空比,两个通达同时对一个引脚进行捕获,就可以同时测量频率和占空比,这就是PWMI模式,TIM3和TIM4也可以选择交叉连接。 另外还有一个TRC信号,也可以选择捕获部分的输入。

输入信号进行滤波和极性选择后就来到了预分频器,预分频器每个通道都有一个,可以选择对前面的信号进行分频,分频之后的触发信号就可对捕获电路进行工作了。每来一个触发信号,CNT的值,就会向CCR转运一次,转运的同时会发生一个捕获事件,这个事件会在状态寄存器置标志位,同时也可以产生中断,如果需要在捕获的瞬间,处理一些事情的话,就可以开启这个捕获中断,这就是整个电路的工作流程。 例如:我们可以配置上升沿触发捕获,每来一个上升沿,CNT转运到CCR一次,又因为这个CNT计数器是由内部的标准时钟驱动的,所以CNT的数值,其实就可以用来记录两个上升沿之间的时间间隔,这个时间间隔就是周期,在取个倒数,就是测周法测量的频率。

输入捕获通道

引脚进来,经过一个滤波器,滤波器的输入是TI1,就是CH1的引脚,输出的是TI1F,就是滤波后的信号。fDTS是滤波器的采样时钟来源,下面的CCMR1寄存器的ICF位可以控制滤波器的参数,滤波之后的信号通过边沿检测器,捕获上升沿和下降沿,用CCER寄存器里的CC1P位,就可以选择极性了,最终得到TI1FP1触发信号,通过数据选择器,进入通道1后续的捕获电路,通道2TI2FP1连接到通道1的后续,TI1FP2也会连接到TI2的后续上。然后经过数据选择器,进入后续捕获部分电路,CC1S位可以对数据选择器进行选择,之后ICPS位,可以配置这里的分频器,可以选择不分频、2、4、8分频,最后CC1E位,控制输出使能或者失能。每捕获一次CNT的值,都要把CNT的值清零一下,以便下一次的捕获。这里硬件电路就可以在捕获之后自动完成CNT的清零工作。 这里TI1FP1信号和TI1的边沿信号,都可以通向从模式控制器,如:TI1FP1信号的上升沿触发捕获,TI1FP1还可以同时触发从模式,这个从模式里,就有电路,可以自动完成CNT的清零。

CCMR1:输入捕获1滤波器 (Input capture 1 filter) 这几位定义了TI1输入的采样频率及数字滤波器长度。数字滤波器由一个事件计数器组成,它记 录到N个事件后会产生一个输出的跳变。

主从触发模式

主从触发模式:主模式、从模式、触发源选择。

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

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

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

输入捕获结构

这里只使用了一个通道,所以目前只能测量频率,右上角就是时基单元,把时基单元配置好,启动定时器,那这个CNT,就会在预分频之后的时钟驱动下,不断自增,这个CNT,就是测周法用来计数计时的东西,经过预分频之后这个位置的时钟频率,就是驱动CNT的标准频率fc,这里的标准频率=72MHZ/预分频系数。

然后说 下面输入捕获通道1的GPIO口,输入一个像左上图的方波信号,经过滤波器和边沿检测,选择TI1FP1为上升沿触发,之后输入选择直连的通道,分频器选择不分频,当TI1FP1出现上升沿之后,CNT的当前计数值转运到CCR1里,同时触发源选择选中TI1FP1为触发信号,从模式选择复位,这样TI1FP1的上升沿也会通过上面这一路,去触发CNT清零, 先后顺序:先转运CNT的值到CCR里去,再触发从模式给CNT清零。或非阻塞的同时转移。CNT的值转到CCR,同时0转运到CNT,总之,不能先清零再捕获。 再看左上角的图,当来了一个上升沿,CCR1=CNT,就是CNT的值转到CCR中,这是输入捕获自动执行的,然后CNT清零。这是从模式自动执行的,然后CNT在标准时钟的驱动下,不断自增,从0开始计数,一直到下个上升沿的到来,然后再执行相同操作。这个电路工作时,CCR1的值,始终保持最新一个周期的计数值, 这个计数值就是测周法里的N ,fc/N就是信号的频率。所以当我们想要读取信号的频率时,只需要读取CCR1得到N,再计算fc/N。 注意:CNT的值有上限,ARR一般最大为65535,如果信号频率太低,CNT计数值可能会溢出。 还有从模式的触发源选择,只有TI1FP1和TI2FP2,没有TI3和TI4。想用从模式自动清零CNT,只能使用通道1和通道2。对于通道3和通道4,就只能开启捕获中断,在中断里手动清零。这样,程序会处于频繁中断,比较消耗软件资源。

PWMI结构

这个PWMI模式,使用了两个通道同时捕获一个引脚。可以同时测量周期和占空比,下面多了一个通道,首先,TI1FP1配置上升触发,触发捕获和清零CNT,正常的捕获周期,再配置TI1FP2下降沿,通过交叉通道,去触发通道2的捕获单元。看左上角,最开始上升沿,CCR1捕获,同时清零CNT,然后CNT++,然后在下降沿时刻,触发CCR2捕获,这时CCR2的值就是高电平期间计数的值,CCR2捕获,不触发CNT清零。所以CNT继续++。直到下一次上升沿,CCR1捕获周期,CNT清零。CCR1就是整个周期的计数值,CCR2就是高电平期间的计数值。CCR2/CCR1就是占空比。这就是PWMI模式。

IC配置

IC配置步骤:

第一步:打开时钟 //相关时钟

第二步:配置GPIO //相关GPIO

第三步:时基单元配置 //ARR PSC 极性

第四步:配置IC通道 //通道、滤波器参数、极性、分频器、通道交叉

第五步:配置主从模式: //触发源选择、从模式操作

第六步:启动定时器

#include "stm32f10x.h"                  // Device header

void IC_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,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_TimeBaseInitStruceure;
	TIM_TimeBaseInitStruceure.TIM_ClockDivision = TIM_CKD_DIV1;  //不分频
	TIM_TimeBaseInitStruceure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInitStruceure.TIM_Period = 65535-1;		//ARR
	TIM_TimeBaseInitStruceure.TIM_Prescaler = 72-1;		//PSC
	TIM_TimeBaseInitStruceure.TIM_RepetitionCounter =0 ;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruceure);
	
	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_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);   //测周法   fc/N   1M/计数值
}

编码器接口

简介

编码器接口可以接收增量编码器的信号,或叫正交编码器(两个方波信号相差90°),编码器可以根据编码器旋转产生的正交脉冲信号,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度。就是接受正交信号,自动执行CNT的自增或自减。在一定时间内,计算CNT的增加减少次数,就是测速度。

每个高级定时器和通用定时器都有1各编码器接口,如果一个定时器配置成了编码器接口,那基本做不了其他工作了,C8T6有四个定时器,如果接四个定时器,那就没有定时器可以用了。

两个输入引脚借用了输入捕获的通道1和通道2(CH1、CH2),CH3、CH4不能用于编码器。

正交编码器

正交编码器一般可以测量位置,或带方向的速度值,它一般有两个输出引脚,一个是A相,一个是B相,当编码器的旋转轴转起来的时候,A相和B相就会输出方波信号,转的越快,方波频率就会越高,所以方波频率就代表速度。取出任意一相的信号测频率,就能直到速度。当正转时,A相提前B相90°,反转时,B相滞后A相90°,这些并不是固定的,总之是朝一个方向是A相提前,另一个方向是A相滞后,这样做正交信号精度高,因为A、B相都可以计次,相当于计次频率提高了一倍。其次就是正交信号可以抗噪声,如果一个信号不变,另一个信号连续变化,那这时计次值是不会变化的。

右方状态表,正转:第一时刻,A相上升沿,对应B相此时是低电平, 第二时刻:B相上升沿,A相高电平,第三时刻:A相下降沿,B相高电平,第四时刻:B相上升沿,A相低电平。 反转:第一时刻:B相上升沿:A相低电平, 第二时刻:A相上升沿,B相高电平, 第三时刻:B相下降沿,A相高电平, 第四时刻:A相下降沿,B相低电平。 A、B相出现这些边沿时,对于另一项状态,正转和反转正好是相反的。

结构

电路结构

编码器接口设计逻辑:首先把A相和B相的所有边沿作为计数器的计数时钟,出现边沿信号时,就自增或自减,增加还是减少,由另一项的状态来决定。

可以看出,编码器的接口借用了输入捕获的前两个通道,其中CH1、CH2输入捕获滤波器和边沿检测,编码器接口也有在使用。但是后面的是否交叉、预分频器、CCR寄存器与编码器接口无关,这就是编码器的输入部分,编码器的输出部分,相当于从模式控制器,去控制CNT的计数时钟和计数方向。如:如果出现了边沿信号,并且对应另一相的状态为正转,则控制CNT自增,否则控制CNT自减。之前使用的72MHz时钟,在这里时基单元初始化时设置的计数方向,并不会使用,因为此时计数时钟和计数方向都处于编码器接口托管的状态,计数器的自增和自减受编码器控制,这就是编码器的电路接口。

配置结构

输入捕获的前两个通道,通过GPIO接入编码器的A、B相,然后通过滤波器和极性选择,产生TI1FP1、TI2FP2,通向编码器接口,编码器通过预分频器控制CNT计数器自增或自减,同时,编码器接口还根据编码器的旋转方向,控制CNT的计数方向,如:编码器正转时,计数器自增,编码器反转时,计数器自减。这里ARR也是有效的,一般ARR都会设为最大量程。这里要把16位的无符号数转换位16位的有符号数(补码)。

工作模式

编码器的工作模式:TI1FP1接的就是编码器的A相,TI2FP2接的就是编码器的B相,在A相的上升沿或者下降沿触发计数,向上计数还是向下计数取决于边沿信号发生的这个时刻,另一相的电平状态,也就是上图的想对信号的电平状态,TI1FP1对应TI2,TI2FP2对应TI1,就是另一相电平的意思。 编码器还分了三种工作模式:TI1计数、TI2计数、TI1和TI2都计数。第一第二中模式,只在一相计数,第三种模式,就是在双边沿计数。

例子1

这个例子用的是双相计数,TI1上升沿,TI2低电平,计数加1,TI2上升沿,TI1高电平,计数+1,一直到毛刺这里,TI2没有变化,TI1变化好几次,不符合正交编码器的规律。一个引脚不变,另一个引脚连续跳变多次的毛刺信号,计数器就会加减、加减来回摆动。最终计数值还是原来那个数,并不受毛刺信号的影响,这是正交编码器抗噪声的原理。再到后面是CNT--的信号波动。

例子2

前一个例子是两个引脚都不反相,这个是TI1反相,TI2不反相,TI1反向:TI1和TI2进入输入捕获模式,都会经过一个极性选择,极性选择就是高低电平选择,就不是边沿检测了,如果,选择上升沿,就是信号直通,高低电平极性不反转,如果选择下降沿,信号会通过一个非门,高低电平极性反转,如果把TI1高低电平反转一下,就是这里的TI反相,所以TI1反相之后,先把TI1高低电平取反,才是反相后给编码器接口的电平。

配置步骤

第一步:配置RCC时钟

第二步:配置GPIO时钟

第三步:配置时基单元 //PSC 、ARR、CNT

第四步:配置输入捕获单元 //只有滤波器和极性有用。

第五步:配置编码器接口模式

第六步:启动定时器

#include "stm32f10x.h"                  // Device header

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;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1 ;
	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;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
//	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
//	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInit(TIM3,&TIM_ICInitStructure);
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Falling,TIM_ICPolarity_Falling);
	
	TIM_Cmd(TIM3,ENABLE);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值