目次

RTC(Real Time Clock)動作シミュレーション(AWK)

 秋月電子で販売されているRTC(Real Time Clock)の動作が
 どうなっているのかを理解するため、スクリプトを書いて
 みました。

 ターゲットのRTCは、以下。



 マイコンで実現するには、1秒ごとの割込みをキャッチして
 秒、分、時、日、月、年の順番で、+1の操作をし、ドミノ
 倒しの要領で、より上位の値を変化させるかを判断すれば
 できそうとわかりました。

 秒、分、時は、60、60、24を境界条件にして、上位の
 値を更新するか、否かを決定します。

 この要領で、計算処理をまとめると、以下。

  # second
  clk_sec++
  # judge
  if ( clk_sec == 60 ) {
    # clear
    clk_sec = 0
    # minute
    clk_min++
  }
  # minute
  if ( clk_min == 60 ) {
    # clear
    clk_min = 0
    # hour
    clk_hour++
  }
  # hour
  if ( clk_hour == 24 ) {
    # clear
    clk_hour = 0
    # increment
    clk_day++

 時が23から0に戻るとき、日、月、年の順番で、判定を入れないと
 うまく結果がでないことになります。

 月ごとに日が異なるため、場合分けをします。

    # day
    mode = 0
    if ( month == 12 ) { mode = 1 }
    if ( month == 2  ) { mode = 2 }
    if ( month == 4 || month == 6  ) { mode = 3 }
    if ( month == 9 || month == 11 ) { mode = 3 }
    #
    if ( mode == 0 ) {
      if ( clk_day == 32 ) {
        clk_day = 1 ;
        month++ ;
      }
    }
    if ( mode == 1 ) {
      if ( clk_day == 32 ) {
        clk_day = 1
        month = 1
        clk_year++
      }
    }
    if ( mode == 2 ) {
      if ( clk_day == 29 ) {
        clk_day = 1
        month++
      }
    }
    if ( mode == 3 ) {
      if ( clk_day == 31 ) {
        clk_day = 1
        month++
      }
    }

 大の月、小の月で場合分けした後、2月と12月を
 より分けています。閏年は、後で考えることにして
 おきます。

 2つのスクリプトを合体して、関数にします。

function update_rtc()
{
  #  set month  
  month = clk_month
  #  second  
  clk_sec++
  #  judge  
  if ( clk_sec == 60 ) {
    #  clear  
    clk_sec = 0
    #  minute  
    clk_min++
  }
  #  minute  
  if ( clk_min == 60 ) {
    #  clear  
    clk_min = 0
    #  hour  
    clk_hour++
  }
  #  hour  
  if ( clk_hour == 24 ) {
    #  clear  
    clk_hour = 0
    #  increment  
    clk_day++
    #  day  
    mode = 0
    if ( month == 12 ) { mode = 1 }
    if ( month == 2  ) { mode = 2 }
    if ( month == 4 || month == 6  ) { mode = 3 }
    if ( month == 9 || month == 11 ) { mode = 3 }
    #
    if ( mode == 0 ) {
      if ( clk_day == 32 ) {
        clk_day = 1 ;
        month++ ;
      }
    }
    if ( mode == 1 ) {
      if ( clk_day == 32 ) {
        clk_day = 1
        month = 1
        clk_year++
      }
    }
    if ( mode == 2 ) {
      if ( clk_day == 29 ) {
        clk_day = 1
        month++
      }
    }
    if ( mode == 3 ) {
      if ( clk_day == 31 ) {
        clk_day = 1
        month++
      }
    }
  }
  clk_month = month ;
}

 関数を定義しただけなので、アクション部分を考え
 フィールド値を、わかりやすい変数名で代入して
 対応することにします。
 アクション部分は、以下。

{
  clk_year  = $1
  clk_month = $2
  clk_day   = $3
  clk_hour  = $4
  clk_min   = $5
  clk_sec   = $6
  #
  update_rtc()
  # show
  for ( i = 1 ; i < 7 ; i++ ) {
    printf("%02d ",$i)
  }
  printf(" => ")
  printf("%02d %02d %02d %02d %02d %02d\n",clk_year,clk_month,clk_day,clk_hour,clk_min,clk_sec)
}

 2つを合体して、ひとつのAWKスクリプトにします。

function update_rtc()
{
  #  set month  
  month = clk_month
  #  second  
  clk_sec++
  #  judge  
  if ( clk_sec == 60 ) {
    #  clear  
    clk_sec = 0
    #  minute  
    clk_min++
  }
  #  minute  
  if ( clk_min == 60 ) {
    #  clear  
    clk_min = 0
    #  hour  
    clk_hour++
  }
  #  hour  
  if ( clk_hour == 24 ) {
    #  clear  
    clk_hour = 0
    #  increment  
    clk_day++
    #  day  
    mode = 0
    if ( month == 12 ) { mode = 1 }
    if ( month == 2  ) { mode = 2 }
    if ( month == 4 || month == 6  ) { mode = 3 }
    if ( month == 9 || month == 11 ) { mode = 3 }
    #
    if ( mode == 0 ) {
      if ( clk_day == 32 ) {
        clk_day = 1 ;
        month++ ;
      }
    }
    if ( mode == 1 ) {
      if ( clk_day == 32 ) {
        clk_day = 1
        month = 1
        clk_year++
      }
    }
    if ( mode == 2 ) {
      if ( clk_day == 29 ) {
        clk_day = 1
        month++
      }
    }
    if ( mode == 3 ) {
      if ( clk_day == 31 ) {
        clk_day = 1
        month++
      }
    }
  }
  clk_month = month ;
}

{
  clk_year  = $1
  clk_month = $2
  clk_day   = $3
  clk_hour  = $4
  clk_min   = $5
  clk_sec   = $6
  #
  update_rtc()
  # show
  for ( i = 1 ; i < 7 ; i++ ) {
    printf("%02d ",$i)
  }
  printf(" => ")
  printf("%02d %02d %02d %02d %02d %02d\n",clk_year,clk_month,clk_day,clk_hour,clk_min,clk_sec)
}

 テキストファイルには、境界を跨ぐようにデータを格納。

19 1 1 23 59 59
19 1 31 23 59 59
19 2 27 23 59 59
19 2 28 23 59 59
19 3 31 23 59 59
19 4 29 23 59 59
19 4 30 23 59 59
19 5 30 23 59 59
19 5 31 23 59 59
19 6 30 23 59 59
19 7 7 12 34 0
19 7 7 12 34 59
19 7 7 12 59 59
19 7 7 23 59 59
19 7 30 23 59 59
19 7 31 23 59 59
19 8 31 23 59 59
19 9 30 23 59 59
19 10 30 23 59 59
19 10 31 23 59 59
19 11 30 23 59 59
19 12 31 23 59 59

 使うときは、テキストファイルとをスクリプトファイルを
 用意して、端末上で結果を貰います。



 I/Oリダイレクトを使えば、テキストファイルに落とし
 後から、ゆっくりと検証することもできます。

19 01 01 23 59 59  => 19 01 02 00 00 00
19 01 31 23 59 59  => 19 02 01 00 00 00
19 02 27 23 59 59  => 19 02 28 00 00 00
19 02 28 23 59 59  => 19 03 01 00 00 00
19 03 31 23 59 59  => 19 04 01 00 00 00
19 04 29 23 59 59  => 19 04 30 00 00 00
19 04 30 23 59 59  => 19 05 01 00 00 00
19 05 30 23 59 59  => 19 05 31 00 00 00
19 05 31 23 59 59  => 19 06 01 00 00 00
19 06 30 23 59 59  => 19 07 01 00 00 00
19 07 07 12 34 00  => 19 07 07 12 34 01
19 07 07 12 34 59  => 19 07 07 12 35 00
19 07 07 12 59 59  => 19 07 07 13 00 00
19 07 07 23 59 59  => 19 07 08 00 00 00
19 07 30 23 59 59  => 19 07 31 00 00 00
19 07 31 23 59 59  => 19 08 01 00 00 00
19 08 31 23 59 59  => 19 09 01 00 00 00
19 09 30 23 59 59  => 19 10 01 00 00 00
19 10 30 23 59 59  => 19 10 31 00 00 00
19 10 31 23 59 59  => 19 11 01 00 00 00
19 11 30 23 59 59  => 19 12 01 00 00 00
19 12 31 23 59 59  => 20 01 01 00 00 00

 スクリプトで、動作論理が理解できれば、回路に変換したり
 ワンチップマイコンのファームウエアにするのは簡単。

 西暦年が4で割り切れると、無条件でうるう年。
 400で割り切れて、かつ100で割り切れるならば
 うるう年となります。

 これを西暦年から計算で求めます。

 今回使ったRTCでは、下2桁だけを入れられる
 ようにしてありました。上2桁を加えられる
 なら、スクリプトのどこかに判定処理を入れ
 対応します。


目次

inserted by FC2 system