xiaoliumonitor 发表于 2015-5-2 11:21:54

arduino uno 如何判断重启类型

#include<avr/wdt.h>

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.print("setup__");
Serial.println(MCUSR);
if(MCUSR&0x08)
{
    pinMode(13,OUTPUT);
    digitalWrite(13,HIGH);
//do something else
}
wdt_enable (WDTO_4S);

}

void loop() {
// put your main code here, to run repeatedly:
MCUSR=8;
Serial.print("loop__");
Serial.println(MCUSR);
//wdt_reset();
delay(5000);

}

opti版本的bootloader,看门狗重启后无法读取mcusr寄存器的值,即使给它赋值也不行。熔丝位中的看门狗未开启。不考虑看门狗中断,只需要复位后能判断出是看门狗导致的复位,arduino如何实现呢?谢谢

tsaiwn 发表于 2015-5-2 19:16:45

如果你是要分辨 Power On Cold Start vs. WDT reset
可以这样: (偷放一串字符串在 RAM 检查是否 Cold start)


// Coldstart vs. Not cold start
#include <Arduino.h>
#include <string.h>
const char SECRET[ ] PROGMEM = "Hey 168ggYouSecLaLa";// 特殊字符串
boolean cold = false;
void checkCold( ) {
static char*p;
p = (char*)malloc( sizeof(SECRET) );
cold = true;// assume NOT cold start
if(strcmp(p,(char*)SECRET) == 0 ) cold = false;// 0 是字符串相等
if(cold)memcpy(p, SECRET, sizeof(SECRET));
} // checkCold(
void setup( ) {
Serial.begin(9600);
checkCold( );
if(cold) Serial.println("Power On start--Cold start");
else Serial.println("WDT reset or other Reset ..");
//...
}
void loop( ) {
//..
}


如果是要分辨 WDT Reset vs. 一般 Reset, 那我也不知道:(

林定祥 发表于 2015-5-2 21:02:53

tsaiwn 发表于 2015-5-2 19:16 static/image/common/back.gif
如果你是要分辨 Power On Cold Start vs. WDT reset
可以这样: (偷放一串字符串在 RAM 检查是否 Cold star ...

应该各种复位有优先顺序的

xiaoliumonitor 发表于 2015-5-2 23:20:41

谢谢
刚才实验了下程序   

cold = true;// assume NOT cold start 这条赋值语句与注释好像有些问题
我这里实验后即使冷启(直接reset接GND或拔电),程序打印的还是WDT reset or other Reset ..


前几天下雨打闪电,arduino板(有实时时钟数据写sd卡功能)“死机”,SD卡文件未能记录“死机”后的所需数据。未下雨时,arduino板可长时间工作。于是要加入看门狗,转而又想明白一下是看门狗复位了,还是其它的。


tsaiwn 发表于 2015-5-3 01:54:50

xiaoliumonitor 发表于 2015-5-2 23:20 static/image/common/back.gif
谢谢
刚才实验了下程序   




我这里说的冷启动是指把供电拔掉
因这时 RAM 才是乱的
至于你 RESET 或是 WDT Reset 则 RAM 都还在,
所以我才说我也不知道如何区别 RESET vs. WDT Reset
不过忽然想到
我之前说的方法无法用 Serial.print 看出来
因为要查看串口必须开启串口监视器Serial Monitor
可是根据手册说法, 一旦开启Serial Monitor 就会自动对板子 Reset
所以这时已经不是 Cold Start 而是 Warm Start 了
就是说当我们从串口监视器看到信息
其实 Arduino IDE 已经对 arduino 板做了 RESET
何况如果把 USB 线拔掉, COM? 可能变不见又得把串口监视器关闭并RESET...
所以只能说那方法确实可辨认是否刚冷启动, 但无法用串口验证 :(
也许可以改为闪烁不同 LED 来验证 !
关于 WDT Reset,
也许你可以参看这篇:

   https://ariverpad.wordpress.com/2012/02/26/resetting-the-arduino-through-software-for-fun-and-profit/

xiaoliumonitor 发表于 2015-5-3 10:24:00

点击arduino串口按钮时,13脚灯频闪一下,证明已重启(如您所说),并且是从boot区启动,bootloader程序肯定已执行。
发帖前我也尝试把贴中所有Serial语句注释掉,13脚的灯也并未亮起,此时的MCUSR的值应该还是为0.
看了下optibootloader程序(安装于1.0.5版本中)有
void appStart() {
watchdogConfig(WATCHDOG_OFF);
.....
相关内容,好像是在bootloader启动时关了一下看门狗。

在arduino环境下,如何区分wdt或是bod重启(或是其他)?暂时还是没搞清。有时间了我再试下avr下(不带bootloader)的重启。arduino蛮厉害,MCUSR已赋值(328PDF里明确注明可以赋值),就是打印不出来。
谢谢


tsaiwn 发表于 2015-5-4 12:56:22

xiaoliumonitor 发表于 2015-5-3 10:24 static/image/common/back.gif
点击arduino串口按钮时,13脚灯频闪一下,证明已重启(如您所说),并且是从boot区启动,bootloader程序肯定 ...

根据手册
要查看MCUSR 的 EXTRF 这 bit 是否被 set 就可知道是否看门狗引起的:
    if( (MCUSR&(1 << EXTRF) ) != 0) {
         // 外部 RESET
    }else{
      // 看门狗引起的
    } // if..else..

但是, MCUSR 貌似会被 Bootloader 设定为 0
你可以看看你 IDE 内的 bootloader:
   hardware\arduino\bootloaders\atmega\ATmegaBOOT_168.c

里面有一段显然会把 MCUSR 设为 0, 所以你打印出来应该都是 0
如下:

#ifdef WATCHDOG_MODS
        ch = MCUSR;
        MCUSR = 0;

        WDTCSR |= _BV(WDCE) | _BV(WDE);
        WDTCSR = 0;

        // Check if the WDT was used to reset, in which case we dont bootload and skip straight to the code. woot.
        if (! (ch &_BV(EXTRF))) // if its a not an external reset...
                app_start();// skip bootloader
#else
        asm volatile("nop\n\t");
#endif

所以, 如果你要自己检查 MCUSR
必须修改 BootLoader

xiaoliumonitor 发表于 2015-5-6 20:17:07

非常感谢            
页: [1]
查看完整版本: arduino uno 如何判断重启类型