目录
一、TIM模块概述
1.定时器/计数器的特点
- 可以有多种工作方式——定时方法或技术方式
- 计数器的模值可变——技术的最大值有一定的限制,取决于计数器的位数。计数的最大值限制了定时的最大值
- 可以根据的规定的定时或计数值,当到达定时时间或到达计数终点时,发出中断请求信号,以便实现定时或计数控制
定时器——计数脉冲来自于系统工作时钟或经过分频后的系统时钟,即驱动脉冲内为部时钟信号
- 计数器——计数脉冲来自于芯片外部引脚,即驱动脉冲为外部时钟信号
2.嵌入式系统中定时器/计数器模块的作用
- 产生波形输出
从MCU的I/O引脚向外输出一系列符合一定时序规范的周期信号。
- 测量输入波形
从MCU的I/O引脚上检测外部输入的一系列周期信号的脉宽、周期或频率。
- 统计脉冲或边沿个数
对端口引脚输入的、由外部事件产生的触发信号进行计数。
- 作为定时基准
产生内部定时,例如用于定时采样等
- MC9S12系列定时器模块称为TIM(Timer Module)
二、TIM模块结构和工作原理
1.TIM结构模块
1.1 TIM组成
- 1个16位自由运行计数器
- 8个16位输入捕捉/输出比较通道
- 1个16位脉冲累加器
1.2 特点
- 模块时钟输入具有7位预分频器
- 8个输入捕捉通道带有边沿检测器
- 8个输出比较通道的输出极性可选择
- 16位脉冲累加器带有边沿检测器
2.TIM模块工作原理
2.1 工作模式
- 停止模式(STOP)
- 冻结模式(Freeze)
- 等待模式(Wait)
- 正常模式(Normal)
2.2 定时器模块框图
2.3 详细功能框图
自由运行计数器
- TIM的核心——16位自由运行计数器,也称为自由运行主定时器。
- 系统复位时——自由运行计数器为$0000。
- 模块运行时——自由运行计数器从$0000~$FFFF循环递增计数。
- 溢出复零时——置位中断标志。
- 时钟源TIMCLK—— PCLK,PACLK,PACLK/256,PACLK/65536。
- 预分频器时钟PCLK——由总线时钟经过一个7位预分频器得到。
- 预分频系数—— 8种
输入捕捉
输入捕捉(Input Capture,IC):通过捕获自由运行计数器的计数值来检测外部事件和记录选定的输入信号跳变边沿的时间。
当外部事件发生或信号发生变化时,指定的输入捕捉通道对应的引脚上产生一个规定的跳变沿(上升沿或下降沿)。定时器输入通道根据相应引脚上的电平变化,将当前自由运行计数器中的计数值捕捉到通道寄存器中。
如果此时允许输入捕捉中断,则产生一次输入捕捉中断申请,利用中断服务程序可读取通道计数器数值,获得事件发生的时刻或信号变化的时刻
输入比较
输出比较(Output Compare,OC):输出比较功能利用编程实现特定时刻输出需要的电平,实现对外部电路的控制。
用户根据需要设置输出比较寄存器值,自由运行计数器值与输出比较寄存器值每隔4个总线周期比较一次,当两者相等时,会在相应通道引脚上输出预先设定的电平。
如果允许输出比较中断,则产生一次中断申请。
脉冲累加器
脉冲累加器(Pulse accumulator,PA):通过检测相应引脚上的有效边沿统计脉冲个数。TIM模块只有一个16位的脉冲累加器,与PT7引脚复用,其工作方式有事件计数方式和门控时间累加方式两种。
【计数方式】 工作方式不同,脉冲累加器的计数脉冲的来源不同。
★ 事件计数方式——计数脉冲来自输入引脚,脉冲累加器相当于普通计数器,即对有效边沿计数,有效边沿可设定为上升沿或下降沿。输入引脚上每产生一个有效边沿跳变,脉冲累加计数器的值加1。
当脉冲累加器溢出时,将置位中断标志。如果允许脉冲累加器溢出中断,则产生一次中断申请。
★ 门控时间累加方式——门控信号来自输入引脚,时钟信号来自内部时钟PACLK,即总线时钟的64分频(ECLK/64),门控信号可设定为高电平有效或低电平有效。在有效电平期间,脉冲累加器对PACLK时钟信号进行计数。此时,脉冲累加器相当于可控计数器,可用来测量脉冲宽度。
门控时间累加方式下,输入引脚上的有效电平将触发脉冲累加器开始对ECLK/64时钟进行计数,输入引脚上有效电平结束时的跳变沿将停止计数,同时置位中断标志。如果允许脉冲累加器中断,则产生一次中断申请。
3.TIM模块寄存器
- TIM模块共有48个寄存器,其中9个是系统保留寄存器。
- TIM模块的内存映射表给出了这些寄存器的地址、名称和访问权限。
- 对于每个寄存器,所列的地址是地址偏移量,每个寄存器的绝对地址是TIM模块的基本地址与每个寄存器地址偏移量之和。
- TIM模块的基本地址是0x0040。
- TIM模块的寄存器分为3类:控制寄存器、数据寄存器和状态寄存器
-
【控制寄存器】
-
【数据寄存器】
-
【状态寄存器】
4.TIM模块中断系统
【ECT模块中断源】
TIM模块共有11个中断源:
- 1个自由运行定时器溢出中断
- 8个定时器通道中断
- 1个脉冲累加器输入中断
- 1个脉冲累加器溢出中断
TIM模块只检测中断并产生中断请求,不会对中断请求进行处理,用户根据需要自行编写中断服务程序处理相应的中断事件。
默认中断优先级次序:从上到下优先级为从高到低。
写入HPRIO中的代码值实际上是中断矢量起始地址的低字节。
三、TIM模块的自由运行计数器和定时器基本寄存器设置
1.自由运行主定时器与时钟频率设置
16位自由运行主定时器的工作频率决定输入捕捉/输出比较的分辨能力。
定时器计数寄存器TCNT对多路转换器输出的时钟信号进行计数,当计数值从$FFFF溢出变为$0000时,主定时器中断标志寄存器TFLG2中的中断标志TOF置位,如果此时定时器系统控制寄存器TSCR2中的中断允许位TOI=1,将向CPU申请中断。
设置TOI=0将禁止自由运行计数器溢出中断,向TFLG2中写入$80将清除TOF标志。
自由运行主定时器的时钟TIMCLK由4选1多路转换器提供,时钟源的切换由16位脉冲累加器控制寄存器 PACTL中的CLK1和CLK0确定,时钟可以是PCLK、PACLK、PACLK/256、PACLK/65536。
其中,PCLK称为P时钟,由自由运行计数器预分频器将总线时钟进行2k 分频后得到(k=0~7) ,分频系数由定时器系统控制寄存器TSCR2中的PR2、PR1和PR0三位确定(此时,要求定时器系统控制寄存器TSCR1中的PRNT=0,即定时器为普通定时器)。
PACLK是16位脉冲累加器的时钟,频率为ECLK/64。
为了提高定时器性能,TIM模块增加一个精确定时器分频因子选择寄存器PTPSR,通过定时器系统控制寄存器TSCR1中的PRNT位选择是否使用PTPSR寄存器。当TSCR1寄存器中的PRNT=1(定时器为精确定时器)时,PTPSR寄存器的8位可以对主定时器的预分频值进行附加设置,用来扩大定时范围。
定时器系统控制寄存器TSCR1中的TEN位是TIMCLK时钟的总开关。
当TEN=0时,自由运行主定时器的时钟被关断,定时器停止工作,但并不影响脉冲累加器在事件计数方式下的正常工作。
输出比较通道7(OC7)对自由运行主定时器具有特殊的控制功能。
当定时器系统控制寄存器TSCR2中的控制位TCRE=1时,如果OC7比较成功,则定时器计数寄存器TCNT自动复位到$0000。这样可利用OC7实现TCNT在$0000~$xxxx(
2.TIM模块基本寄存器及设置
2.1 TIM模块的基本寄存器
定时器系统控制寄存器TSCR1和TSCR2——用于确定定时器是否工作,设置自由运行计数器预分频器的分频因子、是否允许定时器溢出中断、是否允许通过通道7输出比较事件复位定时器计数寄存器TCNT。
定时器计数寄存器TCNT——自由运行主定时器的数据寄存器,用来对TIMCLK时钟计数。
主定时器中断标志寄存器TFLOG2——表示主定时器是否产生溢出。
1. 定时器系统控制寄存器1 (Timer System Control Register 1,TSCR1)
【作用】用于确定定时器是否启动和等待、冻结模式下的行为、标志清除方式等。
TEN:定时器使能位
1 = 允许定时器正常运行。
0 = 禁止主定时器(包括计数器),可用于降低功耗。
TEN控制着定时器的时钟,要使用TIM模块的输入捕捉/输出比较功能,必须将TEN置位。如果由于任何原因导致定时器未被激活,则脉冲累加器没有ECLK/64时钟,因为ECLK/64时钟由定时器预分频器产生,此时脉冲累加器将不能工作于门控时间累加方式。
TSWAI:等待模式下TIM模块停止位
1 = 当MCU处于等待模式时,禁止定时器模块。定时器中断不能使MCU退出等待模式。
0 = 在等待期间允许TIM模块继续运行。
TSWAI还影响脉冲累加器。
TSFRZ:冻结模式下定时器和模数计数器停止位
1 = 只要MCU处于冻结模式,禁止定时器和模数计数器。
0 = 冻结模式下允许定时器和模数计数器继续运行。
TFFCA :快速清除定时器所有标志位
1 = 定时器标志快速清除方式。
对于TFLG1寄存器,读输入捕捉或写输出比较通道($10–$1F)将清除相应通道的标志CnF。
对于TFLG2寄存器,对TCNT寄存器的任何访问将清除TOF标志。
对PACNT寄存器的任何访问将清除PAFLG寄存器中的PAOVF和PAIF标志。
【优点】不需要单独的清零操作,节省了软件的额外开销。需要特别注意的是,防止由于无意的访问导致标志被意外清除。
0 = 定时器标志正常清除方式。允许清除定时器标志,使其正常运行
PRNT:精确定时器设置位
0 = 使能普通定时器。TCSR2寄存器的PR0、PR1和PR2位用于计数器的分频因子选择。
1 = 使能精确定时器。PTPSR寄存器的所有位被用于精确定时器的分频因子选择。
复位后该位只能写一次。
2. 定时器系统控制寄存器2 (Timer System Control Register 2,TSCR2)
【作用】用来设置TIM模块自由运行计数器预分频器的分频因子、是否允许定时器溢出中断、是否允许通过通道7输出比较事件复位定时器计数寄存器TCNT。
TOI:定时器溢出中断允许位
1 = 允许定时器溢出中断,当TOF标志置位时,允许请求硬件中断。
0 = 禁止定时器溢出中断。
TCRE:定时器计数器复位允许
该位用来设置是否允许通过成功的输出比较7事件复位定时器/计数器。这种工作模式类似于递增计数模数计数器。
1 = 通过成功的输出比较7复位自由运行计数器。
0 = 禁止计数器复位,计数器自由运行。
如果TC7 = $0000且TCRE = 1,TCNT一直保持$0000。
如果TC7 = $FFFF且TCRE = 1,当TCNT从$FFFF复位到$0000时,TOF将不会置位。
【注意】如果TCRE=1且TC7≠0,TCNT的循环周期将是TC7预分频计数器宽度+1个总线时钟。
PR2、PR1、PR0:定时器预分频器选择位
当PSCR1中PRNT=0时,这3位规定了插入在总线时钟与主定时器计数器之间2分频的级数。
3.精确定时器预分频因子选择寄存器(Precision Timer Prescaler Select Register,PTPSR)
PTPS[7:0]:精确定时器预分频选择位。
这8位规定了主定时器预分频器的分频比率。只有当TSCR1寄存器中PRNT=1时,该寄存器才有效。
预分频因子可跟据PTPS[7:0]的值和PRNT位状态,计算公式:预分频因子=PTPS[7:0]+1
4. 定时器计数寄存器(Timer Count Register,TCNT)
16位主定时器是一个递增计数器,不停地对时钟信号TIMCLK进行计数,定时器计数寄存器TCNT的内容即为计数结果。
TCNT寄存器值的访问要求在一个时钟周期内完成,且应该按字访问,分别读/写操作高字节寄存器和低字节寄存器可能会产生不同的结果。
5. 主定时器中断标志寄存器2(Main Timer Interrupt Flag 2,TFLG2)
TFLG2寄存器只有一个标志位TOF,表示何时出现自由运行定时器的溢出中断条件。
当TSCR1寄存器中的TEN=1或PACTL寄存器中的PAEN=1时,TFLG2寄存器的第7位写“1”操作将清零,写“0”操作无效。
TOF:主定时器溢出标志
当16位自由运行定时器从$FFFF溢出变为$0000时,该位置1。向该位写1将清除TOF标志。
TOF =1时,如果允许溢出中断(TSCR2寄存器中TOI=1),则将引发中断。在禁止中断的情况下,也可以通过软件查询该标志来进行相应的处理。
如果TSCR1寄存器中的TFFCA=1,对TCNT的任何访问将清零TFLG2寄存器。
如果TC7=$FFFF且TSCR1寄存器中的TCRE = 1,当TCNT从$FFFF溢出复零时,TOF将不会置位。
四、TIM模块的输入捕捉功能及寄存器设置
五、TIM模块的输出比较功能及寄存器设置
六、TIM模块脉冲累计器功能及寄存器设置
七、TIM模块模块实例
当发生溢出时,点亮小灯
TIM模块输出比较功能应用实例
功能描述:设定输出比较寄存器每隔0.125s发生一次比较,并在4次比较后改变P口输出电平状态
结果观察:P口驱动的小灯每秒一次的频率闪烁
#include <hidef.h> /* common defines and macros */ #include "derivative.h" /* derivative-specific definitions */ /*************************************************************/ /* 初始化锁相环 */ /* 使用外部晶振:8MHz */ /* 设置总线频率:16MHz */ /*************************************************************/ void PLL_init(void) { CPMUPROT = 0x26; CPMUOSC_OSCE = 1; while(!CPMUOSC_OSCPINS_EN); while (CPMUFLG_UPOSC); CPMUCLKS_PLLSEL = 1; CPMUSYNR = 0x01; // 配置fpll=32MHZ,fbus=16MHZ CPMUREFDIV = 0x81; CPMUPOSTDIV = 0x00; CPMUPLL = 0x10; while(!CPMUFLG_LOCK); CPMUPROT = 0x01; /** * @brief 初始化TIM * @note * @retval None */ void TIM_init(void) { TSCR1_TEN = 1; // 定时器系统控制寄存器_定时器使能位 TSCR1_TFFCA = 1; // 定时器系统控制寄存器_定时器标志位快速清楚 TIOS = 0xFF;//所有通道设置位输出比较 TSCR2 = 0x06;// 预分频系数pr2-pr0:110,预分频系数为64,定时器时钟周期为4us(0.25us?) TIE = 0x00; // 禁止所有通道定时中断 TCTL1 = 0x00;// 后四个通道设置为定时器与输出引脚断开,即禁止比较 TCTL2 = 0x00;// 前四个通道设置为定时器与输出引脚断开,即禁止比较 TFLG1 = 0xFF;// 清除各IC/OC中断标志位 TFLG2 = 0xFF;// 清除自由定时器中断标志位 } void main(void) { /* put your own code here */ PLL_init(); TIM_init(); DDRP = 0xFF; PTP_PTP6 = 0; EnableInterrupts; for(;;) { TFLG1_C0F = 1;//清除标志位 TC0 = TCNT+31250;//设置输出比较时间=4us*31250=0.125s while (TFLG1_C0F == 0); TFLG1_C0F = 1; TC0 = TCNT+31250; while(TFLG1_C0F == 0); TFLG1_C0F = 1; TC0 = TCNT+31250; while (TFLG1_C0F == 0); TFLG1_C0F = 1; TC0 = TCNT+31250; while(TFLG1_C0F == 0); PTP_PTP6 = ~PTP_PTP6;//每隔0.5s改变led的状态,即1s闪烁一次 } for (;;) { _FEED_COP(); /* feeds the dog */ } /* loop forever */ /* please make sure that you never leave main */ }