Zigbee之旅(九):几个重要的CC2430基础实验——系统睡眠及中断唤醒

一、承上启下

  这一篇,我们来讨论一下CC2430的睡眠功能及唤醒方法。在实际运用中的CC2430节点一般是靠电池来供电,因此对其功耗的控制显得至关重要。

  下面是摘自CC2430中文手册对CC2430的4种功耗模式的介绍:

  从上表中可看出,CC2430共有4种电源模式:PM0(完全清醒),PM1(有点瞌睡)、PM2(半醒半睡)、PM3(睡的很死)。越靠后,被关闭的功能越多,功耗也越来越低。它们之间的转化关系如下:

  

  把 PM1、PM2 唤醒到PM0,有三种方式:复位、外部中断、睡眠定时器中断;但把 PM3 唤醒到 PM0,只有两种方式:复位、外部中断(这是因为在 PM3 下,所有振荡器均停止工作,睡眠定时器当然也熄火啦~)

  下面我们通过一个小实验,来介绍如何进入睡眠模式,以及如何唤醒到 PM0 状态。

二、系统睡眠及中断唤醒实验

(1)实验简介

系统初始化,处于PM0
→ 进入PM1
→ 1s后被睡眠定时器唤醒为PM0
→ 进入PM2
→ 2s后被睡眠定时器唤醒为PM0
→ 进入PM3
→ 等待按键S1按下,触发外部中断,被唤醒为PM0 

(2)程序流程图

  (注:上图中的圆角框表示系统的运行状况)

(3)实验源码及剖析(下面的框框是可以点的~)

头文件及宏定义

/*
实验说明:中断唤醒睡眠实验,分别介绍三种睡眠模式下的唤醒
*/

#include <ioCC2430.h>

 LED_ON  0#define led1 P1_0          #define led2 P1_1          #define led3 P1_2          #define led4 P1_3    

子函数

/*系统时钟初始化
-------------------------------------------------------*/
void xtal_init(void)
{
SLEEP &= ~0x04; //都上电
while(!(SLEEP & 0x40)); //晶体振荡器开启且稳定
CLKCON &= ~0x47; //选择32MHz 晶体振荡器
SLEEP |= 0x04;
}

/*LED初始化
-------------------------------------------------------*/
void led_init(void)
{
P1SEL = 0x00; //P1为普通 I/O 口
P1DIR |= 0x0F; //P1.0 P1.1 P1.2 P1.3 输出

led1 = LED_OFF; //关闭所有LED
led2 = LED_OFF;
led3 = LED_OFF;
led4 = LED_OFF;
}

/*外部中断初始化
-------------------------------------------------------*/
void io_init(void)
{
P0INP &= ~0X02; //P0.1有上拉、下拉

EA = 1; //总中断允许

IEN1 |= 0X20; // P0IE = 1,P0中断使能

PICTL |= 0X09; //P0.1允许中断,下降沿触发

P0IFG &= ~0x02; //P0.1中断标志清0
}

/*睡眠定时器中断初始化
-------------------------------------------------------*/
void sleepTimer_init(void)
{
STIF=0; //睡眠定时器中断标志清0

STIE=1; //开睡眠定时器中断

EA=1; //开总中断
}

/*设置睡眠定时器的定时间隔
-------------------------------------------------------*/
void setSleepTimer(unsigned int sec)
{
unsigned long sleepTimer = 0;

sleepTimer |= ST0; //取得目前的睡眠定时器的计数值
sleepTimer |= (unsigned long)ST1 << 8;
sleepTimer |= (unsigned long)ST2 << 16;

sleepTimer += ((unsigned long)sec * (unsigned long)32768); //加上所需要的定时时长

ST2 = (unsigned char)(sleepTimer >> 16); //设置睡眠定时器的比较值
ST1 = (unsigned char)(sleepTimer >> 8);
ST0 = (unsigned char)sleepTimer;
}

/*选择电源模式
-------------------------------------------------------*/
void PowerMode(unsigned char mode)
{
if(mode<4)
{
SLEEP &= 0xfc; //将SLEEP.MODE清0
SLEEP |= mode; //选择电源模式
PCON |= 0x01; //启用此电源模式
}
}

/*延时函数
-------------------------------------------------------*/
void Delay(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<1000;j++);
}

主函数

/*主函数
-------------------------------------------------------*/
void main(void)
{
xtal_init();
led_init();

//PM0状态,亮灯并延时
led1 = LED_ON; //亮LED1,表示统在PM0模式工作
Delay(10);

//PM1状态,灭灯
setSleepTimer(1); //设置睡眠定时器的定时间隔为1s
sleepTimer_init(); //开睡眠定时器中断
led1 = LED_OFF;
PowerMode(1); //设置电源模式为PM1

//1s后,由PM1进入PM0,亮灯并延时
led1 = LED_ON;
Delay(50);

//PM2,灭灯
setSleepTimer(2); //设置睡眠定时器的定时间隔为2s
led1 = LED_OFF;
PowerMode(2); //设置电源模式为PM2

//2s后,由PM2进入PM0,亮灯并延时
led1=0;
Delay(50);

//PM3,灭灯
io_init(); //初始化外部中断
led1 = LED_OFF;
PowerMode(3); //设置电源模式为PM3

//当外部中断发生时,由PM3进入PM0,亮灯
led1 = LED_ON;

while(1);
}

中断服务程序

/*外部中断服务程序
-------------------------------------------------------*/
#pragma vector = P0INT_VECTOR
__interrupt void P0_ISR(void)
{
EA = 0; //关中断

Delay(50);

if((P0IFG & 0x02 ) >0 ) //按键中断
{
P0IFG &= ~0x02; //P0.1中断标志清0
}
P0IF = 0; //P0中断标志清0

EA = 1; //开中断
}

/*睡眠定时器中断服务程序
-------------------------------------------------------*/
#pragma vector= ST_VECTOR
__interrupt void sleepTimer_IRQ(void)
{
EA=0; //关中断

STIF=0; //睡眠定时器中断标志清0

EA=1; //开中断
}

  关于如何使用睡眠定时器来唤醒系统,可以总结为如下流程:开睡眠定时器中断 → 设置睡眠定时器的定时间隔 → 设置电源模式

  (注:“设置睡眠定时器的定时间隔”这一步一定要在“设置电源模式”之前,因为进入睡眠后系统就不会继续执行程序了)

  接下来,我们重点关注一下设置睡眠定时器定时间隔的子函数:setSleepTimer

  首先对睡眠定时器简单的介绍一下:它是运行于32.768kHz的24位定时器,当系统运行在除了PM3之外的所有的电源模式下,睡眠定时器都会不间断运行。

  睡眠定时器使用的寄存器有:ST0,ST1,ST2。下面是摘自CC2430中文手册对其功能的详细介绍:

  可以看出,它们的功能包括两方面:读,写。

  读:用于读取当前定时器的计数值,读的顺序必须遵循:读ST0 → 读ST1 → 读ST2

  写:用于设置定时器的比较值(当定时器的计数值=比较值时,产生中断),写的顺序必须遵循:写ST2 → 写ST1 → 写ST0

  OK,接下来我们结合源码来讲解:

  (1)首先,定义一个unsigned long型变量(32位)sleepTimer,用于接收睡眠定时器的当前计数值:

unsigned long sleepTimer = 0;

sleepTimer |= ST0; //取得目前的睡眠定时器的计数值
sleepTimer |= (unsigned long)ST1 << 8;
sleepTimer |= (unsigned long)ST2 << 16;

  (2)然后加上所需要的定时间隔:

sleepTimer += ((unsigned long)sec * (unsigned long)32768); //加上所需要的定时时长

  此处需要稍微解释一下:

  为什么1s就代表着32768?因为定时器是工作在32.768kHz之下,所以定时器每加1,需耗时1/32768 s;加32768,就需要1s;

  (3)最后将sleepTimer的值作为定时器的比较值:

ST2 = (unsigned char)(sleepTimer >> 16); //设置睡眠定时器的比较值
ST1 = (unsigned char)(sleepTimer >> 8);
ST0 = (unsigned char)sleepTimer;

  这样,就可成功设置定时器的定时周期啦~

  (注:至于源码的其他部分,相信结合着详细的注释,大家可以轻松看懂,在此不作赘述)

(4)实验结果

  运行程序,观察LED1,现象为:LED1闪烁(即亮->灭1次),1s后再次闪烁,2s后再次闪烁,然后保持熄灭状态,然后按下S1,LED1亮。

  实验现象和预期完全吻合,Over~

三、结语

  吁~ 抽出2天的课余时间,终于搞定了这篇日志。真的发现写博,特别是写一篇“读者友好”的博文,的确是一项体力活:严谨性、美观性、逻辑性...都是要考虑的事儿。

  每次贴代码都嫌太长,但又不太愿意使用博客园自带的折叠工具。因此在本篇博文中,笔者试探性的加入了一些JQuery元素,实现了代码的平滑折叠,还是有小小的成就感嘀,呵呵(JQuery菜鸟,高手勿笑~)。但当局者迷,我并不知这样做是否真正增强了文章的可读性,欢迎读者朋友作出评论 :)

  这一个月,笔者真正决定在博客园扎下根来,于是花费了大量的课余时间在博文的写作上。初次写博,虽然评论很少,但大部分日志都有500以上的点击率,也算是对我的小小的鼓励!在博客园发表关于单片机的内容,的确需要勇气,不过我会坚持写下去的~

  从开始到现在的九篇博文,重点是CC2430芯片上的基本硬件模块的运用。到此为止,我们基本上把CC2430上的大部分外设都过了一遍,但是还有比如Flash存取、随机数发生器、AES协处理器、射频通信等,还没涉及到。不过Zigbee之旅并未结束,笔者打算在下一个主题(Z-Stack协议的实现)中,再来有选择性的把这些遗漏之处补齐。

  下一篇博文,笔者打算以一个稍带综合性与扩展性的小实验——“温度监测系统”来结束Zigbee的首次旅行,讲解一下如何去综合运用前面学到的知识点。

Zigbee之旅(九):几个重要的CC2430基础实验——系统睡眠及中断唤醒相关推荐

  1. Zigbee之旅(八):几个重要的CC2430基础实验——看门狗

    Zigbee之旅(八):几个重要的CC2430基础实验--看门狗 一.承上启下 再好的操作系统,不管是现在的Win7还是以后Win8.Win9,总会出现BlueScreen的时候,更何况是小小的单片机 ...

  2. 《ZigBee开发笔记》第五部分 外设篇 - 基础实验 第1章CC2530温度传感器DS18B20

    1 理论分析 1.1概述 DS18B20 是 DALLAS 最新单线数字温度传感器,新的"一线器件"体积更小.适用电压更宽.更经济.Dallas 半导体公司的数字化温度传感器 DS ...

  3. 嵌入式成长轨迹54 【Zigbee项目】【CC2430基础实验】【系统睡眠工作状态】

    本实验在小灯闪烁10 次以后进入低功耗模式 PM3 .CC2430 一共有4 种功耗模式,分别是PM0,PM1,PM2,PM3,以 PM3 功耗最低. SLEEP (0xBE) - Sleep mod ...

  4. 嵌入式成长轨迹53 【Zigbee项目】【CC2430基础实验】【串口时钟PC显示】

    void InitT1(void) : 函数原型: 1 void InitT1(void) 2 { 3 T1CCTL0 = 0X44; 4 //T1CCTL0 (0xE5) 5 //T1 ch0 中断 ...

  5. 嵌入式成长轨迹37 【Zigbee项目】【CC2430基础实验】【自动闪烁】

    最为简单的代码,只用到一个寄存器P1DIR.因为点亮的led灯(p1.0和p1.1)的管脚是p1的,要输出就得将这两个管脚设置为输出管脚.该寄存器用0~8对应1.0~1.8管脚. 1 //main.c ...

  6. 嵌入式成长轨迹52 【Zigbee项目】【CC2430基础实验】【在PC用串口收数并发数】...

    在PC上从串口向 CC2430发任意长度为 30 字节的字串,若长度不足 30 字节,则以"#"为字串末字节,CC2430在收到字节后会将这一字串从串口反向发向 PC,用串口助手可 ...

  7. 《ZigBee开发笔记》第五部分 外设篇 - 基础实验 第4章 CC2530热释电红外传感器

    1理论分析 HC-SR501人体红外感应模块 是基于红外线技术的自动控制产品.灵敏度高.可靠性强.超低功耗,超低电压工作模式.广泛应用于各类自动感应电器设备,尤其是干电池供电的自动控制产品. 2实验详 ...

  8. 《ZigBee开发笔记》第五部分 外设篇 - 基础实验 第2章 CC2530温湿度传感器DHT11

    1理论分析 1.1 DHT11 介绍 DHT11 数字温湿度传感器,如图所示,是一款含有已校准数字信号输出的温湿度复合传感器.它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓 ...

  9. 《ZigBee开发笔记》第五部分 外设篇 - 基础实验 第5章 CC2530继电器模块

    1理论分析 1.1概述 继电器(relay)是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器.它具有控制系统(又称输入回路)和被控制系统 ...

最新文章

  1. a*算法的时间复杂度_算法基础——时间复杂度amp;空间复杂度
  2. ECShop 增加收藏商品排行榜功能
  3. Jsp登录后数据采集---奇怪的Apache服务器
  4. mysql 排序后 下一条记录_Mysql如何使用order by工作
  5. 设置log缓存_全局变量、事件绑定、缓存爆炸?Node.js内存泄漏问题分析
  6. System Center 2012 R2 CM系列之Configuration Manager系统需求
  7. android代码删除wifi,Android Wifi的forget()操作实例详解_Android_脚本之家
  8. 【bzoj1433】[ZJOI2009]假期的宿舍
  9. 基于java在线问卷调查系统
  10. Python实现Eternal Night游戏(尚未完结,不断更新)
  11. scp登录The authenticity of host 192.168.0.xxx can't be established. 的问题
  12. meltdown linux检测,如何检查你的Linux PC是否受Meltdown和Spectre安全缺陷影响
  13. 各种芯片复位电路分析
  14. 解决Qt5.7.0 cannot find -lGL
  15. 中国电子学会-青少年电子信息等级考试标准 (1-6 级)
  16. ELK搭建毫秒级响应社工裤
  17. 数值分析——LU分解求解线性方程组的Python实现
  18. 古人秃了怎么办:一旦脱发,五大对策!
  19. Python地球科学领域应用:python处理遥感数据、站点数据、遥感水文数据、气候变化数据、WRF模式数据后处理、运行生态模型
  20. 黑金AX7350注意事项

热门文章

  1. mysql下载哪个_Mysql下载与版本选择
  2. matlb的四舍五入取整函数:round、fix、ceil、floor
  3. python面向对象:多继承及搜索顺序
  4. 8259a的相关知识
  5. raiserror的用法
  6. 5.4数据准备之抽样和权重计算
  7. 统一异常处理解决方案
  8. 《笔记本电脑关闭数字小键盘》
  9. three.js建立一个可交互的机房机柜
  10. 关于高德地图地理围栏生成后在BroadcastReceiver的onReceive方法中没有接收到消息的问题