微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 无线和射频 > 射频无线通信设计 > CC2530的定时器使用心得

CC2530的定时器使用心得

时间:10-02 整理:3721RD 点击:

CC2530的定时器使用心得


根据数据手册可知CC2530总共有4个定时器,但是定时器2被系统占用,可用的只有三个,分别为定时器1/3/4
Timer在协议栈的代码位置为hal_timer.c,hal_timer.h,4个定时器的ID分别为
/* Timer ID definitions */
#define HAL_TIMER_0               0x00    // 8bit timer
#define HAL_TIMER_1               0x01    // 16bit Mac timer
#defineHAL_TIMER_2               0x02   // 8bit timer
#define HAL_TIMER_3               0x03    // 16bit timer
#define HAL_TIMER_MAX             4       // Max number of timer
宏定义中的TIMER_ID并非硬件中的定时器1,而是经过函数halTimerRemap映射,将HAL层自定义的timerID映射为硬件的HW TIMER ID
映射的结果为
* @brief  Maps API HAL_TIMER_ID to HW Timer ID.
*         HAL_TIMER_0 --> HW Timer 3 8bit
*         HAL_TIMER_2 --> HW Timer 4 8bit
*         HAL_TIMER_3 --> HW Timer 1 16bit
有两个方法达到定时的目的,一个是协议栈函数,一个直接寄存器操作
协议栈函数使用
        在OSAL的main函数中 HalDriverInit();既有对timer的初始化HalTimerInit();该函数对各个定时器进行了初始化,首先对所有定时器清中断,然后设置时钟和预分频,最后设置定时器的Channel structure.
        如果用户想使用定时器需要自己设置某一个寄存器的变量,并实现相关回调函数,最后调用HalTimerStart来启动定时器.
设置初始化定时器
        函数是uint8HalTimerConfig (uint8 timerId, uint8 opMode, uint8 channel, uint8 channelMode,bool intEnable, halTimerCBack_t cBack)
各个参数的意思
* @param  timerId - Id of the timer
*         opMode - Operation mode操作方式共3种
*         channel - Channel where the counter operates on选择通道,对应IO口
*         channelMode - Mode of that channel通道的模式
*         intEnable -可中断
*         cBack - Pointer to the callback function 中断函数
示例:
HalTimerConfig(HAL_TIMER_0,HAL_TIMER_MODE_CTC,HAL_TIMER_CHANNEL_SINGLE,HAL_TIMER_CH_MODE_OUTPUT_COMPARE,TRUE,timer_callback);
此处的TimerID为HAL_TIMER_0,但是实际上使用的并非这个,而是经过函数halTimerRemap映射,将HAL层自定义的timerID映射为硬件的HW TIMER ID映射的结果为
* @brief  Maps API HAL_TIMER_ID to HW Timer ID.
*         HAL_TIMER_0 --> HW Timer 3 8bit
*         HAL_TIMER_2 --> HW Timer 4 8bit
*         HAL_TIMER_3 --> HW Timer 1 16bit
回调函数(中断服务函数)
        示例中的最后一个参数既是回调函数,回调函数可以决定定时的长短,每中断一次本函数被调用一次,如下代码
/*中断服务函数*/
volatile unsigned int n = 0; //一个volatile的全局变量
//确保本条指令不会因编译器的优化而省略,且要求每次直接读值
void timer_callback(uint8 timerId, uint8 channel, uint8 channelMode)
{
   n++;  //每次调用此函数,n加1
        if(n ==5000) {  //当n加到一个自定义的数值后,就执行相关任务,然后将n清零
                                    //改变这个值即可控制定时的长短
                  /*do something...*/
       HalUARTWrite(0,"20000000000\n",13);  //定时到后执行任务
                  n =0;//重新定时
        }
        /*TODO...*/
   return;
}
启动定时器
        重点函数HalTimerStart(uint8 timerId, uint32 timePerTick),参数定义
* @param  timerId      - ID of the timer
*         timerPerTick - number of micro sec per tick, (ticks x prescale) / clock= usec/tick
第一个是定时器的ID,第二个未理解,但是数值越小,定时器时间间隔越小.
实例:
HalTimerStart (HAL_TIMER_0,65536);
停止定时器
        函数HalTimerStop(uint8 timerId),指定timerID即可停止某一个定时器
实例:HalTimerStop(HAL_TIMER_0)
/*中断服务函数*/
volatile unsigned int n = 0,stop=0;
void timer_callback(uint8 timerId, uint8 channel, uint8 channelMode)
{
        n++;
        if(n == 5000) {
       HalUARTWrite(0,"20000000000\n",13);
       LED1 = ~LED1;
       stop++;
       if(stop == 10)  //将会在led灯闪烁5次之后关闭定时器
           HalTimerStop(HAL_TIMER_0);
                  n =0;
        }
   return;
}
寄存器操作
本段参考网蜂团队的第二章”基础实验”的2.4定时器
分为两种方式:查询模式,中断模式,相比查询模式中断模式更节省cpu资源,效率更高!
查询方式
CC2530的 T1定时器(16位)我们需要配置三个寄存器 T1CTL, T1STAT,IRCON。IO口配置请留意第一节教程内容。各寄存器功能如下表所示:(详细参考 CC2530 datasheet.pdf)
T1CTL(0XE4)Timer1  控制寄存器:
Bit3:Bit2 : 定时器时钟分频倍数选择:
00:不分频 01:8分频 10: 32分频 11:128分频
Bit1:Bit0 :  定时器模式选择:
00: 暂停
01: 自动重装 0X0000-0XFFFF
10: 比较计数 0X0000-T1CC0
11: PWM  方式
T1STAT(0XAF)Timer1  状态寄存器:
Bit5:  OVFIF 定时器溢出中断标志,在计数器达到计数终值时置位 1.
Bit4:   定时器 1  通道 4 中断标志位
Bit3:   定时器 1  通道 3 中断标志位
Bit2:   定时器 1  通道 2 中断标志位
Bit1:   定时器 1  通道 1 中断标志位
Bit0:   定时器 1  通道 0 中断标志位
IRCON(0XC0) 中断标志位寄存器,只要轮询此标志位即可
实现代码
/**************************************
程序描述:通过定时器 T1查询方式控制
LED1周期性闪烁
**************************************/
#include <ioCC2530.h>
#define uint unsigned int
#define uchar unsigned char
//定义控制 LED灯的端口
#define LED1 P1_0     //定义 LED1为 P10口控制
//函数声明
void Delayms(uint xms);   //延时函数
void InitLed(void);       //初始化 P1口
void InitT1();             //初始化定时器 T1
/****************************
//延时函数
*****************************/
void Delayms(uint xms)    //i=xms  即延时 i毫秒
{
uint I,j;
for(i=xms;i>0;i--)
for(j=587;j>0;j--);
}
/***************************
主函数
***************************/
void main(void)
{
uchar count;
InitLed();        //调用初始化函数
InitT1();                 //初始化定时器
while(1)                 //轮询查看IRCON寄存器的状态
{
if(IRCON>0) //查询方式
{
IRCON=0;
if(++count==1)         //约 1s周期性闪烁
{
count=0;
LED1 = !LED1;         //LED1 闪烁
}
}
}
/****************************
//初始化程序
*****************************/
void InitLed(void)
{
P1DIR |= 0x01;    //P1_0 定义为输出
LED1 = 1;         //LED1 灯初 始化熄灭
}
//定时器初始化
void InitT1() //系统不配置工作时钟时使用内部 RC振荡器,即16MHz
{
T1CTL = 0x0d;   //128 分频,自动重装 0X0000-0XFFFF
}
重点:系统在不配置工作频率时默认为 2分频,即 32M/2=16M,所以定时
器每次溢出时 T=1/(16M/128)*65536≈0.5s, 所以总时间Ta=T*count=0.5*1=0.5S
切换 1次状态。所以看起来是 1S闪烁 1次。
中断方式(使用定时器3)
CC2530的 T3定时器主要是配置三个寄存T3CTL,T3CCTL0,T3CC0,T3CCTL1,T3CC1。
T3CTL(0XCB) Timer3 控制寄存器:
Bit7:Bit5 :  定时器时钟分频倍数选择:
000:不分频,001:2分频,010:4分频, 011:8分频,100:16分频,101:32分频,110:64分频,111:128分频
Bit4 :   T3 起止控制位
Bit3 :   溢出中断掩码 0:关溢出中断 1:开溢出中断
Bit2 :   清计数值 高电平有效
Bit1:Bit0: T3模式选择
00:自动重装 0X00-0XFF
01: DOWN (从 T3CC0 到 0X00计数一次)
10: 模计数(反复从 0X00 到 T3CC0 计数)
11: UP/DOWN(反复从 0X00到 T3CC0 计数再到 0X00)
T3CCTL0(0XCC) T3    通道 0 捕获/ 比较控制寄存器:
Bit6:  T3通道 0  中断掩码 0:关中断 1:开中断
Bit5: Bit3 : T3  通道 0 比较输出模式选择
Bit2: T3通道 0 模式选择: 0:捕获 1  :比较
Bit1: Bit0:    T3 通道 0 捕获模式选择
00   没有捕获 01     上升沿捕获
10 下降沿捕获     11     边沿捕获
T3CC0(0XCD) T3 通道 0  捕获/ 比较值寄存器
T3CCTL1(0XCE) T3  通道 1 捕获/ 比较控制寄存器:
Bit6:  T3通道1 中断掩码 0:关中断 1:开中断
Bit5: Bit3 : T3  通道 1 比较输出模式选择
Bit2: T3通道 1 模式选择: 0:捕获 1  :比较
Bit1: Bit0:    T3 通道 1 捕获模式选择
00   没有捕获 01     上升沿捕获
10 下降沿捕获 11     边沿捕获
T3CC1(0XCF)   T3 通道 1  捕获/ 比较值寄存器
与上例 T1定时器查询方式的区别就是此处使用 T3定时器(8位),中断方式。寄存器配置如下:
T3CTL |= 0x08 ;  //开溢出中断
T3IE  = 1;  //开总中断和 T3中断
T3CTL |=0XE0;   //128 分频,128/16000000*N=0.5S,N=65200
T3CTL &= ~0X03;      //自动重装 00->0xff65200/256=254(次)
T3CTL |=0X10;   //启动
EA = 1;  //开总中断
代码实现
//定时器初始化
void InitT3()
{  
T3CTL |= 0x08 ;   //开溢出中断
T3IE = 1;   //开总中断和 T3中断
T3CTL|=0XE0;   //128 分频,128/16000000*N=0.5S,N=65200
T3CTL &= ~0X03;   //自动重装 00->0xff  65200/256=254(次)
T3CTL |=0X10;   //启动
EA = 1;    //开总中断
}
中断函数
/************************************
中断函数
************************************/
#pragma vector = T3_VECTOR    //定时器 T3
__interrupt void T3_ISR(void)
{
IRCON = 0x00;   //清中断标志,也可由硬件自动完成
if(++count>254)  //254 次中断后 LED取反,闪烁一轮(约为 0.5秒时间)
{
count = 0;  // 计数清零
LED1=~LED1; //led闪烁
}
}
Main函数
/***************************
//主函数
***************************/
void main(void)
{
InitLed();      //调用初始化函数
InitT3();
while(1){ }
}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top