[stm32] STM32的通用定时器TIMx系统了解
通用定时器(TIMx)
4.1 使得PB5-TIM3通道2产生频率为12.5Hz的方波,该方波控制LED1的闪烁
4.2 周期控制通用定时器3的2通道,实现1KHz的不同占空比波形,控制LED实现呼吸灯
通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)。使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。每个定时器都是完全独立的,没有互相共享任何资源。它们可以一起同步操作。[正版请搜索:beautifulzzzz(看楼主博客园官方博客,享高质量生活)嘻嘻!!!]
通用TIMx (TIM2、 TIM3、 TIM4和TIM5)定时器功能包括:
● 16位向上、向下、向上/向下自动装载计数器
● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1 ~65536之间的任意数值
● 4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 使用外部信号控制定时器和定时器互连的同步电路
● 如下事件发生时产生中断/DMA:
─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
─ 输入捕获
─ 输出比较
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理
图1 通用定时器框图
注:
Reg:根据控制位的设定,在U事件时传送预加载寄存器的内容至工作寄存器
斜向下的箭头:事件
斜向上的箭头:中断和DMA输出
可编程通用定时器的主要部分是一个16位计数器和与其相关的自动装载寄存器。这个计数器可以向上计数、向下计数或者向上向下双向计数。此计数器时钟由预分频器分频得到。计数器、自动装载寄存器和预分频器寄存器可以由软件读写,在计数器运行时仍可以读写。
时基单元包含:
● 计数器寄存器(TIMx_CNT)
● 预分频器寄存器 (TIMx_PSC)
● 自动装载寄存器 (TIMx_ARR)
自动装载寄存器是预先装载的,写或读自动重装载寄存器将访问预装载寄存器。根据在TIMx_CR1 寄存器中的自动装载预装载使能位(ARPE)的设置,预装载寄存器的内容被立即或在每次的更新事件UEV时传送到影子寄存器。当计数器达到溢出条件(向下计数时的下溢条件)并当TIMx_CR1 寄存器中的UDIS位等于’0’时,产生更新事件。更新事件也可以由软件产生。随后会详细描述每一种配置下更新事件的产生。
计数器由预分频器的时钟输出CK_CNT驱动,仅当设置了计数器TIMx_CR1 寄存器中的计数器使能位(CEN)时, CK_CNT才有效。
注:真正的计数器使能信号CNT_EN是在CEN的一个时钟周期后被设置。
预分频器可以将计数器的时钟频率按1 到65536之间的任意值分频。它是基于一个(在TIMx_PSC寄存器中的)16位寄存器控制的16位计数器。这个控制寄存器带有缓冲器,它能够在工作时被改变。新的预分频器参数在下一次更新事件到来时被采用。(图2和图3给出了在预分频器运行时,更改计数器参数的例子。)
图2 当预分频器的参数从1 变到2时,计数器的时序图
图3 当预分频器的参数从1 变到4时,计数器的时序图
3.2.1 向上计数模式
在向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器的内容),然后重新从0开始计数并且产生一个计数器溢出事件。
每次计数器溢出时可以产生更新事件,在TIMx_EGR寄存器中(通过软件方式或者使用从模式控制器)设置UG位也同样可以产生一个更新事件。
设置TIMx_CR1 寄存器中的UDIS位,可以禁止更新事件;这样可以避免在向预装载寄存器中写入新值时更新影子寄存器。在UDIS位被清’0’之前,将不产生更新事件。但是在应该产生更新事件时,计数器仍会被清’0’,同时预分频器的计数也被请0(但预分频系数不变)。此外,如果设置了 TIMx_CR1 寄存器中的URS位(选择更新请求),设置UG位将产生一个更新事件UEV,但硬件不设置UIF标志(即不产生中断或DMA请求);这是为了避免在捕获模式下清除计数器时,同时产生更新和捕获中断。
当发生一个更新事件时,所有的寄存器都被更新,硬件同时(依据 URS 位)设置更新标志位(TIMx_SR寄存器中的UIF位)。
● 预分频器的缓冲区被置入预装载寄存器的值(TIMx_PSC寄存器的内容)。
● 自动装载影子寄存器被重新置入预装载寄存器的值(TIMx_ARR)。
下图给出一些例子,当TIMx_ARR=0x36时计数器在不同时钟频率下的动作。
图4 计数器时序图,内部时钟分频因子为1
图5 计数器时序图,内部时钟分频因子为2
图6 计数器时序图,内部时钟分频因子为4
图7 计数器时序图,内部时钟分频因子为N
图8 计数器时序图,当ARPE=0时的更新事件(TIMx_ARR没有预装入)
图9 计数器时序图,当ARPE=1 时的更新事件(预装入了TIMx_ARR)
3.2.2 向下计数模式
在向下模式中,计数器从自动装入的值(TIMx_ARR计数器的值)开始向下计数到0,然后从自动装入的值重新开始并且产生一个计数器向下溢出事件。
每次计数器溢出时可以产生更新事件,在TIMx_EGR寄存器中(通过软件方式或者使用从模式控制器)设置UG位,也同样可以产生一个更新事件。
设置TIMx_CR1 寄存器的UDIS位可以禁止UEV事件。这样可以避免向预装载寄存器中写入新值时更新影子寄存器。因此UDIS位被清为’0’之前不会产生更新事件。然而,计数器仍会从当前自动加载值重新开始计数,同时预分频器的计数器重新从0开始(但预分频系数不变)。
此外,如果设置了 TIMx_CR1 寄存器中的URS位(选择更新请求) ,设置UG位将产生一个更新事件UEV但不设置UIF标志(因此不产生中断和DMA请求),这是为了避免在发生捕获事件并清除计数器时,同时产生更新和捕获中断。
当发生更新事件时,所有的寄存器都被更新,并且(根据URS位的设置)更新标志位(TIMx_SR寄存器中的UIF位)也被设置。
● 预分频器的缓存器被置入预装载寄存器的值(TIMx_PSC寄存器的值)。
● 当前的自动加载寄存器被更新为预装载值(TIMx_ARR寄存器中的内容)。
注:自动装载在计数器重载入之前被更新,因此下一个周期将是预期的值。
以下是一些当TIMx_ARR=0x36时,计数器在不同时钟频率下的操作例子。
图10 计数器时序图,内部时钟分频因子为1
图11 计数器时序图,内部时钟分频因子为2
图12 计数器时序图,内部时钟分频因子为4
图13 计数器时序图,内部时钟分频因子为N
图14 计数器时序图,当没有使用重复计数器时的更新事件
3.2.3 中央对齐模式(向上/向下计数)
在中央对齐模式,计数器从0开始计数到自动加载的值(TIMx_ARR寄存器)−1 ,产生一个计数器溢出事件,然后向下计数到1 并且产生一个计数器下溢事件;然后再从0开始重新计数。
在这个模式,不能写入TIMx_CR1 中的DIR方向位。它由硬件更新并指示当前的计数方向。可以在每次计数上溢和每次计数下溢时产生更新事件;也可以通过(软件或者使用从模式控制器)设置TIMx_EGR寄存器中的UG位产生更新事件。然后,计数器重新从0开始计数,预分频器也重新从0开始计数。
设置TIMx_CR1 寄存器中的UDIS位可以禁止UEV事件。这样可以避免在向预装载寄存器中写入新值时更新影子寄存器。因此UDIS位被清为’0’之前不会产生更新事件。然而,计数器仍会根据当前自动重加载的值,继续向上或向下计数。
此外,如果设置了 TIMx_CR1 寄存器中的URS位(选择更新请求) ,设置UG位将产生一个更新事件UEV但不设置UIF标志(因此不产生中断和DMA请求),这是为了避免在发生捕获事件并清除计数器时,同时产生更新和捕获中断。
当发生更新事件时,所有的寄存器都被更新,并且(根据URS位的设置)更新标志位(TIMx_SR寄存器中的UIF位)也被设置。
● 预分频器的缓存器被加载为预装载(TIMx_PSC寄存器)的值。
● 当前的自动加载寄存器被更新为预装载值(TIMx_ARR寄存器中的内容)。
注:如果因为计数器溢出而产生更新,自动重装载将在计数器重载入之前被更新,因此下一个周期将是预期的值(计数器被装载为新的值)。
以下是一些计数器在不同时钟频率下的操作的例子:
图15 计数器时序图,内部时钟分频因子为1 , TIMx_ARR=0x6
图16 计数器时序图,内部时钟分频因子为2
图17 计数器时序图,内部时钟分频因子为4, TIMx_ARR=0x36
图18 计数器时序图,内部时钟分频因子为N
图19 计数器时序图, ARPE=1 时的更新事件(计数器下溢)
图20 计数器时序图, ARPE=1 时的更新事件(计数器溢出)
计数器时钟可由下列时钟源提供:
● 内部时钟(CK_INT)
● 外部时钟模式1 :外部输入脚(TIx)
● 外部时钟模式2:外部触发输入(ETR)
● 内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1 而作为另一个定时器Timer2的预分频器。
3.3.1 内部时钟源(CK_INT)
如果禁止了从模式控制器(TIMx_SMCR寄存器的SMS=000),则CEN、 DIR(TIMx_CR1 寄存器)和UG位(TIMx_EGR寄存器)是事实上的控制位,并且只能被软件修改(UG位仍被自动清除)。只
要CEN位被写成’1’,预分频器的时钟就由内部时钟CK_INT提供。
下图显示了控制电路和向上计数器在一般模式下,不带预分频器时的操作。
图21 一般模式下的控制电路,内部时钟分频因子为1
3.3.2 外部时钟源模式1
当TIMx_SMCR寄存器的SMS=111 时,此模式被选中。计数器可以在选定输入端的每个上升沿或下降沿计数。
图22 TI2外部时钟连接例子
例如,要配置向上计数器在T12输入端的上升沿计数,使用下列步骤:
1. 配置TIMx_CCMR1 寄存器CC2S=’01’,配置通道2检测TI2输入的上升沿
2. 配置TIMx_CCMR1 寄存器的IC2F[3:0],选择输入滤波器带宽(如果不需要滤波器,保持IC2F=0000)
注: 捕获预分频器不用作触发,所以不需要对它进行配置
3. 配置TIMx_CCER寄存器的CC2P=’0’,选定上升沿极性
4. 配置TIMx_SMCR寄存器的SMS=’111’,选择定时器外部时钟模式1
5. 配置TIMx_SMCR寄存器中的TS=’110’,选定TI2作为触发输入源
6. 设置TIMx_CR1 寄存器的CEN=’1’,启动计数器
当上升沿出现在TI2,计数器计数一次,且TIF标志被设置。在TI2的上升沿和计数器实际时钟之间的延时,取决于在TI2输入端的重新同步电路。
图23 外部时钟模式1 下的控制电路
3.3.3 外部时钟源模式2
选定此模式的方法为:令TIMx_SMCR寄存器中的ECE=1
计数器能够在外部触发ETR的每一个上升沿或下降沿计数(下图是外部触发输入的框图)
图24 外部触发输入框图
例如,要配置在ETR下每2个上升沿计数一次的向上计数器,使用下列步骤:
1. 本例中不需要滤波器,置TIMx_SMCR寄存器中的ETF[3:0]=0000
2. 设置预分频器,置TIMx_SMCR寄存器中的ETPS[1:0]=01
3. 设置在ETR的上升沿检测,置TIMx_SMCR寄存器中的ETP=0
4. 开启外部时钟模式2,置TIMx_SMCR寄存器中的ECE=1
5. 启动计数器,置TIMx_CR1 寄存器中的CEN=1
计数器在每2个ETR上升沿计数一次。
在ETR的上升沿和计数器实际时钟之间的延时取决于在ETRP信号端的重新同步电路。
图25 外部时钟模式2下的控制电路
每一个捕获/比较通道都是围绕着一个捕获/比较寄存器(包含影子寄存器),包括捕获的输入部分(数字滤波、多路复用和预分频器),和输出部分(比较器和输出控制)。(下面几张图是一个捕获/比较通道概览。)
输入部分对相应的TIx输入信号采样,并产生一个滤波后的信号TIxF。然后,一个带极性选择的边缘检测器产生一个信号(TIxFPx),它可以作为从模式控制器的输入触发或者作为捕获控制。该信号通过预分频进入捕获寄存器(ICxPS)。
图26 捕获/比较通道(如:通道1 输入部分)
输出部分产生一个中间波形OCxRef(高有效)作为基准,链的末端决定最终输出信号的极性。
图27 捕获/比较通道1 的主电路
图28 捕获/比较通道的输出部分(通道1)
捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。读写过程仅操作预装载寄存器。
在捕获模式下,捕获发生在影子寄存器上,然后再复制到预装载寄存器中。
在比较模式下,预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较。
在输入捕获模式下,当检测到ICx信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中。当捕获事件发生时,相应的CCxIF标志(TIMx_SR寄存器)被置’1’,如果使能了中断或者DMA操作,则将产生中断或者DMA操作。如果捕获事件发生时CCxIF标志已经为高,那么重复捕获标志CCxOF(TIMx_SR寄存器)被置’1’。写CCxIF=0可清除CCxIF,或读取存储在TIMx_CCRx寄存器中的捕获数据也可清除CCxIF。写CCxOF=0可清除CCxOF。
以下例子说明如何在TI1 输入的上升沿时捕获计数器的值到TIMx_CCR1 寄存器中,步骤如下:
● 选择有效输入端: TIMx_CCR1 必须连接到TI1 输入,所以写入TIMx_CCR1 寄存器中的CC1S=01 ,只要CC1S不为’00’,通道被配置为输入,并且TM1_CCR1 寄存器变为只读。
● 根据输入信号的特点,配置输入滤波器为所需的带宽(即输入为TIx时,输入滤波器控制位是TIMx_CCMRx寄存器中的ICxF位)。假设输入信号在最多5个内部时钟周期的时间内抖动,我们须配置滤波器的带宽长于5个时钟周期。因此我们可以(以fDTS频率)连续采样8次,以确认在TI1 上一次真实的边沿变换,即在TIMx_CCMR1 寄存器中写入IC1F=0011 。
● 选择TI1 通道的有效转换边沿,在TIMx_CCER寄存器中写入CC1P=0(上升沿)。
● 配置输入预分频器。在本例中,我们希望捕获发生在每一个有效的电平转换时刻,因此预分频器被禁止(写TIMx_CCMR1 寄存器的IC1PS=00)。
● 设置TIMx_CCER寄存器的CC1E=1 ,允许捕获计数器的值到捕获寄存器中。
● 如果需要,通过设置TIMx_DIER寄存器中的CC1IE位允许相关中断请求,通过设置TIMx_DIER寄存器中的CC1DE位允许DMA请求。
当发生一个输入捕获时:
● 产生有效的电平转换时,计数器的值被传送到TIMx_CCR1 寄存器。
● CC1IF标志被设置(中断标志)。当发生至少2个连续的捕获时,而CC1IF未曾被清除,CC1OF也被置’1’。
● 如设置了CC1IE位,则会产生一个中断。
● 如设置了CC1DE位,则还会产生一个DMA请求。
为了处理捕获溢出,建议在读出捕获溢出标志之前读取数据,这是为了避免丢失在读出捕获溢出标志之后和读取数据之前可能产生的捕获溢出信息。
注:设置TIMx_EGR寄存器中相应的CCxG位,可以通过软件产生输入捕获中断和/或DMA请求。
3.6 PWM输入模式
该模式是输入捕获模式的一个特例,除下列区别外,操作与输入捕获模式相同:
● 两个ICx信号被映射至同一个TIx输入。
● 这2个ICx信号为边沿有效,但是极性相反。
● 其中一个TIxFP信号被作为触发输入信号,而从模式控制器被配置成复位模式。
例如,你需要测量输入到TI1 上的PWM信号的长度(TIMx_CCR1 寄存器)和占空比(TIMx_CCR2寄存器),具体步骤如下(取决于CK_INT的频率和预分频器的值)
● 选择TIMx_CCR1 的有效输入:置TIMx_CCMR1 寄存器的CC1S=01(选择TI1)。
● 选择TI1FP1 的有效极性(用来捕获数据到TIMx_CCR1 中和清除计数器):置CC1P=0(上升沿有效)。
● 选择TIMx_CCR2的有效输入:置TIMx_CCMR1 寄存器的CC2S=10(选择TI1)。
● 选择TI1FP2的有效极性(捕获数据到TIMx_CCR2):置CC2P=1(下降沿有效)。
● 选择有效的触发输入信号:置TIMx_SMCR寄存器中的TS=101(选择TI1FP1)。
● 配置从模式控制器为复位模式:置TIMx_SMCR中的SMS=100。
● 使能捕获:置TIMx_CCER寄存器中CC1E=1 且CC2E=1 。
图29 PWM输入模式时序
由于只有 TI1FP1 和 TI2FP2 连到了从模式控制器,所以 PWM 输入模式只能使用 TIMx_CH1/TIMx_CH2信号。
在输出模式(TIMx_CCMRx寄存器中 CCxS=00)下,输出比较信号(OCxREF和相应的OCx)能够直接由软件强置为有效或无效状态,而不依赖于输出比较寄存器和计数器间的比较结果。
置TIMx_CCMRx寄存器中相应的OCxM=101 ,即可强置输出比较信号(OCxREF/OCx)为有效状态。这样OCxREF被强置为高电平(OCxREF始终为高电平有效),同时OCx得到CCxP极性位相反的值。
例如: CCxP=0(OCx高电平有效),则OCx被强置为高电平。
置TIMx_CCMRx寄存器中的OCxM=100,可强置OCxREF信号为低。
该模式下,在TIMx_CCRx影子寄存器和计数器之间的比较仍然在进行,相应的标志也会被修改。因此仍然会产生相应的中断和DMA请求。这将会在下面的输出比较模式一节中介绍。
此项功能是用来控制一个输出波形,或者指示一段给定的的时间已经到时。
当计数器与捕获/比较寄存器的内容相同时,输出比较功能做如下操作:
● 将输出比较模式(TIMx_CCMRx寄存器中的OCxM位)和输出极性(TIMx_CCER寄存器中的CCxP位)定义的值输出到对应的引脚上。在比较匹配时,输出引脚可以保持它的电平(OCxM=000)、被设置成有效电平(OCxM=001)、被设置成无效电平(OCxM=010)或进行翻转(OCxM=011)。
● 设置中断状态寄存器中的标志位(TIMx_SR寄存器中的CCxIF位)。
● 若设置了相应的中断屏蔽(TIMx_DIER寄存器中的CCxIE位),则产生一个中断。
● 若设置了相应的使能位(TIMx_DIER寄存器中的CCxDE位, TIMx_CR2寄存器中的CCDS位选择DMA请求功能),则产生一个DMA请求。
TIMx_CCMRx中的OCxPE位选择TIMx_CCRx寄存器是否需要使用预装载寄存器。
在输出比较模式下,更新事件UEV对OCxREF和OCx输出没有影响。
同步的精度可以达到计数器的一个计数周期。输出比较模式(在单脉冲模式下)也能用来输出一个单脉冲。
输出比较模式的配置步骤:
1. 选择计数器时钟(内部,外部,预分频器)
2. 将相应的数据写入TIMx_ARR和TIMx_CCRx寄存器中
3. 如果要产生一个中断请求和/或一个DMA请求,设置CCxIE位和/或CCxDE位。
4. 选择输出模式,例如当计数器CNT与CCRx匹配时翻转OCx的输出引脚, CCRx预装载未用,开启 OCx输出且高电平有效,则必须设置OCxM=’011’、 OCxPE=’0’、 CCxP=’0’和CCxE=’1’。
5. 设置TIMx_CR1 寄存器的CEN位启动计数器
TIMx_CCRx寄存器能够在任何时候通过软件进行更新以控制输出波形,条件是未使用预装载寄存器(OCxPE=’0’,否则TIMx_CCRx影子寄存器只能在发生下一次更新事件时被更新)。下图给
出了一个例子。
图30 输出比较模式,翻转OC1
脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。
在TIMx_CCMRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1 寄存器的ARPE位, (在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。
仅当发生一个更新事件的时候,预装载寄存器才能被传送到影子寄存器,因此在计数器开始计数之前,必须通过设置TIMx_EGR寄存器中的UG位来初始化所有的寄存器。
OCx的极性可以通过软件在TIMx_CCER寄存器中的CCxP位设置,它可以设置为高电平有效或低电平有效。 TIMx_CCER寄存器中的CCxE位控制OCx输出使能。
在PWM模式(模式1 或模式2)下, TIMx_CNT和TIMx_CCRx始终在进行比较, (依据计数器的计数方向 ) 以确 定是否符合 TIMx_CCRx≤ TIMx_CNT 或者 TIMx_CNT ≤ TIMx_CCRx 。然而为了与
OCREF_CLR的功能(在下一个PWM周期之前,ETR信号上的一个外部事件能够清除OCxREF)一致,OCxREF信号只能在下述条件下产生:
● 当比较的结果改变
● 当输出比较模式(TIMx_CCMRx寄存器中的OCxM位)从“冻结” (无比较, OCxM=’000’)切换到某个PWM模式(OCxM=’110’或’111’)
这样在运行中可以通过软件强置PWM输出。根据TIMx_CR1 寄存器中 CMS位的状态,定时器能够产生边沿对齐的PWM信号或中央对齐的PWM信号。
>_<" PWM 边沿对齐模式 (向上计数配置当TIMx_CR1 寄存器中的DIR位为低的时候执行向上计数。)
下面是一个PWM模式1 的例子。当TIMx_CNT<TIMx_CCRx时PWM信号参考OCxREF为高,否则为低。如果TIMx_CCRx中的比较值大于自动重装载值(TIMx_ARR),则OCxREF保持为’1’。
如果比较值为0,则OCxREF保持为’0’。 下图为TIMx_ARR=8时边沿对齐的PWM波形实例。
图31 边沿对齐的PWM波形(ARR=8)
>_<" 向下计数的配置(当TIMx_CR1 寄存器的DIR位为高时执行向下计数。)
在PWM模式1,当TIMx_CNT>TIMx_CCRx时参考信号OCxREF为低,否则为高。如果TIMx_CCRx中的比较值大于TIMx_ARR中的自动重装载值,则OCxREF保持为’1’。该模式下不能产生0%的PWM波形。
>_<" PWM 中央对齐模式(当TIMx_CR1 寄存器中的CMS位不为’00’时,为中央对齐模式(所有其他的配置对OCxREF/OCx信号都有相同的作用)。)
根据不同的CMS位设置,比较标志可以在计数器向上计数时被置’1’、在计数器向下计数时被置’1’、或在计数器向上和向下计数时被置’1’。 TIMx_CR1 寄存器中的计数方向位(DIR)由硬件更新,不要用软件修改它。
● TIMx_ARR=8
● PWM模式1
● TIMx_CR1 寄存器中的CMS=01 ,在中央对齐模式1 时,当计数器向下计数时设置比较标志。
图32 中央对齐的PWM波形(APR=8)
使用中央对齐模式的提示:
● 进入中央对齐模式时,使用当前的向上/向下计数配置;这就意味着计数器向上还是向下计数取决于TIMx_CR1 寄存器中DIR位的当前值。此外,软件不能同时修改DIR和CMS位。
● 不推荐当运行在中央对齐模式时改写计数器,因为这会产生不可预知的结果。特别地:
─ 如果写入计数器的值大于自动重加载的值(TIMx_CNT>TIMx_ARR),则方向不会被更新。
例如,如果计数器正在向上计数,它就会继续向上计数。
─ 如果将0或者TIMx_ARR的值写入计数器,方向被更新,但不产生更新事件UEV。
● 使用中央对齐模式最保险的方法,就是在启动计数器之前产生一个软件更新(设置TIMx_EGR 位中的UG位),不要在计数进行过程中修改计数器的值。
单脉冲模式(OPM)是前述众多模式的一个特例。这种模式允许计数器响应一个激励,并在一个程序可控的延时之后,产生一个脉宽可程序控制的脉冲。
可以通过从模式控制器启动计数器,在输出比较模式或者PWM模式下产生波形。设置TIMx_CR1寄存器中的OPM位将选择单脉冲模式,这样可以让计数器自动地在产生下一个更新事件UEV时停止。
仅当比较值与计数器的初始值不同时,才能产生一个脉冲。启动之前(当定时器正在等待触发),必须如下配置:
向上计数方式: CNT < CCRx ≤ ARR (特别地, 0 < CCRx)
向下计数方式: CNT > CCRx
图33 单脉冲模式的例子
例如,你需要在从TI2输入脚上检测到一个上升沿开始,延迟tDELAY之后,在OC1 上产生一个长度为tPULSE的正脉冲。
4.1 使得PB5-TIM3通道2产生频率为12.5Hz的方波,该方波控制LED1的闪烁
>_<" 主函数为:
1 int main(void) 2 { 3 RCC_Configuration(); //系统时钟设置及外设时钟使能 4 NVIC_Configuration(); //中断源配置 5 time_ini(); //定时器3的初始化 6 while(1); 7 }
>_<" 配置各外设的时钟和系统时钟:(有些是多余的)
1 /**************************************************************************** 2 * 名 称:void RCC_Configuration(void) 3 * 功 能:系统时钟配置为72MHZ, 外设时钟配置 4 ****************************************************************************/ 5 void RCC_Configuration(void){ 6 7 SystemInit(); 8 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 9 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC 10 | RCC_APB2Periph_GPIOD| RCC_APB2Periph_GPIOE , ENABLE); 11 }
>_<" 配置中断向量:(因为这里用到了TIM3,所以要配置其中断向量)
1 /**************************************************************************** 2 * 名 称:void NVIC_Configuration(void) 3 * 功 能:中断源配置 4 ****************************************************************************/ 5 void NVIC_Configuration(void) 6 { 7 NVIC_InitTypeDef NVIC_InitStructure; 8 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); 9 10 NVIC_InitStructure.NVIC_IRQChannel =TIM3_IRQn ; //配置定时器中断 11 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 12 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 13 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 14 NVIC_Init(&NVIC_InitStructure); 15 }
>_<" TIM3的2通道配置:(下面首先配置GPIO PB5(为Tim3的2通道),PB5引脚默认是作为通用IO口使用,为了产生特定频率,利用了该引脚可以复用为TIM3_CH2,根据手册,需要用到局部复用映射,才能将TIM3_CH2映射到PB5。)
在定时器3的初始化中,用到了输出比较2模式的翻转设置。也就是当TIM3_CCR2=TIM3_CNT时,翻转输出的电平。以产生需要的频率,TIM3_CCR2的值决定了翻转的频率。当TIM3_CCR2=TIM3_CNT时,产生一次电平翻转,并在中断服务程序里重新完成对TIM3_CCR2的装载。依次往复,产生了所需要的12.5Hz的频率。(注意注释的第15~17行介绍如何控制输出频率,CCR2_Val=45000)
1 void time_ini(void){ 2 GPIO_InitTypeDef GPIO_InitStructure; 3 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //定时器3 时钟使能 4 5 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PB5复用为TIM3的通道2 6 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 7 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 8 GPIO_Init(GPIOB, &GPIO_InitStructure); 9 10 /* TIM3局部复用功能开启 在TIM3的局部复用开启时,PB5会被复用为TIM3_CH2*/ 11 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 , ENABLE); 12 13 /* Time Base configuration */ 14 /*------------------------------------------------------------------- 15 TIM3CLK=72MHz 预分频系数Prescaler=63 经过分频 定时器时钟为1.125MHz 16 捕获/比较寄存器2 TIM3_CCR2= CCR2_Val 17 2通道产生的更新频率是=1.125MHz/CCR2_Val=25Hz 18 19 -------------------------------------------------------------------*/ 20 TIM3_TimeBaseStructure.TIM_Prescaler = 63; //预分频器TIM3_PSC=63 21 TIM3_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器向上计数模式 TIM3_CR1[4]=0 22 TIM3_TimeBaseStructure.TIM_Period =0xffff; //自动重装载寄存器TIM3_APR 23 TIM3_TimeBaseStructure.TIM_ClockDivision = 0x0; //时钟分频因子 TIM3_CR1[9:8]=00 24 25 TIM_TimeBaseInit(TIM3,&TIM3_TimeBaseStructure); //写TIM3各寄存器参数 26 27 TIM3_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle ; //TIM3_CCMR1[14:12]=011 翻转 当TIM3_CCR2=TIM3_CNT时,翻转OC2REF的电平 28 TIM3_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输入/捕获2输出允许 OC2信号输出到对应的输出引脚PB5 29 TIM3_OCInitStructure.TIM_Pulse =CCR2_Val; //若CC1通道配置为输出:CCR2是装入当前捕获/比较2 TIM3_CCR2寄存器的值(预装载值)。 30 //当前捕获/比较寄存器包含了与计数器TIM3_CNT比较的值,并且在OC端口上输出信号 31 TIM3_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性 低电平有效 TIM3_CCER[5]=1; 32 33 TIM_OC2Init(TIM3, &TIM3_OCInitStructure); 34 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable); //TIM3_CCMR1[1]=0 禁止TIM3_CCR2寄存器的预装载功能,可随时写入TIM3_CCR2 35 //且新值马上起作用 36 37 TIM_Cmd(TIM3,ENABLE); //启动定时器3 TIM3_CR1[0]=1; 38 TIM_ITConfig(TIM3,TIM_IT_CC2,ENABLE); //TIM3_DIER[2]=1 允许捕获/比较2中断 39 }
>_<" TIM3的中断服务子程序(每次TIM3_CCR2=TIM3_CNT产生一次中断,在中断子程序中取出上一次的TIM3_CCR2加上CCR2_Val作为新的TIM3_CCR2,这样等TIM3_CNT加到和TIM3_CCR2相等时又会触发一次中断)
1 void TIM3_IRQHandler(void) 2 { 3 4 if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET) //判断状态寄存器 TIM3_SR[2] 是否发生了捕获/比较2 中断 5 { 6 TIM_ClearITPendingBit(TIM3, TIM_IT_CC2); //软件清除状态寄存器 TIM3_SR[2] 捕获/比较2 中断中断标志 7 8 capture1 = TIM_GetCapture2(TIM3); //获取TIM3_CCR2的预装值 9 TIM_SetCompare2(TIM3, capture1+ CCR2_Val); //和CCR2_Val累加后装入TIM3_CCR2 这是为了配合计数器值的递增。以在下一次作出比较。 10 11 } 12 }
4.2 周期控制通用定时器3的2通道,实现1KHz的不同占空比波形,控制LED实现呼吸灯
>_<" 主函数为:(不同于上面固定的频率定时方法,这里在while里不断更改CCR2_Val的值来改变占空比)
1 int main(void) 2 { 3 unsigned char a=0; 4 TIM_OCInitTypeDef TIM3_OCInitStructure; 5 RCC_Configuration(); 6 time_ini(); 7 SysTick_Config(72000); //配置SYSTICK时钟节拍为1ms一次 8 while(1){ 9 Delay(1); //延时1ms 10 TIM3_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2 11 TIM3_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出禁止 12 TIM3_OCInitStructure.TIM_Pulse = CCR2_Val; //确定占空比 13 TIM3_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 14 TIM_OC2Init(TIM3, &TIM3_OCInitStructure); 15 16 /*调整CCR2_Val的值来改变占空比,逐步的控制LED1的亮度, 占空比大过一定值时, 17 亮度的变化就不明显了,所以CCR2_VAL最大设定到17000*/ 18 if(a==0) CCR2_Val=CCR2_Val+10; 19 else CCR2_Val=CCR2_Val-10; 20 if(CCR2_Val>17000){ CCR2_Val=17000; a=1;} 21 else if(CCR2_Val<200){ CCR2_Val=200; a=0;} 22 } 23 }
>_<" 配置各外设的时钟和系统时钟:(同4.1有些是多余的)
1 /**************************************************************************** 2 * 名 称:void RCC_Configuration(void) 3 * 功 能:系统时钟配置为72MHZ, 外设时钟配置 4 ****************************************************************************/ 5 void RCC_Configuration(void){ 6 7 SystemInit(); 8 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 9 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC 10 | RCC_APB2Periph_GPIOD| RCC_APB2Periph_GPIOE , ENABLE); 11 }
>_<" TIM3的2通道配置:(注意,这里没有用到中断向量和中断子程序!!!下面首先配置GPIO PB5(为Tim3的2通道),PB5引脚默认是作为通用IO口使用,为了产生特定频率,利用了该引脚可以复用为TIM3_CH2,根据手册,需要用到局部复用映射,才能将TIM3_CH2映射到PB5。)
由于TIM3计数器的时钟频率是72MHz,希望各通道输出频率为1KHZ,根据3倍预分频后,时钟频率为24MHz,根据公式ftim3=TIM3CLK/(TIM3_Period+1),可得到TIM3预分频的值为24000, 根据公式根据公式 通道输出占空比=TIM3_CCR2/(TIM_Period+1),可以得到TIM_Pulse的计数值,逐步改变这个值,可以控制占空比, 从而获得LED1 亮度明暗渐变的效果。(所以在main函数的while中不断重置CCR2_Val值来控制不同占空比)
1 /**************************************************************************** 2 * 名 称:void time_ini(void) 3 * 功 能:TIM3初始化 4 ****************************************************************************/ 5 void time_ini(void){ 6 GPIO_InitTypeDef GPIO_InitStructure; 7 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 8 9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PB5复用为TIM3的通道2 10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 11 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 12 GPIO_Init(GPIOB, &GPIO_InitStructure); 13 /*TIM3局部复用功能开启 在TIM3的局部复用开启时,PB5会被复用为TIM3_CH2*/ 14 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 , ENABLE); 15 16 /*------------------------------------------------------------------- 17 TIM3CLK=72MHz 预分频系数Prescaler=2 经过分频 定时器时钟为24MHz 18 根据公式 通道输出占空比=TIM3_CCR2/(TIM_Period+1),可以得到TIM_Pulse的计数值 19 捕获/比较寄存器2 TIM3_CCR2= CCR2_Val 20 -------------------------------------------------------------------*/ 21 TIM3_TimeBaseStructure.TIM_Prescaler = 2; //预分频器TIM3_PSC=3 22 TIM3_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器向上计数模式 TIM3_CR1[4]=0 23 TIM3_TimeBaseStructure.TIM_Period =24000; //自动重装载寄存器TIM3_APR 确定频率为1KHz 24 TIM3_TimeBaseStructure.TIM_ClockDivision = 0x0; //时钟分频因子 TIM3_CR1[9:8]=00 25 TIM3_TimeBaseStructure.TIM_RepetitionCounter = 0x0; 26 27 TIM_TimeBaseInit(TIM3,&TIM3_TimeBaseStructure); //写TIM3各寄存器参数 28 29 TIM3_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2 TIM3_CCMR1[14:12]=111 在向上计数时, 30 //一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平 31 TIM3_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输入/捕获2输出允许 OC2信号输出到对应的输出引脚PB5 32 TIM3_OCInitStructure.TIM_Pulse = CCR2_Val; //确定占空比,这个值决定了有效电平的时间。 33 TIM3_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性 低电平有效 TIM3_CCER[5]=1; 34 35 TIM_OC2Init(TIM3, &TIM3_OCInitStructure); 36 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); 37 TIM_Cmd(TIM3,ENABLE); //启动定时器3 TIM3_CR1[0]=1; 38 }
本文正版链接:http://www.cnblogs.com/zjutlitao/p/4652695.html
工程4.1 TIM3-CH2链接:http://pan.baidu.com/s/1c0dLgAW
工程4.2 TIM3-PWM链接: http://pan.baidu.com/s/1dDjiMnn
上述两个工程的说明(建议直接看我博客):http://pan.baidu.com/s/1ntkoym9
stm32几个重要的文件:http://pan.baidu.com/s/1qW41bw4