mxlslf 发表于 2021-2-23 21:48:25

Arduino省电模式下看门狗中断的奇怪现象分析

做了一个单片机控制音乐播放的闹钟,闹钟在整点与半点时会按照设定的音乐播放。
晚上忽然想到在电池供电时,如何达到省电的效果,使电池的使用时间更长。
查找了网络,受网上《Arduino休眠模式和看门狗以及中断详解》的启发,对主程序进行了休眠模式改进,程序如下:
原程序出处:https://blog.csdn.net/qq_39400113/article/details/107536805

#include <avr/wdt.h>
#include <avr/sleep.h>
int ledPin = 13;
int data=0;

ISR(WDT_vect)
{
//看门狗唤醒执行函数1重启看门狗
data++;
}
void setup()
{
Serial.begin(9600);
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()
{
   Serial.println("1");    //串口输出主程序开始

if (data>=5)
{
    digitalWrite(ledPin, HIGH);   
    delay(500);   
    digitalWrite(ledPin, LOW);
    delay(500);   
    data=0;
    Serial.println("2");   //5秒进入if程序,串口输出:2
}
    Serial.println("3");    //串口输出主程序结束   
sleep_cpu();//进入休眠状态,从此处开始进入休眠。这里不需要喂狗。目的就是等狗超时后执行唤醒函数。

}


发现了如下的奇怪现象,如下视频所示:
1. sleep_cpu();执行后程序开始进入休眠,sleep_cpu休眠时间1秒钟:进入休眠后,主程序不执行。
2. 可以从没有执行 Serial.println("1");Serial.println("3"); 观察到主程序没有执行。
3. 但是当5秒钟时,进入if程序里面,此时pin13管脚的Led灯闪,伴随连续输出4组 1 3 1 3 1 3 1 3.

一开始我非常纳闷,if语句中并没有Serial.println("1");Serial.println("3"); 为什么会在进入if后连续输出4组 1 3 1 3 1 3 1 3.
仔细研究后发现:在if程序执行后,LED灯灭掉,TX灯亮,但是串口没有接收到数据。
分析后我认为:sleep_cpu();执行后程序开始进入休眠,休眠后主程序停止。当1秒钟后看门狗溢出,主程序执行,每次单片机会向串口缓存存入1组“1”“3”.这样经过4次溢出,就会存入4组“1”“3”,但是这4组数据都会在单片机缓存内,并不会输出,因为主程序执行速度太快了,串口还没来得及输出,就执行器sleep_cpu()进入了休眠模式。只有当5秒后进入if语句,此时有大量时间可以让串口输出,串口就一下子把所有的数据都吐出来了。

同学们一起来分析分析

弘毅 发表于 2021-2-24 19:12:17

串口输出没有加一点延时确实可能是处于奇怪工作状态,可以尝试的1,3输出前或者后加一点延时。
页: [1]
查看完整版本: Arduino省电模式下看门狗中断的奇怪现象分析