本应用笔记描述了如何针对不同的应用设置和使用MAXQ™系列微控制器中的Type 2定时器。它包括供参考的源代码。
介绍
MAXQ系列微控制器有三种类型的定时器:定时器0、定时器1和定时器2。
MAXQ定时器0型是仿照许多0微型控制器上常见的定时器8051型。MAXQ定时器1类型仿照8051定时器2类型。大多数MAXQ产品都有一个新的定时器,称为定时器2,这是MAXQ系列独有的。本应用笔记详细介绍了如何为不同目的设置和使用这款新的定时器2,并附有一些源代码供参考。
概述
功能
定时器的三个主要用途是生成输出波形、对输入信号的转换进行计数(包括对系统时钟转换进行计数,从而起到定时器的作用)以及对输入信号进行计时。本节介绍使用计时器 2 的配置模式执行这些计时器功能的方法。
比较
在此模式下,计数器由系统时钟或备用时钟(通常为 32,768 Hz RTC 时钟)在内部提供,其中任何一个都可以选择按 1、2、4、8、16、32、64 或 128 进行预分频。然后,计数器用于控制初级和/或次级定时器引脚的输出,以生成各种波形。
通过改变重载(T2R)和比较(T2C)寄存器中的值,可以修改输出波形的频率和占空比。这样,MAXQ处理器就可以产生脉宽调制(PWM)波形。输出可以有选择地使能,起始极性可以反转。频率和占空比的限制由选择作为源的时钟的频率(无论是系统时钟还是备用时钟)和所选的时钟除数决定。最小脉冲宽度为预分频源时钟的一个时钟周期(通过将比较值和重载值设置为相同值或将比较值设置为 FFFEh 来选择)。最大脉冲宽度为预分频源时钟的 65,536 个周期。预标因数为 128 时,最大脉冲宽度为 8,388,608 个系统时钟周期 - 对于 1 MHz 系统时钟,超过 <> 秒。使用频率较低的交替时钟可以进一步增加此值。
比较模式还提供了通过使用单脉冲 (SS2) 功能生成单个脉冲的功能。单脉冲允许固件在触发脉冲之前设置脉冲的长度,从而排除了固件对脉冲进行计时并确定何时结束的要求。门控允许初级引脚触发次级输出上的单个脉冲或打开和关闭计数器,从而允许输入信号修改次级引脚上的PWM输出。比较模式还可用于按特定计划生成重复中断。
捕获
在这种模式下,计数器在内部供电,但用于计算或计时主定时器引脚上输入信号的持续时间。计数器可以在输入信号的任一或两个边缘进行选通和触发,从而可以灵活地定时脉冲、单个事件或递归波形。T2C寄存器中的值可用于计算测量事件的周期。
计数器 在此模式下,主定时器引脚为计数器
提供时钟源。在这种模式下,计数器计算主引脚上的转换,上升沿或下降沿,或两者兼而有之。次级引脚可用于输出波形,当计数溢出以及计数器与特定值匹配时,波形将切换。在这两种情况下也可以生成中断。
双八位模式定时器2可以在十六位模式下运行(在这种情况下只有一个计数器可用)或八位模式,八位模式
将计数器视为两个八位计数器,可以独立使用。这允许定时器电路具有三个附加功能。在八位模式下,主计数器(高计数器)可用于比较、捕获或计数器功能,而次级计数器(低计数器)可用于比较或PWM输出。
双比较
在这种模式下,每个八位计数器单独计数,可用于输出波形,但每个计数器都来自相同的内部时钟源。通过使用每个八位计数器的不同重载和比较值,可以在两个定时器引脚上输出波形的不同频率和占空比。
捕获/PWM
在此模式下,一个八位计数器(高计数器)在捕获模式下工作,以计时输入信号的持续时间。另一个八位计数器(低计数器)在比较模式下工作,可用于输出波形。
计数器/PWM
在这种模式下,一个八位计数器(高计数器)在计数器模式下工作,以计算输入信号的转换。另一个八位计数器(低计数器)在比较模式下工作,可用于输出波形。
选项
单次 (SS2) 此选项允许计数器像运行位 (T2R)
已打开一样运行,但仅在计数器下一次溢出之前运行。然后,计数器恢复为使用运行位来确定它是否将继续计数。在八位模式下,此位仅适用于主八位计数器(高计数器)。
门控使能 (G2EN)
此选项允许在一段时间内关闭计数器(即门控),而无需固件手动切换运行位 (T2R)。在比较和计数器模式下,门控适用于源时钟。在捕获模式下,门控适用于重新加载事件。
门控由主引脚上的值控制。这要求主引脚是输入(T2OE [0]=0),因此输出波形(如果需要)必须输出在次级(或B)引脚上。门控控制仅在主输入端可用。
极性选择 极性位
(T2POL [0] 和 T2POL [1])可用于反转输出波形。用于此功能时,必须在设置相应的输出使能位(T2OE [0] 和 T2OE [1])之前设置它们。设置使能位后设置极性位不起作用。T2POL [0] 位还可用于在初级引脚不用作输出时反相选通条件。T2POL [0] 位在捕获模式下也具有额外的含义,当两个边沿都定义为捕获时。在这种情况下,它定义哪个边缘开始单次注射循环,并在启用门控时禁止在一个边缘上重新加载。
输出使能 输出使能
位(T2OE [0] 和 T2OE [1])确定初级和次级引脚是否由定时器电路主动驱动。当输出使能位关断时,可以使用相应的端口输入寄存器将这些引脚读取为输入。当输出主引脚未使能时,可用于对计数器进行选通(关断)。
时钟选择 T2CI 位(备用时钟选择
)和 T2DIV [2:0] 位(时钟除数)用于设置计数器使用的时钟源和预缩放因子。T2CI 用于在系统时钟和备用时钟之间进行选择。然后,这些中的任何一个都可以按 2 倍进行预缩放n(n 是存储在 T0DIV 中的 7 到 2 之间的值)。
使用计时器
计数器寄存器 计数器在 2 位模式下有三个与之关联的寄存器,在 2 位模式下有三个附加寄存器
。这些寄存器可以在任一模式(2 位或 2 位)下读取和写入,但在 2 位模式下,低寄存器的行为不同。在 2 位模式下工作时,T2V、T2R 和 T2C 分别用作 <> 位计数器、重新加载和比较寄存器。在八位模式下工作时,这三个寄存器用作低阶八位寄存器。高阶寄存器由T<>H、T<>RH和T<>CH分别表示计数器、重载和比较寄存器。此外,这些寄存器充当主计数器的角色,T<>V、T<>R 和 T<>C 寄存器承担辅助角色。
这意味着,当定时器处于 8 位模式与 16 位模式时,使用定时器寄存器的任何代码的操作都将大不相同。因此,建议您对特定计时器使用八位模式或十六位模式。如果您需要在不同时间在两种模式下使用它,则为每种模式使用单独的函数将减少程序员的困惑。
在2位模式下,T2V寄存器包含电流计数。当运行位 (TR2) 或单脉冲位 (SS2) 导通且选通未激活 (G0EN=2) 时,此寄存器随所选时钟边沿递增。如果门控处于活动状态 (G1EN=2),则除了 TR2 或 SS2 导通外,初级引脚上的输入必须与初级极性位 (T0POL [<>]) 的极性相反,计数器才能递增。
T2R 寄存器保存计数器的重新加载值。每当此值溢出(已达到 FFFFh 并且由于再次递增)时,该值都会自动插入计数器 (T2V) 中。
控制和配置寄存器
有三个控制和配置寄存器:T2CFG、T2CNA 和 T2CNB。 T2CFG 包含常规配置信息。
C/T2位(计数器/定时器选择)选择定时器是在计数器模式还是定时器模式下工作(捕获、比较和捕获与比较输出是定时器模式的子模式)。在定时器模式下,CCF [1:0] 位(捕获/比较选择)确定定时器是处于比较模式 (CCF [1:0] = 00) 还是捕获模式 (CCF [1:0] = 01、10 或 11)。在计数器模式下,CCF 位确定将计算哪些边沿(下降、上升或两者兼而有之)。在计数器模式下,不使用 CCF 位中的值 00,因为计数器没有可计数的内容。 模式选择位 (T2MD) 确定定时器是作为一个 <> 位定时器还是两个独立的 <> 位定时器运行。设置后,选择两个八位定时器。次级定时器始终是比较/PWM 定时器。
可以选择系统时钟或备用时钟(在某些MAXQ实现中为32 kHz RTC时钟)作为源时钟,并且每个时钟都可以根据需要进行预分频。备用时钟选择位 (T2CI) 默认为 0,用于选择系统时钟。设置此位将选择备用时钟。
预分频器位 (T2DIV [2:0]) 选择时钟除数,范围从 1 到 128。预分频器的公式为 2n,其中 n 是 T2DIV [2:0] 中的值。
T2CNA 包含选通使能、单次触发、重载使能、运行使能、低运行使能、初级输出极性、主输出使能和中断使能位。
选通使能位(G2EN)允许有选择地禁用计数器。 单次触发位 (SS2) 允许定时器运行,直到下一个溢出情况,此时定时器停止。
捕获和重装位 (CPRL2) 指示定时器将其值捕获到其捕获寄存器中,并从外部边沿上的重载寄存器重新加载该值。CPRL2 不用于比较和计数器模式。
运行使能位 (TR2) 允许主计数器运行,低运行使能位 (TR2L) 允许辅助计数器在 <> 位模式下运行。
初级极性选择位 (T2POL0) 选择初级输出的初始极性。通过 T2OE0 启用输出后更改此位不起作用。设置主输出使能位 (T2OE0) 将打开初级引脚的输出,并将其值设置为等于极性位 (T2POL0) 中的值。
设置主中断使能 (ET2) 允许生成中断,前提是定时器模块已启用中断(在 IMR 寄存器中设置适当的位)并且已启用全局中断(IC 寄存器位 0 设置为 1)。当主计数器溢出(达到FFFFh)或与比较寄存器匹配时,将生成中断。在这些情况下,将设置适当的位(TF2 用于溢出,TCC2 用于比较),并应由中断处理程序中的固件重置。未能重置这些位将导致重复中断,直到它们被重置或中断被禁用。
T2CNB 包含比较和溢出标志、次级中断使能以及次级输出极性和使能位。
捕获/比较标志 (TCC2) 是在主计数器值与比较值匹配时设置的。
低捕获/比较标志 (TC2L) 类似于 TCC2,但仅在处于 <> 位模式且低计数器或次级计数器与低比较值匹配时才设置。
溢出标志 (TF2) 在主计数器溢出时设置。低溢出标志 (TF2L) 与 TF2 类似,但仅在处于 2 位模式且低计数器或次级计数器溢出时设置。 次级极性选择位 (T1POL2) 选择次级或 B 输出引脚的初始极性。通过 T1OE2 启用输出后更改此位不起作用。设置次级输出使能位 (T1OE2) 将打开次级引脚的输出,并将其值设置为等于极性位 (T1POL<>) 中的值。次级输出不直接链接到次级计数器,因为在 <> 位模式下,主计数器提供输出,而在 <> 位模式下,低计数器源输出。
设置次级中断使能 (ET2L) 允许在 2 位模式下,当次级或低位 2 位计数器的溢出 (TF2L) 或比较 (TC2L) 设置 TF2L 或 TC<>L 位时生成中断。ET<>L 位不用于 <> 位模式。
例子
比较示例 1 - 输出带门控
的波形 以下代码将输出频率为 100 Hz、占空比为 1/3 的信号。该代码是为 4.9152 MHz 的时钟速度编写的。4000h(16384 十进制)的重载值在重载和溢出以及随后的重载之间提供 C000h(49152 十进制)时钟周期,持续时间为 10 ms (100 Hz)。C000 的比较值为我们提供了 32768 个时钟周期 (C000h - 4000h) 或重新加载后 6.7 毫秒,将进行比较(以及因此产生的脉冲边沿)。
T2POL1 位设置初始值,因为我们使用的是次级输出,主输出用于选通。在这种情况下,T2POL0 位选择门控电平。当 T2POL1 设置为 0 时,输出的初始值为 0,因此输出低电平持续 6.7 毫秒,然后高电平持续 3.3 毫秒。只要初级引脚保持高电平,就会输出1/3占空比波形。当初级引脚被拉低时,计数器将停止计数,并将次级引脚保持在当前电平。通过将T2POL3设置为2,可以反转波形(产生1/1占空比脉冲)。通过将 T2POL0 设置为 1,可以将门控电平更改为高电平有效。
move T2V0, #04000h ; set to reload value to keep first pulse ; from being extra long move T2R0, #04000h ; reload value move T2C0, #0C000h ; compare value move T2CFG0, #000h ; ; 0000,0000 - use system clock (0), divide by 1 (000), ; 16 bit mode (0), compare mode (00), c/t2=timer (0) move T2CNB0, #040h ; 0100,0000 - ET2L off - low interrupts not available in 16-bit mode (0), ; secondary OE is on (1), POL1 = low starting value (0), reserved (0) ; TF2 is not used (0), TF2L is not used (0), TCC2 is not used (0), ; TC2L is not used (0) move T2CNA0, #009h ; 0000,1001 - ET2 off - interrupts not needed (0), ; primary OE off as primary pin is used for gating (0), ; POL0 low, gated when primary pin is low (0), TR2L is not needed (0) ; TR2 on, run enabled (1), CPRL2 is not needed (0), ; SS2 is not needed (0), gating enabled (1)
比较示例2 - 单次脉冲
以下代码是为MAXQ2000器件编写的,该器件具有3个独立的定时器2。它使用模块 4 中的第三个计时器。它也是为4.9152 MHz的系统时钟频率编写的,触发时将输出宽度为两毫秒的低脉冲,输出通常为高电平。在脉冲结束时,将生成一个中断,以指示脉冲已完成。此代码在八位模式下使用计时器,还演示了预分频器的用法。
为了获得所需的两毫秒周期,使用预标度值 64 和定时器周期 154 个预分频时钟 (4915200 / 64 * 0.002 = 153.6)。选择 66h (100h - 9Ah) 的比较值,在计数器从 FFh 溢出到 9 之前,会得到 154Ah(00 个十进制)的刻度。将重新加载值设置为 65h 会导致脉冲在我们设置 SS1(单次)位后开始 2 个刻度。
SetupPulse: ; This code sets up the timer and should be run once ; set up Int handler move IV, #IntHandler ; Set interrupt vector. move IC.0, #1 ; Enable global interrupts. move IMR.4, #1 ; Enable interrupts for module 3. ; timer 0 is in module 3, timer 1 & 2 are in module 4 move T2CFG2, #068h ; ; 0110,1000 -- use system clock (0), divide by 64 (110), ; 8 bit mode (1), compare mode (00), c/t2=timer (0) move T2CNB2, #000h ; 0000,0000 -- ET2L off, low interrupts not needed (0), secondary OE off (0), ; T2POL1 = not used (0), reserved(0) ; TF2 is generated by the timer (0), TF2L is not used (0), TCC2 is not used (0), ; TC2L is not used (0) move T2CNA2, #0E0h ; 1110,0000 -- ET2 on, interrupt will be generated (1), primary OE on (1), ; T2POL0 is high (1), TR2L is not needed (0) ; TR2 off, run not enabled (0), CPRL2 is not needed (0), SS2 is set later (0), ; gating disabled (0) move T2H2, #065h ; set to reload value move T2RH2, #065h ; move T2CH2, #066h ; 0x100 - 0x66(compare value) = 0x9A = 154 ticks
每当要触发脉冲时,都应调用以下代码。
TriggerPulse: move T2CNA2.1, #1 ; set the single shot bit to start the timer ret The following is a piece of the interrupt code. IntHandler: move c, T2CNB2.3 jump nc, NonTimerInt move T2CNB2.3, #0 ; turn off overflow bit so interrupt is serviced ; code for end of pulse here... NonTimerInt: ; other interrupt code here. reti
比较示例 3 - 定时中断 以下代码将生成两个中断
,每 125 微秒一个,第二个每毫秒一个。它使用一个分为两个八位定时器的定时器。由于两个八位定时器将在同一输入时钟上运行,因此我们希望选择一个时钟除数,允许两个定时器的计数小于256(八位计数器的最大值)。使用备用时钟作为源为我们提供了一种无需划分系统时钟即可获得两个时序的方法,但代价是一些精度:高计数器的实际时序接近 122 微秒,低计数器的实际时序接近 0.98 毫秒,因为备用时钟以 32768 Hz 运行,并且没有所需时间段的偶数除数可用。我们将从低计数器每秒获得 1024 个中断,从高计数器每秒获得 8192 个中断。高中断和低中断均使能,中断类型由TF2和TF2L位标识,必须清除这些位才能为中断提供服务。
; This code sets up the timer and should be run once ; set up Int handler move IV, #IntHandler ; Set interrupt vector. move IC.0, #1 ; Enable global interrupts. move IMR.3, #1 ; Enable interrupts for module 3. ; timer 0 is in module 3 move T2CFG0, #088h ; ; 1000,1000 -- use 32 kHz clock (1), divide by 1 (000), ; 8 bit mode (1), compare mode (00), c/t2=timer (0) move T2CNB0, #080h ; 1000,0000 -- ET2L on, low interrupt will be generated (1), secondary OE off (0), ; T2POL1 = not used (0), reserved(0) ; TF2 is generated by the timer (0), TF2L is generated by timer (0), ; TCC2 is not used (0), TC2L is not used (0) move T2CNA0, #080h ; 1000,0000 -- ET2 on, interrupt will be generated (1), primary OE off (0), ; T2POL0 is not needed (0), TR2L off, will be set later (0) ; TR2 off, will be set later (0), CPRL2 is not needed (0), ; SS2 is not needed (0), gating disabled (0) move T2H0, #0FCh ; set to reload value to keep first pulse from being extra long move T2RH0, #0FCh ; reload value (0x100 - 0xFC = 4 ticks) move T2CH0, #000h ; move T2V0, #0E0h ; set to reload value to keep first pulse from being extra long move T2R0, #0E0h ; reload value (0x100 - 0xE0 = 32 ticks) move T2C0, #000h ; move ACC, T2CNA0 ; turn on high run and low run (TR2, TR2L) or #018h ; move T2CNA0, ACC
以下是中断处理程序代码的一部分:
IntHandler: move c, T2CNB0.3 jump nc, No8KHz ; code for 8KHz interrupt here move T2CNB0.3, #0 No8KHz: move c, T2CNB0.2 jump nc, No1KHz ; code for 1KHz interrupt here move T2CNB0.2, #0 No1KHz: ; other interrupt code here reti
捕获示例 - 对输入波形进行计时
此示例对输入信号进行计时。此代码使用第二个定时器(它们编号为 0、1 和 2),并设置为对高脉冲的持续时间进行计时。在看到上升沿之前,它不会开始计时。CPRL2位可在捕获时重新加载,因此后续脉冲也可以定时。T2POL [0] 和 SS2 位在此模式下的含义略有不同。SS2位(单次)用于禁止计数,直到检测到起始边沿。这使得定时器可以随时设置,即使输入当前为高电平,因为定时器直到下一个上升沿才会启动。T2POL [0] 位选择门控电平,而不是前面示例中的输出极性。门控电平为 0 可防止计数器在输入为低电平时运行。此示例适用于更长的脉冲,并将系统时钟除以 128。系统时钟频率为 4.9152 MHz,定时器的分辨率约为 26 微秒,溢出前可计数至 1.7 秒。
以下代码设置捕获。
; set up Int handler move IV, #IntHandler ; Set interrupt vector. move IC.0, #1 ; Enable global interrupts. move IMR.4, #1 ; Enable interrupts for module 3. ; timer 0 is in module 3, timer 1 & 2 are in module 4 ; repeated capture of high pulse move T2CFG1, #074h ; ; 0111,0100 -- use system clock (0), divide by 128 (111), ; 16 bit mode (0), capture on falling edge (10), c/t2=timer (0) move T2CNA1, #08Fh ; ; 1000,1111 -- ET2 on, interrupt will be generated (1), primary OE off (0), ; T2POL0 (gating) at low (0), TR2L off, will be set later (0) ; TR2 on (1), CPRL2 (reload on capture) is on (1), ; SS2 on (1), gating enabled (1) move T2CNB1, #000h ; 0000,0000 -- ET2L off, low interrupt not used (0), secondary OE off (0), ; T2POL1 = not used (0), reserved(0) ; TF2 is generated by the timer (0), TF2L is not used (0), ; TCC2 is not used (0), TC2L is not used (0)
以下是中断处理程序代码的一部分:
IntHandler: ; looking for Timer2 interrupt... move c, T2CNB1.1 ; capture/reload flag jump nc, NoCapture move T2CNB1.1, #0 ; put code for capture event here move ACC, T2C1 ; capture value now in ACC NoCapture: move c, T2CNB1.3 ; overflow flag jump nc, NoOverflow move T2CNB1.3, #0 ; ; put code to deal with overflow here ; pulse was too long to measure with current clock speed and divisor ; can add 65536 to a 32-bit value to keep counting NoOverflow: ; put other interrupt code here reti
计数器示例 - 使用中断和输出波形
计算传入转换 以下示例对初级引脚上的输入脉冲进行计数,并在每八个脉冲后生成一个中断。它还控制次级引脚上的输出波形,该波形每 8 个输入脉冲切换一次。
; This code sets up the timer and should be run once ; set up Int handler move IV, #IntHandler ; Set interrupt vector. move IC.0, #1 ; Enable global interrupts. move IMR.3, #1 ; Enable interrupts for module 3. ; timer 0 is in module 3 move T2V0, #0FFF8h ; set to reload value move T2R0, #0FFF8h ; reload value 0x10000 - 0x0ffff = 8 ticks move T2C0, #00000h ; move T2CFG0, #003h ; ; 0000,0011 -- use system clock (0), divide by 1 (000), ; 16-bit mode (0), rising edge (01), c/t2=counter (1) move T2CNB0, #060h ; 0110,0000 -- ET2L not used (0), secondary OE on (1), ; T2POL1 start at high (1), reserved(0) ; TF2 is generated by the timer (0), TF2L is not used (0), ; TCC2 is generated by the timer (0), TC2L is not used (0) move T2CNA0, #088h ; 1000,1000 -- ET2 on, interrupt will be generated (1), primary OE not used (0), ; T2POL0 is not used (0), TR2L is not needed(0) ; TR2 on (1), CPRL2 is not needed (0), ; SS2 is not needed (0), gating disabled (0)
以下是中断处理程序的一部分
IntHandler: move c, T2CNB0.3 jump nc, NoTimer move T2CNB0.3, #0 ; service interrupt ; put code for every 8 pulses here NoTimer: ; other interrupt code here reti
要避免的一些常见陷阱
在比较模式下,如果比较值和重载值相等,则在重载发生一个时钟周期后,输出上会发生第二次转换。虽然当您想要一个时钟周期的脉冲宽度时,这是一个有效的选项,但很容易让这种情况发生而没有打算,因为它们都默认为相同的值 0。如果不要使用比较值,则应将其设置在计时器使用的范围之外。通常,将比较值设置为小于重新加载值的值将执行此操作。如果无法做到这一点(由于使用重新加载值 0),则比较值应设置为 <> 位模式下的 FFFFh 或 <> 位模式下的 FFh。这会导致比较和溢出事件发生在同一计时器时钟周期上,从而阻止输出的第二次转换。
输出使能应在运行使能之前或同时打开。在输出使能之前设置运行使能可能会导致输出反转,因为在计时器设置为运行和断言输出使能之间,中断可能会导致代码挂起(在中断提供服务时)。这可能导致在使能输出之前发生比较或溢出事件,从而导致输出具有相反的极性。这通常发生在B或次级输出上,因为输出使能(T2OE1)位于T2CNB寄存器中,而运行位(TR2)和低运行位(TR2L)位于T2CNA寄存器中。在这种情况下,应首先设置 T2CNB 寄存器,或者应设置 T2CNA 寄存器,将运行位设置为零,然后在配置所有寄存器后设置运行位。
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !