STM32F103を使ってみる

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


前回、EEPROM emulation機能を紹介しました。
EEPROMに書き込まれたデータは永遠に初期化されません。
そこで、データ初期化の方法を紹介します。
まずは、スケッチをコンパイルした時だけ初期化する方法です。
RESETボタンでの再起動時や電源ONでは初期化されません。
EEPROMの先頭8バイトにコンパイルした日時を書き込んで、起動時に __DATE__ __TIME__ 変数と比較しています。
時間の比較関数としてdifftime()関数が有りますが、tm_t型変数を比較する関数は見つからなかったので作りました。
もしかしたらtm_t型変数を操作するライブラリが有るかもしれません。
RESETボタンを押したときには、IDEのシリアルモニターへの表示が再開されません。
これかなり不便です。
RESETボタン押し下げ時の動作を確認するためには、LEDの点滅で確認する必要があります。
/*
 * コンパイルした時だけEEPROMを初期化する
 * コンパイルした時はEEPROMを初期化する(RedLEDが点滅)
 * RESETした時はEEPROMを初期化しない(BlueLEDが点滅)
 */
#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

//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 setup() {
  struct EPROM romData;

  delay(1000);
  Serial.begin(9600);

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

  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) {
    Serial.print("Compile date is MUCH!!");
    rt.attachSecondsInterrupt(flashBlue);
  } else {
    Serial.print("Compile date is NOT MUCH!!");
    writeEPROM(&romData,&tm);
    rt.attachSecondsInterrupt(flashRed);
  }
}

void loop() {
}

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

但し、上のスケッチでは、電源を入れ直した時もEEPROMは初期化されません。
そこで、次回はRESETによる再起動か、電源ONによる起動かの判定処理を追加します。

続く...