请选择 进入手机版 | 继续访问电脑版

智能创客,中国最大的极客空间,智能平台,免费教学,视频教程,手把手教你创造儿时梦想!

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 3830|回复: 46

Zigbee之旅(九):几个重要的CC2430基础实验——系统睡眠...

  [复制链接]

110

主题

396

帖子

2321

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2321
QQ
发表于 2014-2-9 10:43:07 | 显示全部楼层 |阅读模式
一、承上启下

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

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

2011030113230664.jpg

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

2011030220203113.png   

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

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

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


(2)程序流程图

2011030219492131.png

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


(3)实验源码及剖析(下面的框框是可以点的~
头文件及宏定义
/*
    实验说明:中断唤醒睡眠实验,分别介绍三种睡眠模式下的唤醒
*/

#include
<ioCC2430.h>
#define LED_ON  0
#define LED_OFF 1
#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.768kHz24位定时器,当系统运行在除了PM3之外的所有的电源模式下,睡眠定时器都会不间断运行

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

2011030221165167.jpg

2011030221173526.jpg

2011030221175240.jpg

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

  :用于读取当前定时器的计数值,读的顺序必须遵循:读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的首次旅行,讲解一下如何去综合运用前面学到的知识点。

  其实根本没有资格称“讲解”,作为一个初学者,笔者只希望在写博的过程中与读者互勉,共同进步!


回复

使用道具 举报

0

主题

23

帖子

81

积分

注册会员

Rank: 2

积分
81
发表于 2014-8-9 04:04:33 | 显示全部楼层
不回不行了,因为楼猪太有才了。












八年信誉圣龙虎威传奇 www.zhuiyihw.com 真实开区八年
回复 支持 反对

使用道具 举报

0

主题

1

帖子

36

积分

新手上路

Rank: 1

积分
36
发表于 2014-9-19 19:47:59 | 显示全部楼层
谢谢了饿~~~~~~~












回复 支持 反对

使用道具 举报

0

主题

6

帖子

25

积分

新手上路

Rank: 1

积分
25
发表于 2014-9-20 04:33:54 | 显示全部楼层
回帖是必须的,这个可以有!












同心母婴 www.tx-kids.com
回复 支持 反对

使用道具 举报

0

主题

9

帖子

42

积分

禁止发言

积分
42
发表于 2015-6-26 18:00:52 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

0

主题

9

帖子

38

积分

禁止发言

积分
38
发表于 2015-7-4 21:12:01 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

0

主题

25

帖子

78

积分

注册会员

Rank: 2

积分
78
发表于 2015-9-30 23:57:39 | 显示全部楼层
我也来看了,很不错,收藏了












回复 支持 反对

使用道具 举报

0

主题

2

帖子

32

积分

新手上路

Rank: 1

积分
32
发表于 2015-10-28 06:45:01 | 显示全部楼层
水平很高啊,值得学习
回复 支持 反对

使用道具 举报

0

主题

152

帖子

384

积分

禁止发言

积分
384
发表于 2015-10-30 19:34:07 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

0

主题

14

帖子

52

积分

注册会员

Rank: 2

积分
52
发表于 2015-11-8 08:11:23 | 显示全部楼层
好帖,确实好帖!












佐尚网
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|小黑屋|手机版|智能创客 ( 桂ICP备14000828号

GMT+8, 2019-3-27 00:21 , Processed in 0.076990 second(s), 30 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表