极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 119027|回复: 40

转:认识与实验Arduino的睡眠模式

  [复制链接]
发表于 2014-2-25 14:03:58 | 显示全部楼层 |阅读模式
本帖最后由 Cupid 于 2014-2-25 14:03 编辑

原文引自:http://swf.com.tw/?p=525

根据Nick Gammon这位澳洲老兄,在Power saving techniques for microprocessors(微处理器省电技术)文章,於Arduino UNO Rev 3控制板执行底下的程式码:

  1. void setup () {}
  2. void loop () {}
复制代码


所测量到的消耗电流量:

  • 採用9V电池,接电源插孔供电,约消耗55 mA
  • 用5V电源供电,约消耗46.6 mA


若用最精简的準系统(barebone)形式,例如,在麵包板上直接用ATmega828处理器和石英震盪器等少数零件组装的Arduino,仅消耗15.15 mA电流。

因為Arduino控制板上的USB序列埠转换晶片以及电压调节元件,都会消耗电力。

毕竟Arduino控制板是「原型开发板」,其用意是提供一个方便、好用的微电脑控制实验工具。实验成功之后,如果要长久保留作品或者需要节省电力,最好自製一个精简的Arduino板,或购买类似Arduino Pro Mini这种没有其他周边零件的板子。

Arduino的睡眠模式

Arduino像电脑和手机一样,也具备睡眠∕休眠∕待机功能。在睡眠状态下,系统几乎完全停止运作,只保留基本的侦测功能,因此只消耗少许电力。以电脑為例,在睡眠状态下,可被键盘按键或者网路讯息唤醒。

底下的程式一开始就让微控器进入睡眠状态,下文将採用名叫”Enerlib”的程式库,简化睡眠设定程式:

  1. void setup ()
  2. {
  3.   // 設定採用“Power-down”睡眠模式
  4.   set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  5.   // 啟用睡眠模式
  6.   sleep_enable();
  7.   // 進入睡眠模式
  8.   sleep_cpu ();  
  9. }

  10. void loop () { }
复制代码


这段程式在UNO R3控制板上,约消耗32.9 mA电流;但是在精简的「準系统」Arduino板,仅仅消耗0.36mA (360μA)。

ATMega328微控器具有六种睡眠模式,底下是依照「省电情况」排列的睡眠模式名称,以及Enerlib(註:Energy和Library,即:「能源」和「程式库」的缩写)程式库的五道函数指令对照表,排越后面越省电。「消耗电流」栏位指的是ATmega328处理器本身,而非整个控制板。

睡眠模式 Energy指令 中文直译 消耗电流
Idle Idle() 閒置 15mA
ADC Noise Reduction SleepADC() 类比数位转换器降低杂讯 6.5mA
Power-save PowerSave() 省电 1.62mA
Standby Standby() 待机 1.62mA
Extended Standby 延长待机 0.84mA
Power-down PowerDown() 断电 0.36mA


微控器内部除了中央处理器(CPU), 还有记忆体、类比数位转换器、序列通讯…等模组。越省电的模式,仍在运作中的模组就越少。

例如,在”Power-Down”(电源关闭)睡眠模式之下,微控器仅剩下外部中断和看门狗计时器(Watchdog Timer, 参阅下文说明)仍持续运作。而在Idle睡眠模式底下,SPI, UART(也就是序列埠)、计时器、类比数位转换器等,仍持续运作,只有中央处理器和快闪记忆体(Flash)时脉讯号被停止。

时脉讯号就像心跳一样,一旦停止时脉讯号,相关的元件也随之暂停。各种睡眠模式的详细说明,请参阅ATmega328微控器的资料手册,第39页,「Power Management and Sleep Modes(电源管理与睡眠模式)」单元。

採用Enerlib程式庫設定睡眠模式

Enerlib程式库可简化Arduino睡眠模式的程式设定,请先下载Enerlib程式库并解压缩到Arduino的libraries资料夹:


本实验程式的行为如下:

  • 启动时,每隔0.5秒点、灭三次位于第13脚的LED。
  •     LED闪烁完毕后,进入“Power-down(断电)”睡眠模式。
  •     当中断0(第2脚)的讯号改变时,唤醒Arduino,再次闪烁LED三次,接著再进入睡眠模式。


请先把Arduino的数位脚2接高电位(5V或3.3V插座):



反覆闪烁LED的基本程式码如下:

  1. void setup() {
  2.   Serial.begin(9600);

  3.   pinMode(ledPin, OUTPUT);
  4.   
  5.   Serial.println("Running...");
  6. }

  7. void loop() {
  8.   digitalWrite(ledPin, !digitalRead(ledPin));
  9.   delay(500);
  10. }
复制代码


负责闪烁LED的关键叙述是这一行:



设定唤醒Arduino的中断服务常式

修改上一节的程式,建立Energy程式物件,并加入中断服务常式叙述(广告一下,中断服务常式的说明,请参阅《超图解Arduino互动设计入门》的D-3页):


若Arduino处于睡眠状态,只要中断0脚位的讯号改变,它就会被唤醒。然而,同一个程式其他叙述,也有可能需要接收中断0的讯息。为此,Energy提供一个用于判断Arduino是否处于睡眠状态的WasSleep()函数,若是,它将传回true。

底下是修改后的wakeISR中断处理常式,若Arduino之前处于睡眠状态,则state变数值将是1,若是在执行过程发生中断讯号,state值将是2:



透过state值,主程式将能得知中断的触发时机。补充说明,WasSleep()函数只能写在中断处理常式裡面。

让Arduino睡眠的主程式

主程式迴圈如下,它将在闪烁LED三次后进入最省电的「断电」睡眠模式:



完整的范例程式码如下:

  1. #include <Enerlib.h>

  2. Energy energy;             // 宣告"Energy"程式物件

  3. const byte swPin = 2;      // 開關腳位
  4. const byte ledPin = 13;    // LED腳位
  5. byte times = 0;            // 記錄執行次數
  6. volatile byte state = 0;   // 暫存執行狀態

  7. void wakeISR() {
  8.    if (energy.WasSleeping()) {
  9.     state = 1;
  10.   } else {
  11.     state = 2;
  12.   }
  13. }

  14. void setup() {
  15.   Serial.begin(9600);

  16.   pinMode(ledPin, OUTPUT);
  17.   pinMode(swPin, INPUT);
  18.   digitalWrite(swPin, HIGH);

  19.   attachInterrupt(0, wakeISR, CHANGE);  // 附加中斷服務常式
  20.   
  21.   Serial.println("Running...");
  22. }

  23. void loop()
  24. {
  25.   if (state == 1) {
  26.     Serial.println("Was sleeping...");
  27.   } else if (state == 2) {
  28.     Serial.println("Was awake...");
  29.   }
  30.   state = 0;
  31.   
  32.   digitalWrite(ledPin, !digitalRead(ledPin));
  33.   delay(500);
  34.   times ++;
  35.   Serial.println(times);

  36.   if (times > 5) {
  37.     times = 0;
  38.     Serial.println("Go to sleep...");
  39.     energy.PowerDown();
  40.   }
  41. }
复制代码


编译并上传程式到Arduino板之后,开启「序列埠监控视窗」,它将显示:



接著,把连接中断0的导线接到低电位(GND):



Arduino将被唤醒,并再次闪烁LED;笔者在LED闪烁的过程中,反覆将中断0接高、低电位,「序列埠监控视窗」因而呈现如下的内容:


看门狗计时器简介

看门狗计时器(Watchdog Timer, 简称WDT)是微控器内部的「当机」监控器,若微控器当掉了,它会自动重新启动微控器。其运作原理是,看门狗内部有个计时器,微处理器必须每隔一段时间,向看门狗发出一个讯号,重设计时器值。



若看门狗迟迟没有收到微处理器的讯号,计时器仍将继续倒数,直到计时值变成零,它就会认定微处理器已经当掉了,进而重新启动微处理器。

主程式可设定看门狗的计时器值,最短16ms,最长8s。Donal Morrissey写了一篇看门狗程式的介绍,以及沉睡8秒之后,切换LED状态的范例:Sleeping Arduino – Part 5 Wake Up Via The Watchdog Timer

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

参与人数 1 +1 收起 理由
幻生幻灭 + 1 赞一个!

查看全部评分

回复

使用道具 举报

发表于 2014-2-25 14:18:18 | 显示全部楼层
谢谢分享,请问有没有用定时器唤醒的例子,就是隔断时间唤醒一次,不用外部中断?
回复 支持 反对

使用道具 举报

发表于 2014-2-25 14:26:24 | 显示全部楼层
非常好的帖子,谢谢分享
回复 支持 反对

使用道具 举报

发表于 2014-2-25 14:54:58 | 显示全部楼层
本帖最后由 shihaipeng04 于 2014-2-25 14:56 编辑

swf.com.tw 发现亮点了。哈哈
回复 支持 反对

使用道具 举报

发表于 2014-2-25 15:08:38 | 显示全部楼层
這是書裡的內容~.~
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-2-25 15:26:14 | 显示全部楼层
隨風大俠 发表于 2014-2-25 15:08
這是書裡的內容~.~

这本书在哪儿能买到?
回复 支持 反对

使用道具 举报

发表于 2014-2-25 15:33:52 | 显示全部楼层
Cupid 发表于 2014-2-25 15:26
这本书在哪儿能买到?

這是台灣的書~不知道你們那裡有沒有賣。
回复 支持 反对

使用道具 举报

发表于 2014-2-25 17:07:03 | 显示全部楼层
有一个问题,不知道这样反复休眠会不会导致系统的不稳定?

pc的话,反复进入 s1 s3后面一定会有问题的。
回复 支持 反对

使用道具 举报

发表于 2014-2-25 22:29:26 | 显示全部楼层
好贴, 谢谢分享.     
回复 支持 反对

使用道具 举报

发表于 2014-2-25 22:48:52 | 显示全部楼层
感谢分享。内容非常精彩!!!!!
回复 支持 反对

使用道具 举报

发表于 2014-3-16 13:18:06 | 显示全部楼层
感谢分享,收藏了
回复 支持 反对

使用道具 举报

发表于 2014-5-1 10:19:14 | 显示全部楼层
一定支持~!
是有意义的内容,对设计实际项目有参考价值。
谢谢分享。
回复 支持 反对

使用道具 举报

发表于 2014-5-27 17:26:24 | 显示全部楼层
不错的文章
回复 支持 反对

使用道具 举报

发表于 2014-5-27 19:23:07 来自手机 | 显示全部楼层
好文章,这库对我用途很大!
回复 支持 反对

使用道具 举报

发表于 2014-5-29 11:21:16 | 显示全部楼层
好帖子,好好学习,谢谢了!
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-20 12:53 , Processed in 0.044007 second(s), 31 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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