STM32F103を使ってみる

起動モードの判定方法 その2


前回、起動モードの判定方法を紹介しました。
前回紹介したスケッチにはRESETによる再起動か、電源ONによる起動かの判定処理が有りません。
そこで、この判定処理を追加します。
まずは以下のスケッチで、RESETによる再起動時と、電源ONによる起動時のRTCの値を調べてみます。
/*
 * RESETによる再起動時と電源ONによる起動時の判定
 * RESETによる再起動時はBlueLEDが点滅
 * 電源ONによる起動時はGreenLEDが点滅
 */

#include <RTClock.h>

RTClock rt (RTCSEL_LSE); // initialise
uint32 tt;

#define Red   PA0
#define Blue  PA1
#define Green PA2

void flashRed () {
  digitalWrite(Red,!digitalRead(Red));
}

void flashBlue () {
  digitalWrite(Blue,!digitalRead(Blue));
}

void flashGreen () {
  digitalWrite(Green,!digitalRead(Green));
}

// the setup function runs once when you press reset or power the board
void setup() {
  tt = rt.getTime();
  pinMode(Blue,OUTPUT);
  pinMode(Red,OUTPUT);
  pinMode(Green,OUTPUT);
  digitalWrite(Blue,LOW);
  digitalWrite(Red,LOW);
  digitalWrite(Green,LOW);

  if (tt == 0) { // Power ON
    rt.attachSecondsInterrupt(flashGreen);
  } else { // Reset
    rt.attachSecondsInterrupt(flashBlue);
  }
}

void loop() {
}

スケッチの最初でRTCを読み込んでいます。
電源ONによる起動の時はRTCの値がゼロになります。
電源ONによる起動の時はGreenLEDが点滅し、RESETによる再起動の時はBlueLEDが点滅します。
前回の処理に、上記の処理を組み込んだのが以下のスケッチです。
/*
 Check boot mode of your board.

 When you COMPILE sketch, Blink RedLED.
 When you RESET board, Blink BlueRed.
 When you POWER ON, Blink GreenLED.

*/

#include <EEPROM.h>
#include <RTClock.h>

RTClock rt (RTCSEL_LSE); // initialise
uint32 tt;
tm_t   tm;

//#define EPSIZE 252
#define EPSIZE 250

#define Red   PA0
#define Blue  PA1
#define Green PA2

//Structure define of EEPROM(254Word)
struct EPROM{
  tm_t     tm; // Compile Date & Time
  uint16_t data[EPSIZE]; // User Data
};

const char *monthName[12] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

const char *dayName[7] = {
  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

bool getTime(const char *str)
{
  int Hour, Min, Sec;

  if (sscanf(str, "%d:%d:%d", &Hour, &Min, &Sec) != 3) return false;
  tm.hour = Hour;
  tm.minute = Min;
  tm.second = Sec;
  return true;
}

bool getDate(const char *str)
{
  char Month[12];
  int Day, Year;
  uint8_t monthIndex;

  if (sscanf(str, "%s %d %d", Month, &Day, &Year) != 3) return false;
  for (monthIndex = 0; monthIndex < 12; monthIndex++) {
    if (strcmp(Month, monthName[monthIndex]) == 0) break;
  }
  if (monthIndex >= 12) return false;
  tm.day = Day;
  tm.month = monthIndex + 1;
  tm.year = Year-1970;
  tm.weekday = dow(Year,tm.month,tm.day);
  return true;
}

// dow() [0-Sunday, 1-Monday etc.]
int dow(int y, int m, int d) {
  static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
//  y -= m < 3;
  if (m < 3) y--;
  return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}


int readEPROM(EPROM* hoge, tm_t* cdate) {
  uint16 AddressWrite = 0x10;
  uint16 Status;
  uint16 Data;
  uint32_t crc32;
 
  Serial.println("[readEPROM]");
  Status = EEPROM.read(AddressWrite++, &Data);
  if (Status != 0) return Status;
  cdate->year = (Data >> 8) & 0xFF;
  cdate->month = (Data >> 0) & 0xFF;
 
  Status = EEPROM.read(AddressWrite++, &Data);
  if (Status != 0) return Status;
  cdate->day = (Data >> 8) & 0xFF;
  cdate->weekday = (Data >> 0) & 0xFF;

  Status = EEPROM.read(AddressWrite++, &Data);
  if (Status != 0) return Status;
  cdate->pm = (Data >> 8) & 0xFF;
  cdate->hour = (Data >> 0) & 0xFF;

  Status = EEPROM.read(AddressWrite++, &Data);
  if (Status != 0) return Status;
  cdate->minute = (Data >> 8) & 0xFF;
  cdate->second = (Data >> 0) & 0xFF;

  for(int i=0;i<EPSIZE;i++) {
    Status = EEPROM.read(AddressWrite, &Data);
    if (Status != 0) return Status;
    hoge->data[i] = Data;
    AddressWrite++;
  }
  return 0;
}

int writeEPROM(EPROM* hoge, tm_t* cdate) {
  uint16 AddressWrite = 0x10;
  uint16 Status;
  uint16 Data;
  uint32_t crc32;

  Serial.println("[writeEPROM]");
  Data = (cdate->year << 8) + cdate->month;
  Status = EEPROM.write(AddressWrite++, Data);
  if (Status != 0) return Status;

  Data = (cdate->day << 8) + cdate->weekday;
  Status = EEPROM.write(AddressWrite++, Data);
  if (Status != 0) return Status;

  Data = (cdate->pm << 8) + cdate->hour;
  Status = EEPROM.write(AddressWrite++, Data);
  if (Status != 0) return Status;

  Data = (cdate->minute << 8) + cdate->second;
  Status = EEPROM.write(AddressWrite++, Data);
  if (Status != 0) return Status;

  for(int i=0;i<EPSIZE;i++) {
    Data = hoge->data[i];
    Status = EEPROM.write(AddressWrite, Data);
    if (Status != 0) return Status;
    AddressWrite++;
  }
  return 0;
}

void displayTM(char *title, tm_t hoge) {
  Serial.print(title);
  Serial.print(" year=");
  Serial.print(hoge.year);
  Serial.print(" monh=");
  Serial.print(hoge.month);
  Serial.print(" day=");
  Serial.print(hoge.day);
  Serial.print(" weekday=");
  Serial.print(hoge.weekday);
  Serial.print(" hour=");
  Serial.print(hoge.hour);
  Serial.print(" minute=");
  Serial.print(hoge.minute);
  Serial.print(" second=");
  Serial.println(hoge.second);
}

int difftm(tm_t tm1, tm_t tm2) {
  if (tm1.year != tm2.year) return 1;
  if (tm1.month != tm2.month) return 1;
  if (tm1.day != tm2.day) return 1;
  if (tm1.weekday != tm2.weekday) return 1;
  if (tm1.pm != tm2.pm) return 1;
  if (tm1.hour != tm2.hour) return 1;
  if (tm1.minute != tm2.minute) return 1;
  if (tm1.second != tm2.second) return 1;
  return 0;
}

void flashRed () {
  digitalWrite(Red,!digitalRead(Red));
}

void flashBlue () {
  digitalWrite(Blue,!digitalRead(Blue));
}

void flashGreen () {
  digitalWrite(Green,!digitalRead(Green));
}

void setup() {
  struct EPROM romData;

  tt = rt.getTime();
  delay(1000);
  Serial.begin(9600);

  pinMode(Blue,OUTPUT);
  pinMode(Red,OUTPUT);
  pinMode(Green,OUTPUT);
  digitalWrite(Blue,LOW);
  digitalWrite(Red,LOW);
  digitalWrite(Green,LOW);

  if (tt != 0) { // Reset

    tm_t cdate;
    readEPROM(&romData,&cdate);
    displayTM("[cdate]",cdate);
 
    Serial.print("__TIME__=[");
    Serial.print(__TIME__);
    Serial.print("] __DATE__=[");
    Serial.print(__DATE__);
    Serial.println("]");
   
    // get the date and time the compiler was run
    if (getDate(__DATE__) && getTime(__TIME__)) {
      displayTM("[tm]",tm);
    }
 
    if (difftm(cdate, tm) == 0) { // Reset
      Serial.print("Compile date is MUCH!!");
      rt.attachSecondsInterrupt(flashBlue);
    } else { // Compile
      Serial.print("Compile date is NOT MUCH!!");
      writeEPROM(&romData,&tm);
      rt.attachSecondsInterrupt(flashRed);
    }
  } else { // Power ON
    Serial.print("RTC is CLEAR!!");
    writeEPROM(&romData,&tm);
    rt.attachSecondsInterrupt(flashGreen);
  }
}

void loop() {
}

スケッチコンパイル時:EEPROMを初期化します。
RESETによる再起動時:EEPROMを初期化しません。
電源ONによる起動時:EEPROMを初期化します。

これを応用して、次回はRTCの初期化設定方法を紹介します。

続く...