CC2530基础实验三 定时器

2019-04-13 14:01发布

一、任务要求

使用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) 注意:外部石英晶振比较稳定,在无线收发中采用外部石英晶振 时钟源的切换 CLKCONSTA 用于判断时钟源是否切换成功 这里写图片描述 CLKCONCMD 用于设置时钟源 这里写图片描述 用命令寄存器(CLKCONCMD)来改变系统时钟源,用状态寄存器 (CLKCONSTA) 来判断改变后的寄存器是否稳定了。 这里写图片描述

四、定时器

这里写图片描述 定时器设置 定时器时间:1/CLKCONCMD*T1CTL分频*工作模式*溢出次数 CLKCONCMD -->TI计数器(T1CTL模式选择)-->TISTAT.OVFIF(标志位)-->TIMIF.OVFIM-->T1IF-->EA-->T1IE 定时器初始化 T1CTL 设置分频 与模式 T1CCOH T1CCOL 高低八位 T1CCTL0|=0x04 通道0 比较模式 T1IF=0 清除TIMER1中断标志 T1STAT &=~0x01; 清除通道0中断标志 IEN1|=0X02 使能定时器1的中断 EA=1 T1定时器中断条件 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 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、定时器中断函数 #pragma vector = T1_VECTOR __interrupt void t1() { counter++; if(counter == 30) { T1IF = 0; counter = 0; /*************** 代码 ******************/ } } 寄存器 T1CTL 设置T1定时器操作模式和分频 这里写图片描述 T1STAT 这里写图片描述 IRCON 溢出中断标志定时器计数满后需要清楚标志位 当定时器T1产生中断时也可以写作 IRCON &= 0X02;  T1IF = 0; 这里写图片描述 T1CCTL0 设置TIMER1通道0比较模式 T1CCTL0 |= 0X04; 这里写图片描述 T1CC0L、T1CC0H 这里写图片描述 正计数/倒计数器工作模式从0x0000~T1CC0,再从T1CC0~0x0000需设置 这里写图片描述 TIMIF 不产生定时器T1的溢出中断 常用设置 TIMIF &= ~0X40; 这里写图片描述 IEN1 用于设置中断使能 常用设置 IEN1 |= 0X02; 这里写图片描述

五、具体代码

#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口中断标志位 }