zoukankan      html  css  js  c++  java
  • CC2530定时器使用

    

    定时器学习

     

    文件夹

    说明...1

    协议栈函数使用...2

    设置初始化定时器...2

    回调函数(中断服务函数)3

    启动定时器...3

    停止定时器...4

    寄存器操作...4

    查询方式...4

    中断方式(使用定时器3)7

     

    说明

        依据数据手冊可知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

     

    有两个方法达到定时的目的,一个是协议栈函数,一个直接寄存器操作

    协议栈函数使用

            OSALmain函数中 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);

    此处的TimerIDHAL_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++;  //每次调用此函数,n1

            if(n ==5000) {  //n加到一个自己定义的数值后,就运行相关任务,然后将n清零

                                        //改变这个值就可以控制定时的长短

                      /*do something...*/

           HalUARTWrite(0,"20000000000 ",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 ",13);

           LED1 = ~LED1;

           stop++;

           if(stop == 10)  //将会在led灯闪烁5次之后关闭定时器

               HalTimerStop(HAL_TIMER_0); 

                      n =0;

            }

       return;

    }

     

    寄存器操作

    本段參考网蜂团队的第二章基础实验2.4定时器

    分为两种方式:查询模式,中断模式,相比查询模式中断模式更节省cpu资源,效率更高!

     

    查询方式

    CC2530 T1定时器16位)我们须要配置三个寄存器 T1CTL T1STATIRCON

    IO口配置请留意第一节教程内容。

    各寄存器功能例如以下表所看到的:(具体參考 CC2530 datasheet.pdf

    T1CTL(0XE4)Timer1  控制寄存器:

    Bit3:Bit2 : 定时器时钟分频倍数选择:

    00:不分频 018分频 10 32分频 11128分频

    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灯的port

    #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)*655360.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:不分频,0012分频,0104分频, 0118分频,10016分频,10132分频,11064分频,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){ }

    }

     

  • 相关阅读:
    JAVA CAS原理深度分析
    Java 并发类库AbstractQueuedSynchronizer 分析
    构建高并发高可用的电商平台架构实践
    简单控件 复合控件
    WebFrom基础
    控件m
    控件
    WinForm
    操作数据类m
    数据操作类
  • 原文地址:https://www.cnblogs.com/llguanli/p/7123523.html
Copyright © 2011-2022 走看看