zoukankan      html  css  js  c++  java
  • CC2530学习路线-基础实验-定时器控制LED灯亮灭(3)



    1. 前期预备知识

    1.1 定时器中断触发

    本次实验需关注的中断寄存器。

    image_1bqbsemrp897bm6hhja68i9vp.png-497.2kB

    在本次实验中,分别会使用T1和T3定时器完成功能,所以我们需要注意上图中标注出的中断寄存器。
    T1定时器:16位定时器(065535)。T3定时器:8位定时器(0255)

    1.2 相关寄存器

    注:一下只给出实验中新出现的寄存器,并不是本次实验需用到的所有寄存器;想了解其它寄存器作用及功能请看之前的基础实验文档,或查看CC2530中文数据手册。
    
    寄存器名称 作用 寄存器描述
    T1CTL (0xE4) 定时器1的控制和状态 T1CTL (bit 3~2) 为分频器划分值,具体值如下:
    00:标记频率/1
    01:标记频率/8
    10:标记频率/32
    11:标记频率/128
    T1CTL (bit 1~0) 为选择定时器1模式
    00:暂停运行
    01:自由运行
    10:模,从0x0000到T1CC0反计数
    11:正计数/倒计数,从0x0000到T1CC0反复计数并且从T1CCO倒计数到0x000
    T1STAT (0xAF) 定时器1 状态 bit5:定时器 计数器溢出中断标志
    bit4:定时器1通道4中断标志
    bit3:定时器1通道3中断标志
    bit2:定时器1通道2中断标志
    bit1:定时器1通道1中断标志
    bit0:定时器1通道0中断标志
    IEN1 (0xB8) 中断使能 1 IEN1寄存器中我们只使用了bit1,bit3所在的功能,
    bit1 : T1计时器中断使能
    bit3 : T3计时器中断使能
    TIMIF (0xD8) 定时器1/3/4中断屏蔽/标志 TIMIF我们这一次实验只用到了bit6为定时器1溢出中断屏蔽
    IRCON (0xC0) 中断标志4 bit1:定时器1中断标志。当定时器1中断发生时设为1并且当CPU向量指向中断服务例程时清除。
    0:无中断未决
    1:中断未决
    T3CTL (0xCB) 定时器3的控制和状态 bit[7:5] : 定时器时钟分频倍数选择:
    000:不分频; 001:2分频; 010:4分频
    011:8分频; 100:16分频; 101:32分频
    110:64分频; 111:128 分频.

    bit4 : T3 起止控制位
    bit3 : 溢出中断掩码 0:关溢出中断 1:开溢出中断
    bit2 : 清计数值 高电平有效
    Bit[1:0]T3模式选择
    00:自动重装 0x00-0xFF
    01:DOWN (从T3CC0 到0X00计数一次)
    10:模计数(反复从 0X00到T3CC0 计数)
    11:UP/DOWN(反复从0X00到T3CC0 计数再到0X00)
    T3CCTL0(0xCC) T3 通道 0 捕获/比较控制寄存器 bit6: 通道0中断屏蔽 0:中断禁止 1:中断使能
    bit5~3: T3 通道0 比较输出模式选择
    bit2: T3 通道0模式选择: 0:捕获 1:比较
    bit1~0 T3 通道 0 捕获模式选择
    00 没有捕获 01 上升沿捕获10 下降沿捕获 11 边沿捕获
    T3CC0(0xCD) 定时器 3 通道0捕获/比较值 定时器捕获/比较值通道 0。当 T3CCTL0.MODE=1(比较模式)时写该寄存器会导致 T3CC0.VAL[7:0]更新到写入值延迟到 T3CNT.CNT[7:0]=0x00。
    T3CCTL1(0xCE) T3 通道 1 捕获/比较控制寄存器 bit6: 通道1中断屏蔽 0:中断禁止 1:中断使能
    bit5~3: T3 通道1 比较输出模式选择
    bit2: T3 通道 1 模式选择: 0:捕获 1 :比较
    Bit[1:0] T3 通道 1 捕获模式选择
    00 没有捕获01 上升沿捕获10 下降沿捕获 11 边沿捕获
    T3CC1(0xCF) 定时器 3 通道1捕获/比较值 定时器捕获/比较值通道 1。当 T3CCTL1.MODE=1(比较模式)时写该寄存器会导致 T3CC1.VAL[7:0]更新写入值延迟到 T3CNT.CNT[7:0]=0x00。

    1.3 寄存器相关问题

    1.什么是标记频率,什么是分频?

    标记频率可以理解为是外部晶振的频率,在新大陆CC2530模块中,外部晶振频率是32MHz。分频的意思就是通过模块将高频率信号降低值原来的X分之一。这里举个例子,如将32MHz进行2分频,那就是32Mhz/X=16MHz的信号;将32MHz进行4分频就是32Mhz/X=8Mhz。在CC2530中会对51内核进行默认的2分频,也就是说51内核实际标记频率为16Mhz;如果不使用CLKCONCMD寄存器对晶振频率进行设定,那么51内核实际频率为16Mhz.

    2.什么是无中断未决,什么是中断未决?

    英文手册中是Interrupt not pending(中断未挂起)和Interrupt pending(中断挂起)。所谓无中断未决就是说中断都进入其中断处理函数进行处理了;而中断未决就是中断被挂起目前没有进入对应的中断处理函数进行处理。

    3.为什么有写书籍上T1中断使能是IEN1|=0x02,而有些直接是T1IE=1?

    /*  Interrupt Enable 1                                                              */
    SFRBIT( IEN1    ,  0xB8, _IEN17, _IEN16, P0IE, T4IE, T3IE, T2IE, T1IE, DMAIE )
    

    我们查看IEN1在ioCC2530.h中的定义,其中针对其bit位的定义(高位在前),我么可以发现T1IE就是IEN1的bit1,所以T1中断使能操作IEN1|=0x02和T1IE=1是一样的效果。

    4.如何根据标记频率和分频计算溢出所需要的时间?

    这是有一个公式的 溢出时间 = 1S/(标记频率/分频)*2^定时器位数.
    如果我们使用的是16Mhz标记频率,64分频,T3定时器,它的位数是8位.那么结果就是 1/(16mhz/64)*256 = 0.001s
    在比如我们使用的是16Mhz标记频率,128分频,T1定时器,它的位数是16位.那么结果就是 1/(16mhz/128)*65535 = 0.524s

    1.4 T1、T3定时器初始化流程


    1.4.1 T1定时器初始化流程

    首先我们来看T1定时器的初始化流程图,T1定时器是一个16位的定时器,我们实现简单的功能。

    5

    1.4.2 T3定时器初始化流程

    T3定时器初始化流程和T1定时器初始化流程基本一致.

    8

    T3寄存器多了一个步骤,就是启动定时器。当然同样可以暂停寄存器。

    2 程序及代码

    #include <ioCC2530.h>
    typedef unsigned int uint;
    typedef unsigned char uchar;
    
    uint t1_count = 0;
    uint t3_count = 0;
    
    void init_gpio(void)
    {
      P1SEL &=~ 0x03;
      P1DIR |= 0x03;
      P1 = 0x00;
      
      P1_0 = 0;
      P1_1 = 1;
    }
    
    void init_timer3()
    {
      T3CTL |= 0xC0;  // 设置64分频,自动重装,每次溢出时间 1/(16mhz/64)*256 = 0.001s(几乎1ms)
      T3CTL |= 0x04;  // 打开T3溢出中断使能
      EA = 1; // 打开总开关
      T3IE = 1; // 打开T3中断使能
      T3CTL |= 0x10;  // 启动定时器
    }
    
    void init_timer1()
    {
      T1CTL |= 0x0d;  // 设置128分频,自由运行; 每次溢出时间 1/(16mhz/128)*65535 = 0.524s
      TIMIF |= 0x40; //打开T1溢出中断
      EA = 1; // 打开总开关
      IEN1 |= 0x02; // 打开t1中断使能
    }
    
    #pragma vector = T3_VECTOR
    __interrupt void T3_ISR(void)
    {
      t3_count ++;
      if(t3_count % 2000 == 0)  // 2S翻转一次
      {
        P1_0 = ~P1_0;
        P1_1 = ~P1_1;
      }
    }
    
    #pragma vector = T1_VECTOR
    __interrupt void T1_ISR(void)
    {
      t1_count++;
      if(t1_count%2 == 0) // 1S翻转一次状态
      {
        P1_0 = ~P1_0;
        P1_1 = ~P1_1;
      }
    }
    
    void main(void)
    {
      init_gpio();
      //init_timer1();
      init_timer3();
      while(1)
      {
        ;
      }
    }
    
    通过注释init_timer1();或init_timer3()可以分别看到使用两个定时器实现不同延时的效果。
    

    THE END

  • 相关阅读:
    SpringMVC——拦截器及文件上传和下载
    SpringMVC——数据处理
    SpringMVC——返回结果及指定视图
    SpringMVC——SpringMVC配置
    SpringMVC——简介及原理简单分析
    Kakfa和其他类型消息中间件对比图
    Kafka消费者——结合spring开发
    Kafka生产者——结合spring开发
    五大浏览器-四大内核
    python中查看module和function的方法
  • 原文地址:https://www.cnblogs.com/InCerry/p/9397888.html
Copyright © 2011-2022 走看看