且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

更新时间:2021-10-17 23:35:15


 

 

1、定时器1概述

  定时器1 是一个支持典型的定时/计数功能的独立16 位定时器,支持输入捕获,输出比较和PWM等功能。定时器有五个独立的捕获/比较通道。每个通道定时器要使用一个I/O 引脚。定时器用于范围广泛的控制和测量应用,可用的五个通道的正计数/倒计数模式将允许诸如电机控制应用的实现。


定时器1 的功能如下:

• 五个捕获/比较通道
• 上升沿、下降沿或任何边沿的输入捕获
• 设置、清除或切换输出比较
• ***运行、模或正计数/倒计数操作
• 可被1,8,32 或128 整除的时钟分频器
• 在每个捕获/比较和最终计数上生成中断请求
•  DMA 触发功能

 

2、16 位计数器

  【关于分频,时钟】定时器包括一个16 位计数器,在每个活动时钟边沿递增或递减。活动时钟边沿周期由寄存器位CLKCON.TICKSPD定义,它设置全球系统时钟的划分,提供了从0.25MHz 到32MHz 的不同的时钟标签频率(可以使用32 MHz XOSC 作为时钟源)。这在定时器1 中由T1CTL.DIV设置的分频器值进一步划分。这个分频器值可以从1、8、32 或128。因此当32 MHz 晶振用作系统时钟源时,定时器1 可以使用的最低时钟频率是1953.125Hz,最高是32 MHz。当16MHz RC 振荡器用作系统时钟源时,定时器1 可以使用的最高时钟频率是16MHz。

  【读取定时器当前值】计数器可以作为一个***运行计数器,一个模计数器或一个正计数/倒计数器运行,用于中心对齐的PWM。可以通过两个8 位的SFR 读取16 位的计数器值:T1CNTH 和T1CNTL,分别包含在高位字节和低位字节中。当读取T1CNTL 时,计数器的高位字节在那时被缓冲到T1CNTH,以便高位字节可以从T1CNTH 中读出因此!!!T1CNTL 必须总是在读取T1CNTH 之前首先读取。对T1CNTL 寄存器的所有写入访问将复位16 位计数器。当达到最终计数值(溢出)时,计数器产生一个中断请求。

  【控制定时器】可以用T1CTL 控制寄存器设置启动并停止该计数器。当一个不是00 值的写入到T1CTL.MODE 时,计数器开始运行。如果00 写入到T1CTL.MODE,计数器停止在它现在的值上。

 

3、定时器1 操作

  一般来说控制寄存器T1CTL 用于控制定时器操作。状态寄存器T1STAT 保存中断标志。各种操作模式如下所述。

 

4、***运行模式

  在***运行操作模式下,计数器从0x0000 开始,每个活动时钟边沿增加1。当计数器达到0xFFFF(溢出),计数器载入0x0000,继续递增它的值,如图1 所示。当达到最终计数值0xFFFF,设置标志IRCON.T1IF 和T1STAT.OVFIF。如果设置了相应的中断屏蔽位TIMIF.OVFIM 以及IEN1.T1EN,将产生一个中断请求。***运行模式可以用于产生独立的时间间隔,输出信号频率。(0xFFFF型)

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

               图1 ***运行模式

 

5、模模式

  当定时器运行在模模式,16 位计数器从0x0000 开始,每个活动时钟边沿增加1。当计数器达到T1CC0(溢出),寄存器T1CC0H:T1CC0L 保存的最终计数值,计数器将复位到0x0000,并继续递增。如果定时器开始于T1CC0 以上的一个值,当达到最终计数值(0xFFFF)时,设置标志IRCON.T1IF 和T1CTL.OVFIF。如果设置了相应的中断屏蔽位TIMIF.OVFIM 以及IEN1.T1EN,将产生一个中断请求。模模式可以用于周期不是0xFFFF的应用程序。计数器的操作展示在图2 中。(自定义上限型)

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

              图2 模模式

 

6、正计数/倒计数模式

  在正计数/倒计数模式,计数器反复从0x0000 开始,正计数直到达到T1CC0H:T1CC0L 保存的值。然后计数器将倒计数直到0x0000,如图3 所示。这个定时器用于周期必须是对称输出脉冲而不是0xFFFF 的应用程序,因此允许中心对齐的PWM 输出应用的实现。在正计数/倒计数模式,当达到最终计数值时,设置标志IRCON.T1IF 和T1CTL.OVFIF。如果设置了相应的中断屏蔽位TIMIF.OVFIM 以及IEN1.T1EN,将产生一个中断请求。(增减交替型)

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

            图3 正计数/倒计数模式

 

7、通道模式控制

  通道模式随着每个通道的控制和状态寄存器T1CCTLn 设置。设置包括输入捕获和输出比较模式。

 

8、 输入捕获模式

  当一个通道配置为输入捕获通道,和该通道相关的I/O 引脚必须被配置为输入。(什么是输入捕获模式,运作机制)在启动定时器之后,输入引脚的一个上升沿、下降沿或任何边沿都将触发一个捕获,即把16 位计数器内容捕获到相关的捕获寄存器中。因此定时器可以捕获一个外部事件发生的时间。(捕获外部事件发生时间)

   注意:在定时器可以使用一个输入/输出引脚之前,所需的I/O 引脚必须配置为定时器1 的外设引脚。通道输入引脚和内部系统时钟是同步的。因此输入引脚上的脉冲的最低持续时间必须大于系统时钟周期。

  16 位捕获寄存器的内容从寄存器T1CCnH:T1CCnL 中读出。当捕获发生时,要设置IRCON.T1IF 标志和该通道的中断标志T1STAT.CHnIF(n 是通道号码)。如果分别设置了相应的中断屏蔽位T1CCTLn.IM,以及IEN1.T1EN,将产生一个中断请求。

 

9、输出比较模式最难理解的一个,下面的边沿对其和中心对其其实是基于输出比较的运作核心,用上面讲的几种简单的模式实现PWM,中心对齐是利用模模模式实现的

  在输出比较模式中,与通道相关的IO要设置为输出模式。(什么是输出比较模式,运作机制)在定时器启动后, 计数器的内容会和通道比较寄存器中的内容T1CCnH:T1CCnL做比较。如果这两个内容(值)相等,输出引脚根据比较输出模式T1CCTLn.CMP的设置进行设置、复位或切换。(核心就是将T1CC0的值和每个通道寄存器中的值比较,相等了则产生中断等)

   注意:输出引脚运行在一个给定输出比较模式下时,它上面的所有边沿都是无故障运行的。

  写入比较寄存器T1CCnL 将被缓冲,这样写入到T1CCnL 的值不起作用,直到相应的高位寄存器T1CCnH 被写入。写入比较寄存器T1CCnH:T1CCnL 对于输出比较值不起作用,直到定时器达到0x00。

  注意:通道0 的输出比较模式较少,因为T1CC0H:T1CC0L 在模式6 和7 有一个特殊功能,这意味着这些模式对于通道0 是不能使用的。

  当发生一个比较时,设置IRCON.T1IF 标志和该通道的中断标志T1STAT.CHnIF(n 是通道号码)。如果分别设置了相应的中断屏蔽位T1CCTLn.IM,以及IEN1.T1EN,将产生一个中断请求。

  不同定时器模式下输出比较模式的例子给定在以下图中。

  边沿对齐:PWM 输出信号可以使用定时器在***运行模式下,通道1 和2 在输出比较模式6 或7(第6和第7条线)下生成(由T1CCTLn.CMP 位定义,其中n 是1 或2),如图4 所示。PWM 信号的周期通过设置T1CC0 确定,通道输出的占空比由T1CCn 确定,其中n 是PWM 通道1 或2。也可以使用定时器***运行模式。在这种情况下,T1CTL.DIV 位中的CLKCON.TICKSPD 和分频器值设置PWM 信号的周期。PWM 信号的极性由使用的是输出比较模式6 还是7 确定。PWM 输出信号还可以使用图4 所示的输出比较模式4 和5,或通过使用图5 所示的模模式生成。对于简单的PWM,***使用使用输出比较模式4 和5 来生成。

  [ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

 

               图4 输出比较模式,定时器***运行模式

            图中0、1、2...6是7种模式,左边的波形对应每种模式

 

  [ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

                

               图5 输出比较模式,定时器模模式

 

  中心对齐PWM 输出可以通过选择定时器正计数/倒计数模式生成。根据PWM 信号所需的极性选择通道输出比较模式4 或5(由T1CCTLn.CMP 位定义,其中n 是1 或2)。PWM 信号的周期由T1CC0 确定,通道输出的占空比由T1CCn 确定,其中n 是PWM 通道1 或2。某些类型的电机驱动应用程序会需要中心对齐的PWM 模式,一般地这比边沿对齐的PWM 模式产生的噪音更少,因为I/O 引脚传输不集中在同一个时钟边沿上。

  [ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

              图6  输出比较模式,定时器正计数/倒计数模式

 

  (附加小姿势)在一些类型的应用程序中,需要在输出之间定义一个延迟或死亡的时间。典型地,这用于输出驱动一个H桥配置,以避免H 桥的一边交叉传导失控。延迟或死亡时间可以通过使用T1CCn 在PWM 输出中获得,如下所示:
假定通道1 和通道2 使用定时器正计数/倒计数模式,用于驱动输出,且这两个通道分别使用输出比较模式4 和5,那么定时器周期(定时器1 的时钟周期)是:
tP = T1CC0 x 2
死亡时间,即两个输出都为低电平的时间,(定时器1 的时钟周期)是:
tD = T1CC1 – T1CC2
当下列情况发生,比较输出引脚初始化为表9-1 所列的值:

???? 一个值被写入T1CNTL(所有定时器1 通道)
???? 0x7 被写到T1CCTLn.CMP(通道n)

 

                表9-1 初始的比较输出值(比较模式)

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

10、IR 信号产生和线性化 (*

  本节描述了CC253x 设备只需最少的SW 参与即可产生IR 的功能。


10.1、简介(*

  为远程控制产生IR 信号一般以下面两种方式之一完成:

???? 调制码
???? 非调制码(C 码,闪存代码)

  CC253x 包括灵活的定时器功能,以最少的CPU 参与,来执行这两种类型的IR 信号的产生和线性化。大多数IR 协议每个命令只需一个CPU 干预即可实现。


10.2、调制码(*

  调制码可以使用定时器1(16 位)和定时器3(8 位)生成。处于调制模式的定时器3 用于产生载波。定时器3 有一个单独的分频器,用于它的输入。它的周期使用T3CC0 设置。定时器3 通道1 用于PWM 输出。载波的占空比使用T3CC1 设置。通道1 使用比较模式:“在比较设置输出,在0xFF 清除”(T3CCTL1.CMP = 101)。
表9-2 显示了定时器3 的38kHz 载波的频率误差计算。(用定时器3产生载波)

              38kHz 载波的频率误差计算

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

  

  IRCTL.IRGEN 寄存器位使得IR 产生模式处于定时器1。当设置了IRGEN 位,定时器1采用定时器3通道1的输出比较信号作为标记,而不是采用系统标记。定时器1周期是使用T1CC0 设置的,定时器1处于调制模式(T1CTL.MODE = 10),通道0处于比较模式(T1CCTL0.MODE = 1)。通道1比较模式“在比较设置输出,在0x0000 清除”(T1CCTL1.CMP = 011)用于输出门控信号。

  标记载波的个数由T1CC1. T1CC1 设置,需要每个定时器1 周期由DMA 或CPU 更新一次。注意T1CC1的一个更新被缓冲,在定时器1 达到0x0000 之前不起作用。

  空间载波的个数由T1CC0 设置。其值必须设置为标记和空间载波周期希望的总数。比较值被缓冲直到定时器达到0x0000。

  定时器1 通道1 的输出进行定时器3 通道1 的输出和运算,作为IR 的输出,如图。

 

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

                图7  定时器在IR 产生模式的方框图

  定时器3 通道1 输出和定时器1 通道1 输出信号的时序是同步的,这样在IR 输出信号上就没有故障。当设置了IRGEN 位,IR 输出信号被送到引脚,而不是送到一般的定时器1 通道1 输出。下图显示了定时器3 被初始化为33%的占空比(T3CC0 = 3× T3CC1)的例子。定时器1 已经被初始化为3。(如果仅仅要实现一个空间周期,T1CC1 必须设置为0x00。)

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

                图8  调制的波形示例

 

10.3 非调制码(*

  要产生非调制IR 码,定时器1 要处于模模式。信号的周期由T1CC0 给定,脉冲宽度由T1CC1 给定。T1CC1给出标记周期的长度,T1CC0 给出标记和空间周期的总数。比较值被缓冲,直到定时器达到0x0000。如果比较值不能保持不变,必须在每个周期由DMA 或CPU 更新。

 

10.4 学习(*

  学习通过使用定时器1(16 位)和定时器3(8 位)的捕获功能完成。定时器3 可以处理载波频率检测,定时器1 可以处理调制信代码的学习。电路应该按照图9 所述安装。

 

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

            图9 IR 学习的方框图

 

10.4.1 载波频率检测(*

  定时器3 用于捕获和检测直接从IR 引脚二极管输入的载波频率。定时器必须对载波进行一定次数的采样。如果载波被检测,被检测出的频率必须提供平均数,这会存储在数据库中。


10.4.2 解调码学习(*

  IR 引脚二极管的输出由一个合适的电路解调。这一电路的输出用作处于捕获模式的定时器1 其中一个通道的输入。


10.5 其他注意事项(*

  IR 输出引脚在复位期间必须处于三态或下拉状态,以避免点亮IR LED 这一不必要的功耗。注意只有定时器1 通道1 的输出P1.1 是三态的,在复位期间和复位后没有上拉。

 

11、定时器1 中断

  为定时器分配了一个中断向量。当下列定时器事件之一发生时,将产生一个中断请求:

● 计数器达到最终计数值(溢出或回到零)
● 输入捕获事件
● 输出比较事件

  寄存器状态寄存器T1STAT 包括最终计数值事件和五个通道比较/捕获事件的中断标志。仅当设置了相应的中断屏蔽位和IEN1.T1EN 时,才能产生一个中断请求。中断屏蔽位是n 个通道的T1CCTLn.IM 和溢出事件TIMIF.OVFIM。如果有其它未决中断,必须在一个新的中断请求产生之前,通过软件清除相应的中断标志。而且,如果设置了相应的中断标志,使能一个中断屏蔽位将产生一个新的中断请求。

 

12、定时器1 DMA 触发

  有三种DMA 触发与定时器1 有关。这些是DMA 触发T1_CH0,T1_CH1 和T1_CH2,分别在以下定时器比较事件上产生:

● T1_CH0 – 通道0 比较
● T1_CH1 – 通道1 比较
● T1_CH2 – 通道2 比较

  通道3 和4 没有相关的触发。

 

13、定时器1 寄存器

  本节描述了定时器1 的寄存器,由以下寄存器组成:

● T1CNTH – 定时器1 计数高位
● T1CNTL – 定时器1 计数低位
● T1CTL – 定时器1 控制
● T1STAT –定时器1 状态
● T1CCTLn – 定时器1 通道n 捕获/比较控制
● T1CCnH – 定时器1 通道n 捕获/比较高位值
● T1CCnL – 定时器1 通道n 捕获/比较低位值

  TIMIF.OVFIM 寄存器位驻留在TIMIF 寄存器,和定时器3 和定时器4 寄存器一起描述。

 

14、作为数组访问定时器1 寄存器

  定时器1 捕获/比较通道寄存器可以在XDATA 存储空间中作为一个连续的区域被访问。这使得可以作为一个简单的索引结构方便地访问寄存器。5 个捕获/比较控制寄存器映射到0x62A0 - 0x62A4。16 位捕获/比较值映射到0x62A6 - 0x62AF。0x62A5 不使用。

 

15、代码示例

15.1、定时器轮训方式

  下面代码展示了通过设置定时器1计数来控制LED闪烁,这里没有采用中断方式,而是采用普通的轮训。关于LED的初始化我在前几节已经介绍了。这里重点看和定时器1相关的部分:

  ① 第33行将T1CTL设置为0x0d=0000 1101,参考下面寄存器表可知是通过设置定时器1的控制和状态寄存器来将定时器设置为:128分频,***运行,从0x0000到0xFFFF反复计数。由于系统在没配置工作频率时默认是2分频,即32MHz/2=16MHz,因此定时器每次溢出的时间T=1/(16MHz/128)*65536=0.524s

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

  

  ② 第34行将T1STAT设置为0x21=0010 0001,参考下面的寄存器表知为使用定时器1的通道0,且中断有效。

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

  ③ 在49行一旦IRCON>0表明发生了某个中断,在该例程中我们仅仅用了TIMER1的中断,因此表明TIMER1中断发生:

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

  因此下面整个程序实现的功能是:利用定时器1的通道0产生0.524s的周期性中断,每次发生中断系统会自动置IRCON的第1位为1,在main函数的轮训中一旦检测到该信息,则让计数变量count加1,一旦count计数大于1时,就让LED状态翻转,实现1SLED闪烁控制。

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)
 1 /****************************************************************************
 2 * 文 件 名: main.c
 3 * 版    本: 1.0
 4 * 描    述: 定时器T1通过查询方式控制LED1周期性闪烁
 5 ****************************************************************************/
 6 #include <ioCC2530.h>
 7 
 8 typedef unsigned char uchar;
 9 typedef unsigned int  uint;
10 
11 #define LED1 P1_0       // P1.0口控制LED1
12 
13 /****************************************************************************
14 * 名    称: InitLed()
15 * 功    能: 设置LED灯相应的IO口
16 * 入口参数: 无
17 * 出口参数: 无
18 ****************************************************************************/
19 void InitLed(void)
20 {
21     P1DIR |= 0x01;      //P1.0定义为输出
22     LED1 = 1;           //使LED1灯上电默认为熄灭     
23 }
24 
25 /****************************************************************************
26 * 名    称: InitT1()
27 * 功    能: 定时器初始化,系统不配置工作时钟时默认是2分频,即16MHz
28 * 入口参数: 无
29 * 出口参数: 无
30 ****************************************************************************/
31 void InitT1()
32 {
33     T1CTL = 0x0d;       //128分频,自动重装 0x0000-0xFFFF 
34     T1STAT= 0x21;       //通道0,中断有效   
35 }
36 
37 /****************************************************************************
38 * 程序入口函数
39 ****************************************************************************/
40 void main(void)
41 {
42     uchar count=0;
43     
44     InitLed();             //调用初始化函数
45     InitT1();
46     
47     while(1)
48     {
49         if(IRCON > 0)
50         { 
51             IRCON=0;
52             if(count++ >= 1) //约1s周期性闪烁,示波器测大约为1025MS
53             {
54               count=0;
55               LED1 = !LED1;  //LED1闪烁        
56             }
57         } 
58     }
59 }
[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

15.2、定时器中断方式

  上面采用轮训的方法是比较占资源的,类似我们按键那节中介绍的,除了轮训我们还可以用中断方式!在黄色初始化部分比采用轮训方式多了使能T1中断和总中断的部分(35、36行代码)。我之前没有加这两句代码,结果橙色部分的定时器1中断回调函数无法被触发!查datasheet发现Interrupt Overview:如果想触发回调函数,需要将EA开关和T1IE开关打开才行!

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)

 

[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)
 1 /****************************************************************************
 2 * 文 件 名: main.c
 3 * 版    本: 1.0
 4 * 描    述: 定时器T1通过查询方式控制LED1周期性闪烁
 5 ****************************************************************************/
 6 #include <ioCC2530.h>
 7 
 8 typedef unsigned char uchar;
 9 typedef unsigned int  uint;
10 
11 #define LED1 P1_0       // P1.0口控制LED1
12 
13 /****************************************************************************
14 * 名    称: InitLed()
15 * 功    能: 设置LED灯相应的IO口
16 * 入口参数: 无
17 * 出口参数: 无
18 ****************************************************************************/
19 void InitLed(void)
20 {
21     P1DIR |= 0x01;      //P1.0定义为输出
22     LED1 = 1;           //使LED1灯上电默认为熄灭     
23 }
24 
25 /****************************************************************************
26 * 名    称: InitT1()
27 * 功    能: 定时器初始化,系统不配置工作时钟时默认是2分频,即16MHz
28 * 入口参数: 无
29 * 出口参数: 无
30 ****************************************************************************/
31 void InitT1()
32 {
33     T1CTL = 0x0d;       //128分频,自动重装 0x0000-0xFFFF 
34     T1STAT= 0x21;       //通道0,中断有效  
35     T1IE = 1;                //开总中断和T1中断
36     EA = 1;                  //开总中断
37 }
38 
39 //定时器T1中断处理函数
40 #pragma vector = T1_VECTOR 
41 __interrupt void T1_ISR(void) 
42 { 
43     static uchar count=0;
44     IRCON = 0x00;            //清中断标志, 也可由硬件自动完成 
45     if(count++ >= 1) //约1s周期性闪烁,示波器测大约为1025MS
46     {
47       count=0;
48       LED1 = !LED1;  //LED1闪烁        
49     }
50 }
51 
52 /****************************************************************************
53 * 程序入口函数
54 ****************************************************************************/
55 void main(void)
56 {
57     InitLed();             //调用初始化函数
58     InitT1();
59     
60     while(1){}
61 }