CC2530的定时/计数器原理与应用
Posted 364.99°
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CC2530的定时/计数器原理与应用相关的知识,希望对你有一定的参考价值。
目录
1.定时计数器的基本原理
定时/计数器: 一种能够对内部时钟信号或外部输入信号进行计数,当计数值达到设定要求时,向CPU提出中断请求,从而实现定时或者计数功能的外设
定时器/计数器最基本的原理: 进行计数,两者本质上都是计数器,可以进行加/减1计数,每出现一个计数信号,计数器就会自动加/减1,当计数值从0变成最大值/从最大值变成0溢出时,定时/计数器就会向CPU提出中断请求
2.CC2530的定时/计数器
CC2530共有6个定时/计数器(4个通用 + 2个特殊功能)
-
定时器1: 16位定时器,功能最全,应优先选用
支持输入捕获、输出比较、PWM输出、触发DMA
5个独立的捕获/比较通道
具有三种工作模式:自由运行模式、模模式、正计数/倒计数模式 -
定时器2: 16位定时器,用于CSMA-CA提供定时
-
定时器3、定时器4: 8位定时器
支持输入捕获、输出比较
2个独立的捕获/比较通道(对应2个I/O引脚)
具有四种工作模式:自由运行模式、倒计数、模模式、正计数/倒计数模式 -
睡眠定时器: 24位正计数定时器,运行在32KHz的时钟频率,主要用于系统进入或退出低功耗睡眠模式之间的周期定时
-
看门狗定时器: 15位计数器,频率由32KHz时钟源规定(不使用看门狗功能时,可作为通用的定时器)
2.1.定时器1的工作原理
16位的定时器,其计数器的工作是在每个活动时钟边沿递增或递减
- 支持输入捕获、输出比较、PWM输出、触发DMA
- 5个独立的捕获/比较通道,对应5个I/O引脚
- 通过2个8位的寄存器读取定时器1的16位计数器值:T1CNTH、T1CNTL
当读取T1CNTL时,计数器的高位字节就会缓冲到T1CNTH,所以必须先读取T1CNTL - 具有三种工作模式:自由运行模式、模模式、正计数/倒计数模式
2.2.定时器1的三种工作模式
- 自由运行模式
工作方式: 计数器从0x0000开始,在每个活动时钟边沿增加1,当计数器达到0xFFFF时溢出,计数器重新进入0x0000并开始新一轮的递增计数
计数周期: 固定为0xFFFF,当计数值达到0xFFFF时,标志位T1IF和OVFIF被设置,可产生独立的时间间隔,输出信号频率
- 模模式
工作方式: 从0x0000开始,在每个活动时钟边沿增加1,当计数器达到T1CC0寄存器保存的置时溢出,计数器又从0x0000开始新一轮的递增计数
计数周期: 可以由用户自定义设置
- 正计数/倒计数模式
工作方式: 计数器反复从0x0000开始,正计数到TICC0保存的最终计数值,然后再倒计数回0x0000,当达到最终计数值时,标志位T1IF和OVFIF被设置,可用于中心对齐的PWM信号输出
3.CC2530的定时/计数器中断系统
定时器产生中断请求的三种情况:
- 计数器达到最终计数值(溢出或回到0)
- 输入捕获事件
- 输出比较事件(模模式时使用)
注意: 使用模模式,需要开启通道0的输出比较模式,否则计数器的值达到T1CC0后,不会产生溢出中断
CC2530中定时器1~定时器4的中断使能位分别是IEN1寄存器中的T1IE、T2IE、T3IE、T4IE
CC2530中定时器1~定时器4分别有一个计数溢出中断屏蔽位:TxOVFIM(可位寻址)。一般不需要对TxOVFIM进行置1操作,因为上电复位时其初始值就是1
3.1.定时器1的最大计数值和计算与设置
最大计数值 = 定时时长 / 定时器计数周期
当系统时钟为16MHz,分频系数为128,要定时0.1s,最大计数值是多少?在程序设计上如何设置?
- 最大计数值 = 定时时长 / 定时器计数周期 = 0.1s / ((1/16M) * 128) = 12500 = 0x30D4
T1CC0L = 0xD4
;//先写低8位寄存器T1CC0H = 0x30
; //再写高8位寄存器
T1CTL定时器1控制寄存器
注意: 一旦设置了定时器1的工作方式,该定时器就立刻开始定时计数工作,一般放在初始化最后一行
T1CCTLx定时器1通道x捕获/比较控制寄存器
注意: 使用模模式,需要开启通道0的输出比较模式
定时器1通道0的输出比较功能通过T1CCTL0寄存器来设置
T1STAT定时器1状态寄存器
3.2.定时器1初始化函数设计
- 将定时器1的最大计数值写入T1CC0
- 通过T1CCTL0寄存器开启定时器1通道0的输出比较模式
- 设置定时器1的相关中断控制位
- 设置分频系数和工作模式并启动定时器
3.3.定时器中断服务函数设计
- 清除T1STAT的中断标志位
- 累加全局变量count
- count被10整除,即1s的定时到了
- 10s定时到,将count清零
4.案例1:应用定时器1的模模式实现1s定时
要求: 将内部系统时钟16MHz的RC振荡器128分频作为定时器1的计数信号,在模模式中实现0. 1秒定时。在定时中断服务函数中对全局变量count进行累加,实现1秒定时,并将LED5作为秒闪灯,而10秒后LED6亮,再10秒后LED6灭… 如此往复
设计思路:
- 计算最大计数值,并填入T1CC0H和T1CC0L
- 使用模模式,记得开启通道0的输出比较模式
- 使能定时器1相关的中断控制位
- 在T1CTL寄存器设置分频系数,启动定时器
- 编写定时器1中断服务处理函数,在这里记得,手工清除T1STAT寄存器中的中断标志位
- 定义一个全局变量count,进行1秒定时
#include "ioCC2530.h"
#define LED5 P1_3
#define LED6 P1_4
/*========================定时器1初始化函数=======================*/
void Init_Timer1(){
//设置最大计数值
T1CC0L = 0xd4;//低8位
T1CC0H = 0x30;//高8位
//开启通道0的比较模式
T1CCTL0 |= 0x04;
//使能定时器1的中断
T1IE = 1;
//T1OVFIM = 1;定时器1溢出中断,因为复位置1,可不设置
//使能总中断
EA = 1;
//设置定时器1的分配系数和工作模式
T1CTL = 0x0e;//分频系数是128模模式
}
unsigned char count = 0;
/*==========================定时器1服务函数=======================*/
#pragma vector = T1_VECTOR
__interrupt void Timer1_Sevice(){
//清除定时器1通道0中断标志
T1STAT &= ~0x01;
count ++;
//定时1s到
if (count % 10 == 0){
LED5 = ~LED5;
}
//定时10s到
if (count == 100){
LED6 = ~LED6;
count = 0;
}
}
/*==========================端口初始化函数=======================*/
void Init_Port(){
//将P1_3和P1_4设置为通用I/O口
P1SEL &= ~0x18;
//将P1_3和P1_4的端口设置为输出
P1DIR |= 0x18;
LED5 = 0;
LED6 = 0;
}
/*==========================主函数==============================*/
void main(){
Init_Port();
Init_Timer1();
while(1);
}
5.案例2:应用定时器1的模模式实现秒闪灯
要求:
- 选择内部16MHz时钟的128分频作为计数器1的计数信号
- 在定时器1的模模式中实现0.1s的间隔定时
- 在中断服务函数中,实现1s的间隔定时,并反转D4灯的开关状态,以实现灯秒闪的功能,即D4灯亮1s,灭1s…实现3s的间隔定时,并翻转D6的开关状态,即D6灯亮3s,灭3s…
#include "ioCC2530.h"
#define D3 P1_0
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4
//长定时累计变量
unsigned char count = 0;
/*=========================端口初始化函数===================================*/
void Init_Port(){
//初始化LED灯的I/O端口
P1SEL &= ~0x1b;//将P1_0、P1_1、P1_3和P1_4设为通用I/O
P1DIR |= 0x1b;//将P1_0、P1_1、P1_3和P1_4设为输出
//关闭所有LED灯
P1 &= ~0x1b;
}
/*=========================定时器1初始化函数=================================*/
void Init_Timer1(){
//设置最大计数值
T1CC0L = 0xd4; //16MHz时 钟128分频定时100ms
T1CC0H = 0x30; //设 先填低8位,再填高8位
//开启通道0的比较模式
T1CCTL0 |= 0x04;
//使能定时器1中断
T1IE = 1;
//使能总中断打开
EA= 1;
//设置定时器1的分频系数和T作模式
T1CTL = 0x0e;//分频系数是128,模模式
}
/*=========================定时器1中断服务函数===============================*/
#pragma vector = T1_VECTOR
__interrupt void Timer1_Sevice(){
//清除定时器1通道0中断标志
T1STAT &= ~0x01;
//累加定时周期
count++;
//定时1s时间到
if ((count % 10) == 0){
D4 = ~D4;
}
//定时3s到
if ((count % 10) == 30){
D6 = ~D6;
count = 0;
}
}
/*======================================主函数===============================*/
void main(){
//端口初始化
Init_Port();
//定时器1初始化
Init_Timer1();
while(1);
}
以上是关于CC2530的定时/计数器原理与应用的主要内容,如果未能解决你的问题,请参考以下文章