休眠模式、看门狗、中断

  • 一、休眠模式
    • 睡眠中断的触发
  • 二、看门狗
    • 实例一
    • 实例二
  • 三、外部中断
    • 1.为什么需要中断?
    • 2.不关心功耗还需要中断吗?
    • 3.各种板子的中断
    • 4.中断函数、中断触发模式与设置中断
    • 5.例程

一、休眠模式

  Arduino睡眠模式也称为Arduino省电模式(Power Save mode)或Arduino待机模式(Standby Mode)。Arduino睡眠模式允许用户停止或关闭微控制器中未使用的模块,从而显着降低功耗。 Arduino UNO、Arduino Nano和Pro-mini配备了ATmega328P,它有一个欠压检测器(BOD),用于监控睡眠模式时的电源电压。
   ATmega328P有六种睡眠模式,要进入任何睡眠模式,我们需要在睡眠模式控制寄存器(SMCR.SE)中启用睡眠位。然后,睡眠模式选择位选择Idle、ADC noise reduction、Power-Down、Power-Save、Standby和External Standby的睡眠模式。在现实世界中,实际上只有一种模式很有用;掉电模式(SLEEP_MODE_PWR_DOWN)。
  内部或外部Arduino中断或复位可以将Arduino从睡眠模式唤醒。
  Arduino像电脑和手机一样,也具备睡眠/休眠/待机功能。在睡眠状态下,系统几乎完全停止运作,只保留基本的侦测功能,因此只消耗少许电力。以电脑为例,在睡眠状态下,可被键盘按键或者网络信息唤醒。

主要功能函数如下:

  #include <avr/sleep.h>//引用库文件  set_sleep_mode (SLEEP_MODE_PWR_DOWN);// 设置休眠模式  sleep_mode (); // 进入休眠状态

注意: sleep_mode 为宏指令,它会自动自动开启休眠功能、进入睡眠状态、禁用休眠功能。 按照官方解释,在某些条件下, sleep_mode 宏会导致个别操作步骤开启休眠功能并发出sleep指令进入休眠,所以,另外提供了以下三个指令来分步完成sleep_mode ()工作:

  sleep_enable();  // 开启休眠功能  sleep_cpu (); // 进入休眠状态  sleep_disable();//关闭休眠功能


也就是说,貌似使用sleep_mode会出现意外情况,所以,根据情况自己选择吧。

#include <avr/sleep.h>
void setup ()
{  set_sleep_mode (SLEEP_MODE_PWR_DOWN); // 采用“Power-down”睡眠模式 sleep_enable();// 启动睡眠模式 sleep_cpu ();  // 进入睡眠模式
}
void loop ()
{}

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

  微控器内部除了中央处理器(CPU),还有內存、模拟数位转换器、序列通信…等模块。越省电的模式,仍在运作中的模块就越少。
  例如,在”Power-Down”(电源关闭)睡眠模式之下,微控器仅剩下外部中断和看门狗定时器(Watchdog Timer)仍持续运作。而在Idle睡眠模式底下,SPI,UART(也就是序列端口)、定时器、模拟数位转换器等,仍持续运作,只有中央处理器和闪存(Flash)时脉信号被停止。时脉信号就像心跳一样,一旦停止时脉信号,相关的元件也随之暂停。

睡眠中断的触发

中断触发种类:

  1. 通过外部中断。只有在发生外部中断时才会唤醒。
  2. 通过UART(USB串行接口)。保持睡眠,直到通过串行接口收到数据。
  3. 通过一个内部计时器,将定期通过Timer1从睡眠中醒来,执行一个动作并返回到睡眠状态。
  4. 通过看门狗定时器。定期通过看门狗定时器从睡眠中醒来,执行一个动作并返回到睡眠状态。请注意使用Watchdog可以提供最长的睡眠时间和最低的功耗。

二、看门狗

  看门狗,又叫 watchdog timer,是一个定时器电路, 一般有一个输入,叫喂狗(kicking the dog or service the dog),一个输出到MCU的RST端,MCU正常工作的时候,每隔一端时间输出一个信号到喂狗端,给 WDT清零,如果超过规定的时间不喂狗(一般在程序跑飞时),WDT 定时超过,就会给出一个复位信号到MCU,是MCU复位,防止MCU死机。看门狗的作用就是防止程序发生死循环,或者说程序跑飞。出于对单片机运行状态进行实时监测的考虑,产生了一种专门用于监测单片机程序运行状态的芯片,俗称"看门狗"(watchdog)。
  看门狗定时器(WDT:Watch Dog Timer)实际上是一个计数器。一般给看门狗一个大数,程序开始运行后看门狗开始倒计数。如果程序运行正常,过一段时间CPU应该发出指令让看门狗复位,令其重新开始倒计数。如果看门狗计数减到0,就认为程序没有正常工作(因为没有及时复位),就强制整个系统复位(单片机重启)。
  所以,当你开启看门狗后,需要在看门狗超时(计数减到0)前,对其进行 喂狗(复位)操作,否则看门狗会强制你的单片机重启,从头运行程序。如果看门狗在休眠或空闲模式下超时,器件将唤醒并从PWRSAV指令执行处继续执行代码,同时“休眠”状态位(RCON< 3>)或“空闲”状态位(RCON< 2>)会置1,表示器件之前处于省电模式。
  功能作用:看门狗可以在你的程序陷入死循环的时候,让单片机复位而不用整个系统断电,从而保护你的硬件电路。

使用看门狗需要引用头文件 【 avr/wdt.h 】,在wdt.h中,提供了3个看门狗API:

wdt_enable(timeout) //看门狗启动,并设置超时时间
wdt_disable() //看门狗停止
wdt_reset() //看门狗复位(喂狗)

wdt_enable(timeout) 中timeout为超时时间,当超过这个时间后没有喂狗,则单片机重启。
这个时间可使用如下常量:

0=15(16)ms, 1=30(32)ms,2=60(64)ms,3=120(128)ms,4=250ms,5=500ms
6=1 sec,7=2 sec, 8=4 sec, 9= 8sec

使用看门狗很简单,只需要做下面三步即可:

1、引用头文件 #include avr/wdt.h
2、Setup函数中启动看门狗,并设置超时时间为两秒:wdt_enable(WDTO_2S);
3、Loop函数中喂狗,防止饿死(重启): wdt_reset();

代码如下:

#include <avr/wdt.h>
int ledPin = 13;
void setup()
{  pinMode(ledPin, OUTPUT);       wdt_enable(WDTO_2S);//启动看门狗,设置喂狗时间不能超过2秒
}
void loop()
{  digitalWrite(ledPin, HIGH);    delay(500);     digitalWrite(ledPin, LOW);    //喂狗。如果超过2S没有喂狗,则单片机重启。 也就是说,如果本循环执行时间超过2S的话,单片机就会自动重启。wdt_reset();
}

其它应用:
【利用看门狗进行休眠唤醒】
用下面的代码,代替wdt_enable(),并且不要喂狗。
这样就实现了看门狗超时后,执行唤醒函数,而不是重启单片机。

void wdt_setup(int ii)
{// ii为看门狗超时时间,支持以下数值:// 0=16毫秒, 1=32毫秒,2=64毫秒,3=128毫秒,4=250毫秒,5=500毫秒// 6=1秒 ,7=2秒, 8=4秒, 9=8秒byte bb;if (ii > 9 ) ii = 9;bb = ii & 7;if (ii > 7) bb |= (1 << 5);bb |= (1 << WDCE);//开始设置看门狗中断   MCUSR &= ~(1<<WDRF);  //清除复位标志WDTCSR |= (1<<WDCE) | (1<<WDE);//设置新的看门狗超时时间WDTCSR = bb;//设置为定时中断而不是复位WDTCSR |= _BV(WDIE); //别忘了设置【看门狗唤醒执行函数】
}

看门狗唤醒执行函数:

ISR(WDT_vect)
{//唤醒后执行的代码
}

实例一

测试代码如下:

#include <avr/wdt.h>
#include <avr/sleep.h>
int ledPin = 13;
int data=0;ISR(WDT_vect)
{//看门狗唤醒执行函数data++;
}void setup()
{  pinMode(ledPin, OUTPUT);   set_sleep_mode(SLEEP_MODE_PWR_DOWN); //设置休眠模式。sleep_enable(); //开启休眠功能。//ACSR |=_BV(ACD);//关掉ACD,据说很省电。不知道唤醒以后要不要重新开,怎么开?//ADCSRA=0;//关掉ADC,据说很省电。不知道唤醒以后要不要重新开,怎么开?//按照官方解释,sleep_enable()最好写在中断(attachInterrupt())前,防止中断在开始休眠前就提前释放而造成休眠后无法唤醒。//开始设置看门狗中断,用来唤醒。   MCUSR &= ~(1<<WDRF);WDTCSR |= (1<<WDCE) | (1<<WDE);WDTCSR = 1<<WDP1 | 1<<WDP2;WDTCSR |= _BV(WDIE);
}  void loop()
{  if (data>=5){digitalWrite(ledPin, HIGH);    delay(500);     digitalWrite(ledPin, LOW);    data=0;}sleep_cpu();//进入休眠状态,从此处开始进入休眠。这里不需要喂狗。目的就是等狗超时后执行唤醒函数。
}

本实验程序的行为如下:
1.启动时,每隔0.5秒点、灭三次位于第13脚的LED。
2.LED闪烁完毕后,进入“Power-down(断电)”睡眠模式,5秒之后又开始闪烁一次。

实例二

测试代码如下:

#include <avr/wdt.h>
#include <avr/sleep.h>
int ledPin = 13;
int data=0;ISR(WDT_vect)
{//看门狗唤醒执行函数data++;
}
void setup()
{  pinMode(ledPin, OUTPUT);   set_sleep_mode(SLEEP_MODE_PWR_DOWN); //设置休眠模式。sleep_enable(); //开启休眠功能。//ACSR |=_BV(ACD);//关掉ACD,据说很省电。不知道唤醒以后要不要重新开,怎么开?//ADCSRA=0;//关掉ADC,据说很省电。不知道唤醒以后要不要重新开,怎么开?//按照官方解释,sleep_enable()最好写在中断(attachInterrupt())前,防止中断在开始休眠前就提前释放而造成休眠后无法唤醒。//开始设置看门狗中断,用来唤醒。   MCUSR &= ~(1<<WDRF);WDTCSR |= (1<<WDCE) | (1<<WDE);WDTCSR = 1<<WDP1 | 1<<WDP2;WDTCSR |= _BV(WDIE);
}
void loop()
{  if (data>=5){digitalWrite(ledPin, HIGH);    delay(500);     digitalWrite(ledPin, LOW);    data=0;}sleep_cpu();//进入休眠状态,从此处开始进入休眠。这里不需要喂狗。目的就是等狗超时后执行唤醒函数。
}

或者代码可以如下:

#include <avr/wdt.h>
#include <avr/sleep.h>
int ledPin = 13;
int data=0;ISR(WDT_vect)
{//看门狗唤醒执行函数data++;
}
void setup()
{  pinMode(ledPin, OUTPUT);   set_sleep_mode(SLEEP_MODE_PWR_DOWN); //设置休眠模式。//开始设置看门狗中断,用来唤醒。   MCUSR &= ~(1<<WDRF);WDTCSR |= (1<<WDCE) | (1<<WDE);WDTCSR = 1<<WDP1 | 1<<WDP2;WDTCSR |= _BV(WDIE);
}  void loop()
{  if (data>=5){digitalWrite(ledPin, HIGH);    delay(500);     digitalWrite(ledPin, LOW);    data=0;}sleep_mode(); //进入休眠状态,从此处开始进入休眠。这里不需要喂狗。目的就是等狗超时后执行唤醒函数。
}

三、外部中断

1.为什么需要中断?

  因为没有中断,你不能让你的Arduino进入睡眠状态,并期望它再次唤醒(一般来说,在有限的情况下,有办法在没有中断的情况下从睡眠中唤醒)。如果你不能入睡,一直工作你的能量很快就会消耗殆尽。睡眠模式消耗的功率非常小,但需要特别设置。你必须知道的第一件事是如何编写代码来利用中断,然后你可以使用更强大的技术。

2.不关心功耗还需要中断吗?

  是! 即使你不打算让处理器进入睡眠状态,也可能需要中断!如果您有一个与时间相关的应用,如需要每间隔几毫秒发生一次操作,或者需要在发生外部事件后立即发生操作,这是中断就会至关重要。如果你熟悉Arduino编程的基础知识,你可能会想知道为什么你不能只用一个简单的while循环来检查什么时候执行你的动作。简单的while循环是可以按顺序读取每个引脚的状态,但这种方法并不可靠。如果只简单的应用while循环来检查按钮的轮询的话,你的while循环再次检查按钮状态之前,该按钮是否已经被按下并释放?你会错过按钮按下。如果您正在寻找一个非常快速的事件,例如来自传感器的信号,因为害怕错过关键事件,你必须经常进行轮训,从而导致你的程序无法做任何其他事情。但是有了中断,你100%保证能够赶上事件。使用中断还可以使您不必经常检查状态,从而节省计算能力,并让while循环更快地完成其他任务。
  试想一下,你正在家里吃饭,这时传来了敲门声,虽然你巨饿,虽然面前全是山珍海味,但此时你不得不去开门,同时不得不放停下生命中最重要的事情——吃饭。打开门后,你发现只是一个查水表的,你检查了水表读数并告诉了查水表的人。关上门,你马不停蹄的又投入了于食物的作战中。
  我们来分析一下这个颇具传奇性的故事,在这里人生的主旋律——吃饭,就是你的主程序,而敲门声,就是一个中断信号,它让你不得不去执行你的人生插曲——开门接客这个中断函数。完成这个小插曲后,你又要投入到主线剧情 吃饭这个主程序上。
  现在我想告诉你一个惊天秘密,其实你妈欺骗了你,你根本不是他们亲生的,你是人造人,而你的大脑里装备了一个arduino控制器!你的型号是 Arduino 吃货,之所以叫这么2的名字,是因为你的loop的写法问题。我们来看看你的loop函数。

void loop()
{吃();
}
//吃,是的,你没有看错,你的人生是如此的幸福,就是不断的 吃();循环。
//但实际上,你还有附加功能 开门();
void 开门()
{打开门;
if(门口的人==女神)跪舔();
if(门口的人==查水表的)报告水表读数();
}

  为了让你能顺利执行 开门();动作,你的亲生父母还得在Setup函数中设置 开门();这个动作何时启动。具体的方法是attachInterrupt(中断通道, 中断函数, 触发方式); 在这里中断通道就是你的耳朵(不要问为什么不是屁股),触发 开门();这个函数的方式是敲门声。

void setup()
{attachInterrupt(耳朵, 开门, 敲门声);
}

  这样设定后,你每次听到敲门声,就不得不去打开门,并执行相应的动作了。也许你对这样的人物设定不太满意,但这就是你的宿命,少年。忘记你蛋碎的屌丝设定吧,我们要开始严肃的讨论问题了!

3.各种板子的中断

UNO、NANO、ProMINI这仨板子都是INT0 (D2针脚:中断编号为0)、INT1(D3针脚:中断编号为1)。

4.中断函数、中断触发模式与设置中断

【中断函数】:就是你要去执行的函数,这个函数不能带任何参数,且没有返回类型。如:

void hello()
{Serial.println("hello");
}

【中断模式】:就是你的中断触发方式。在大多数arduino上有以下四种触发方式

LOW                  低电平触发
CHANGE            电平变化,高电平变低电平、低电平变高电平
RISING              上升沿触发
FALLING           下降沿触发
HIGH                高电平触发(该中断模式仅适用于Arduino due)

【设置中断】:在定义中断函数后,要使用外部中断,你只需要在程序的Setup部分配置好中断函数即可,配置函数如下:

attachInterrupt(interrupt, function, mode);
//interrupt为你中断通道编号,function为中断函数,mode为中断触发模式
需要注意的是在Arduino Due中,中断设置有点不同:
attachInterrupt(pin, function, mode);
//due 的每个IO均可以进行外部中断,所以这里第一个参数为pin,即你使用的引脚编号。
//如果在程序中途,你不需要使用外部中断了,你可以用中断分离函数来取消这一中断设置:detachInterrupt(interrupt);
同样在Arduino Due上,该函数为detachInterrupt(Pin);。

5.例程

外部中断的使用也是非常简单的,下面我们来看一个官方提供的例程

volatile int state = 0;
void setup()
{pinMode(13, OUTPUT);attachInterrupt(0, blink, CHANGE);//当int.0电平改变时,触发中断函数led
}
void loop()
{digitalWrite(13, state);
}
void led()//中断函数
{state = !state;
}

应用:利用外部中断,可以在很多地方提高你程序的运行效率。你可以运用以上知识,做一个简单的监控装置。

Arduino休眠模式和看门狗以及中断详解相关推荐

  1. linux内核看门狗关闭方法,详解linux 看门狗驱动编写

    看门狗是linux驱动的一个重要环节.某些特殊的设备,有时候需要放在一些环境恶劣的地方,比如电信设备.但是,任何软件都不可能100%没有bug.如何保证软件在遇到严重bug.死机的时候也能正常运行呢, ...

  2. STM32 待机模式与看门狗和谐相处

    由于在standby mode,看门狗仍然能继续工作,但是其他时钟都关闭了,没法喂狗,这样会导致mcu不停复位.网上找的方法如下:1. 开启RTC,定期喂狗后再次睡眠.该方法视乎可行,但是不够省电. ...

  3. Exynos 4412 看门狗定时器中断

    如果想弄懂看门狗定时器中断,要掌握下面两个知识点: 1 懂寄存器 Cortex A9采用的是ARM官方规定的中断处理机制 有两大类寄存器决定了中断工作状态 1) exynos 4412 特有的寄存器( ...

  4. STC15W系列单片机休眠唤醒与看门狗配置问题

    STC15W系列单片机休眠唤醒与看门狗配置问题 关于STC单片机之定时器唤醒与看门狗寄存器配置 硬件看门狗 硬件看门狗配置 主程序参考配置 本次是记录自己在STC单片机低功耗模式下使用过程中遇到的一些 ...

  5. Arduino框架下 ESP32看门狗使用示例

    Arduino框架下 ESP32看门狗使用示例 相关篇<Arduino ESP32 看门狗定时器> 开发板型号为:ESP32 DEVKIT V1-DOIT 板载led灯 GPIO 2 -- ...

  6. linux内核中断详解

    linux内核中断详解 1.中断的硬件触发流程 外设:如果外设有操作或者有数据可用,那么就会产生一个电信号,这个电信号发送给中断控制器. 中断控制器:中断控制器接收到外设发来的电信号以后,进行进一步的 ...

  7. 工程之星android版使用,安卓版工程之星软件网络1+1模式及网络cors连接操作详解...

    原标题:安卓版工程之星软件网络1+1模式及网络cors连接操作详解 现在,越来越多用户开始使用安卓版工程之星进行作业,科力达技术工程师总结了安卓版工程之星网络1+1模式及网络CORS连接方式操作步骤, ...

  8. java 配置jmstemplate_SpringBoot集成JmsTemplate(队列模式和主题模式)及xml和JavaConfig配置详解...

    1.导入jar包: org.springframework.boot spring-boot-starter-activemq org.apache.activemq activemq-pool 2. ...

  9. 命令行模式下几个网络命令详解

    命令行模式下几个网络命令详解 上一篇 / 下一篇  2007-05-16 16:20:55 查看( 166 ) / 评论( 0 ) / 评分( 0 / 0 ) 命令行模式下几个网络命令详解 一.pin ...

最新文章

  1. 投资计算机方面的策略构建,金融投资简单的策略分享和构建策略的基本思路
  2. Dart 7-Day
  3. Linux保护文件实现,Linux完整性保护机制模块实现分析(1)
  4. TokenInsight:BTC链上活跃度保持上行,新增人气处历史高位
  5. 如何理解和使用Java package包
  6. 收集Tomcat异常日志并发送邮件
  7. 商业计划书模板(高质量)
  8. CCS安装教程——学习DSP的第一步
  9. 振耀退休感言及海辉执行董事长视频访谈
  10. EMC设计经典15问
  11. 2019北航计科保研夏令营(非优营)
  12. 前端40+精选VSCode插件
  13. Git和Mercurial(Hg)的分析
  14. 中国农场可变利率技术(VRT)行业市场供需与战略研究报告
  15. 由硫化铅/硒化物和碲化物(PbX:PbS,PbSe和PbTe)制成的QD钙钛矿量子点
  16. 【Mac】Mac电脑充电小板、充电器不亮或者接触不良、发黑、针头缩进
  17. nrf52832学习笔记(3)设置发射功率
  18. 第十六章、文件服务器之二: SAMBA 服务器
  19. 2022暑期学校C++课程设计课题
  20. 找出Windows 2003识别不了的移动硬盘

热门文章

  1. 一键如何完成多张静态图合成GIF图?
  2. SpringBoot-AOP环绕通知记录日志/鉴权
  3. IT农民工如何来美国工作
  4. [Step By Step]SAP HANA中创建分析视图(Analytic View)
  5. 牛客网 |复数集合( 北邮往年复试题)
  6. CoCa-GAN阅读笔记
  7. Redis存储结构探究
  8. Python基础灬文件常用操作
  9. conda install安装python库失败:PackagesNotFoundError: The following packages are not available from curren
  10. JAVA面试题100道一