前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CC2530基础实验三 定时器

CC2530基础实验三 定时器

作者头像
w候人兮猗
发布2020-07-01 17:33:55
1.9K0
发布2020-07-01 17:33:55
举报

####一、任务要求 使用CC2530单片机内部定时/计数器来控制LED1进行周期性闪烁,具体闪烁效果要求如下:

①通电后LED1每隔2秒闪烁一次。 ②LED1每次闪烁点亮时间为0.5秒

1.定时/计数器介绍 (1)定时/计数器的概念 定时/计数器是一种能够对时钟信号或外部输入信号进行计数,当计数值达到设定要求时便向CPU提出处理请求,从而实现定时或计数功能的外设。在单片机中,一般使用Timer表示定时计数器。 (2)定时/计数器的作用 定时/计数器的基本功能是实现定时和计数,且在整个工作过程中不需要CPU进行过多参与,它的出现将CPU从相关任务中解放出来,提高了CPU的使用效率。例如我们之前实现LED灯闪烁时采用的是软件延时方法,在延时过程中CPU通过执行循环指令来消耗时间,在整个延时过程中会一直占用CPU,降低了CPU的工作效率。若使用定时/计数器来实现延时,则在延时过程中CPU可以去执行其他工作任务。CPU与定时/计数器之间的交互关系可用图4-1来进行表示。

这里写图片描述
这里写图片描述

单片机中的定时/计数器一般具有以下功能:

1)定时器功能 对规定时间间隔的输入信号的个数进行计数,当计数值达到指定值时,说明定时时间已到。这是定时/计数器的常用功能,可用来实现延时或定时控制,其输入信号一般使用单片机内部的时钟信号。 2)计数器功能 对任意时间间隔的输入信号的个数进行计数。一般用来对外界事件进行计数,其输入信号一般来自单片机外部开关型传感器,可用于生产线产品计数、信号数量统计和转速测量等方面。 3)捕获功能 对规定时间间隔的输入信号的个数进行计数,当外界输入有效信号时,捕获计数器的计数值。通常用来测量外界输入脉冲的脉宽或频率,需要在外界输入信号的上升沿和下降沿进行两次捕获,通过计算两次捕获值的差值可以计算出脉宽或周期等信息。 4)比较功能 当计数值与需要进行比较的值相同时向CPU提出中断请求或改变I/O口输出电平等操作。一般用于控制信号输出。 5)PWM输出功能 对规定时间间隔的输入信号的个数进行计数,根据设定的周期和占空比从I/O口输出控制信号。一般用来控制LED灯亮度或电机转速。

(3)定时/计数器基本工作原理 无论使用定时/计数器的哪种功能,其最基本的工作原理是进行计数。定时/计数器的核心是一个计数器,可以进行加1(或减1)计数,每出现一个计数信号,计数器就自动加1(或自动减1),当计数值从最大值变成0(或从0变成最大值)溢出时定时/计数器便向CPU提出中断请求。计数信号的来源可选择周期性的内部时钟信号(如定时功能)或非周期性的外界输入信号(如计数功能)。

这里写图片描述
这里写图片描述

####二、CC2530的定时/计数器 CC2530中共包含了5个定时/计数器,分别是定时器1、定时器2、定时器3、定时器4和睡眠定时器。 (1)定时器1

定时器1是一个16位定时器,主要具有以下功能: 支持输入捕获功能,可选择上升沿、下降沿或任何边沿进行输入捕获。 支持输出比较功能,输出可选择设置、清除或切换。 支持PWM功能。 具有5个独立的捕获/比较通道,每个通道使用一个I/O引脚。 具有自由运行、模、正计数/倒计数三种不同工作模式。 具有可被1、8、32或128整除的时钟分频器,为计数器提供计数信号。 能在每个捕获/比较和最终计数上产生中断请求。 能触发DMA功能。 定时器1是CC2530中功能最全的一个定时/计数器,是在应用中被优先选用的对象。

####CC2530定时/计数器的工作模式

CC2530的定时器1、定时器3和定时器4虽然使用的计数器计数位数不同,但它们都具备“自由运行”、“模”和“正计数/倒计数”三种不同的工作模式,定时器3和定时器4还具有单独的倒计数模式。此处以定时器1为例进行介绍。 (1)自由运行模式 在自由运行模式下,计数器从0x0000开始,在每个活动时钟边沿增加1,当计数器达到0xFFFF时溢出,计数器重新载入0x0000并开始新一轮递增计数

这里写图片描述
这里写图片描述

自由运行模式最大为FFFF也就是65535

自由运行模式的计数周期是固定值0xFFFF,当计数器达到最终计数值0xFFFF时,系统自动设置标志位IRCON.T1IF和T1STAT.OVFIF,如果用户设置了相应的中断屏蔽位TIMIF.T1OVFIM和IEN1.T1EN,将产生一个中断请求。 (2)模模式 在模模式下,计数器从0x0000开始,在每个活动时钟边沿增加1,当计数器达到T1CC0寄存器保存的值时溢出,计数器将复位到0x0000并开始新一轮递增计数

这里写图片描述
这里写图片描述

计数溢出后,将置位相应标志位,同时如果设置了相应的中断使能则会产生一个中断请求。T1CC0由2个8位寄存器T1CC0H和T1CC0L构成,分别用来保存最终计数值的高8位和低8位。模模式的计数周期不是固定值,可由用户自行设定,以便获取不同时长的定时时间。 定时器3和定时器4的倒计数模式类似与模模式,只不过计数值是从最大计数值向0x00倒序计数。 (3)正计数/倒计数模式 在正计数/倒计数模式下,计数器反复从0x0000开始,正计数到T1CC0保存的最终计数值,然后再倒计时回0x0000

这里写图片描述
这里写图片描述

正计数/倒计数模式下,计数器在到达最终计数值时溢出,并置位相关标志位,若用户已使能相关中断,则会产生中断请求。这种工作模式在用来进行PWM控制时可以实现中心对齐的PWM输出。

####定时器设置流程

这里写图片描述
这里写图片描述

执行流程

这里写图片描述
这里写图片描述

####三、CC2530时钟源 时钟源 1、内部RC震荡器(32KHz、16MHz) 2、外部石英晶振(32.768KHz、32MHz) 注意:外部石英晶振比较稳定,在无线收发中采用外部石英晶振

代码语言:javascript
复制
时钟源的切换
CLKCONSTA
用于判断时钟源是否切换成功
这里写图片描述
这里写图片描述
代码语言:javascript
复制
CLKCONCMD
用于设置时钟源
这里写图片描述
这里写图片描述
代码语言:javascript
复制
用命令寄存器(CLKCONCMD)来改变系统时钟源,用状态寄存器 (CLKCONSTA) 来判断改变后的寄存器是否稳定了。
这里写图片描述
这里写图片描述

####四、定时器

这里写图片描述
这里写图片描述

定时器设置

代码语言:javascript
复制
定时器时间:1/CLKCONCMD*T1CTL分频*工作模式*溢出次数

CLKCONCMD -->TI计数器(T1CTL模式选择)-->TISTAT.OVFIF(标志位)-->TIMIF.OVFIM-->T1IF-->EA-->T1IE

定时器初始化

代码语言:javascript
复制
T1CTL 设置分频 与模式
T1CCOH T1CCOL 高低八位
T1CCTL0|=0x04 通道0 比较模式

T1IF=0 清除TIMER1中断标志
T1STAT &=~0x01; 清除通道0中断标志
IEN1|=0X02 使能定时器1的中断
EA=1

T1定时器中断条件

代码语言:javascript
复制
1、设置时钟源
CLKCONCMD &= ~0X40;
  while(CLKCONSTA & 0x40);
  CLKCONCMD &= ~0X47;
2、设置T1定时器的工作模式和分频
T1CTL = 0X05;
3、打开T1中断和中断总开关
  IEN1 |= 0X02;
EA = 1;
4、写中断函数
  #pragma vector = T1_VECTOR
__interrupt void ti()
{
    counter++;
    if(counter == 50)
    {
      T1IF = 0;   //清空T1溢出中断标志位
      counter = 0;
/***************
代码
**************/
    }
}

按键控制定时器T1

代码语言:javascript
复制
1、初始化按键中断寄存器,打开中断总开关
  IEN2 |= 0X10;
  P1IEN |= 0X04;
  PICTL &= ~0X02;
EA = 1;
2、修改32MHz时钟源
  CLKCONCMD &= ~0X40;
  while(CLKCONSTA & 0x40);
  CLKCONCMD &= ~0X07;
3、按键中断函数,并设置定时器的工作模式和分频,打开T1中断
  #pragma vector = P1INT_VECTOR
__interrupt void f1()
{
  EA = 0;
  if(P1IFG & 0X04)
  {
    while(P1_2 == 0);
    delay(100);
    while(P1_2 == 0);

    if(k == 1)
    {
      k = 0;
      IEN1 |= 0X02;
      T1CTL = 0X05;
    }
    else if(k == 0)
    {
      k = 1;
      IEN1 &= ~0X02;
      T1CTL = 0;
    }
    P1IFG = 0;
    P1IF = 0;
  }
  EA = 1;
}

4、定时器中断函数

代码语言:javascript
复制
  #pragma vector = T1_VECTOR
__interrupt void t1()
{
  counter++;
  if(counter == 30)
  {
    T1IF = 0;
    counter = 0;
    /***************
    代码
    ******************/
      }
}


寄存器
T1CTL
设置T1定时器操作模式和分频
这里写图片描述
这里写图片描述
代码语言:javascript
复制
T1STAT
这里写图片描述
这里写图片描述
代码语言:javascript
复制
IRCON
溢出中断标志定时器计数满后需要清楚标志位
当定时器T1产生中断时也可以写作  
IRCON &= 0X02;    T1IF = 0;
这里写图片描述
这里写图片描述
代码语言:javascript
复制
T1CCTL0
设置TIMER1通道0比较模式      T1CCTL0  |= 0X04;
这里写图片描述
这里写图片描述
代码语言:javascript
复制
T1CC0L、T1CC0H
这里写图片描述
这里写图片描述
代码语言:javascript
复制
正计数/倒计数器工作模式从0x0000~T1CC0,再从T1CC0~0x0000需设置
这里写图片描述
这里写图片描述
代码语言:javascript
复制
TIMIF
不产生定时器T1的溢出中断
常用设置
TIMIF &= ~0X40;
这里写图片描述
这里写图片描述
代码语言:javascript
复制
IEN1
用于设置中断使能
常用设置
    IEN1 |= 0X02;
这里写图片描述
这里写图片描述

####五、具体代码

代码语言:javascript
复制
#include "ioCC2530.h" //引用CC2530头文件

#define LED1 (P1_0)     //LED1端口宏定义
#define LED2 (P1_1)     //LED1端口宏定义

unsigned char flag_Pause=0;  //流水灯运行标志位,为1暂停,为0运行。

/**************************************************************
函数名称:delay
功    能:软件延时
入口参数:time--延时循环执行次数
出口参数:无
返 回 值:无
**************************************************************/
void delay(unsigned int time)
{
    unsigned int i;
    unsigned char j;
    for(i = 0;i < time;i++)
        for(j = 0;j < 240;j++)
        {
            asm("NOP");//asm用来在C代码中嵌入汇编语言操作,汇
            asm("NOP");//编命令nop是空操作,消耗1个指令周期。
            asm("NOP");
            while(flag_Pause);//根据flag_Pause的值确定是否在此循环
        }
}

/**************************************************************
函数名称:main
功    能:程序主函数
入口参数:无
出口参数:无
返 回 值:无
**************************************************************/
void main(void)
{
    P1SEL &= ~0x03;         //设置P1_0口和P1_1口为普通I/O口
    P1DIR |= 0x03;          //设置P1_0口和P1_1口为输出口

    LED1 = 0;               //熄灭LED1
    LED2 = 0;               //熄灭LED2

    /*************新增外部中断初始化部分****************/
    IEN2 |= 0x10;           //使能P1口中断
    P1IEN |= 0x04;          //使能P1_2口中断
    PICTL |= 0x02;          //P1_3到P1_0口下降沿触发中断
    EA = 1;                 //使能总中断
    /***************************************************/

    while(1)//程序主循环
    {
        delay(1000);        //延时
        LED1 = 1;           //点亮LED1
        delay(1000);        //延时
        LED2 = 1;           //点亮LED2
        delay(1000);        //延时
        LED1 = 0;           //熄灭LED1
        delay(1000);        //延时
        LED2 = 0;           //熄灭LED2
    }
}

/**************************************************************
函数名称:P1_INT
功    能:P1口外部中断服务函数
入口参数:无
出口参数:无
返 回 值:无
**************************************************************/
#pragma  vector = P1INT_VECTOR
__interrupt void P1_INT(void)
{
    if(P1IFG & 0x04)       //如果P1_2口中断标志位置位
    {
        if(flag_Pause == 0)
        {
            flag_Pause = 1;
        }
        else
        {
            flag_Pause = 0;
        }
        P1IFG &= ~0x04;    //清除P1_2口中断标志位
    }
    P1IF = 0;              //清除P1口中断标志位
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年3月25日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档