JJY 日本標準時シミュレーター キット        

販売:(株)秋月電子通商 /製造:(有)トライステート /設計:YS電子工作ラボ

概要・特徴                                                        
 電波時計用のJJY(日本標準電波)の模擬信号をループアンテナから電波で送信します。ループアンテナの正面20cm以内に、 "電波時計Ver.2"キット(販売元:鰹H月電子通商 製造元:(有)トライステート)や市販の電波時計を置くことにより、電波時計の時刻を送信時刻に設定できます。 尚、受信する電波環境により受信可能距離がかわる可能性があります
 送信時刻(年月日時分秒)はキバン上のスイッチで設定できます。

      電波時計Ver.2キットへの電波(無線)送信による時刻設定    
   市販電波時計への電波(無線)送信による時刻設定      

★電波を介さないで、"電波時計Ver.2キット"と直接コネクタ接続して、"電波時計Ver2"の時刻を設定することもできます。


電波時計Ver.2キットへの有線送信による時刻設定

RS232Cケーブルでパソコンと接続することにより以下のことができます。
@ キットからの送信時刻を任意設定できたり、パソコンの時刻(システムタイム)に設定できます。
A キットからの送信時刻がモニタできます
B変調前のタイムコード出力パルスのリアルタイム波形がモニタできます。(→動画
 
PCからの時刻設定画面 
  タイムコードリアルタイムモニタ画面
キット上の液晶には 西暦4桁年月日曜日時分秒及び毎秒毎に送信しているパルス幅及びパルスの種類が表示されます。
 写真は2007年11月3日(日曜日) 午前0時6分22秒 に パルス幅500msecの論理”1”のパスルが送られた
時のモニタ画面です。

 
   


■ 諸元

項目 内容 備考
CPU PIC18F452  
システム
     クロック
40MHz 外部10MHz発振子 PLL4倍
出力 JJY模擬タイムコード  
変調周波数  40K/60K Hz (正弦波)     キバン上のスイッチ切替え
アンテナ プリント基板型ループアンテナ  
受信可能距離 アンテナ正面  20cm ±45度 受信条件:
 ・電波時計Ver.2 キットの バーアンテナ&受信回路

 ・電波暗室
時刻設定方法 基板上スイッチ
      または パソコン
 
設定可能時刻
西暦4桁(2000年〜9999年)年
       及び 月日時分秒
 ・手動設定
 ・PCシステム時刻(PCからのみ)
手動設定は任意の時刻で設定が可能です。PCとの接続はRS232CによるCOMポートです。
 
キバン上の
 液晶モニタ表示
・西暦4桁、年月日曜日時分秒
・毎秒毎の送信パルス幅及びパルスの意味
例 
  2008/07/25 Sun  P
  15:12:24 200msec
基板上の
      LEDモニタ
点滅 ポジションマーカ信号、マーカ信号、論理"1"信号、論理"0"信号に対応したLEDが点滅します。
PC画面モニタ ・西暦4桁、年月日曜日時分秒
タイムコード出力のリアルタイム表示
PCとの接続はRS232CによるCOMポートです。
推奨PCの性能
・ペンティアムW 1.8GHz以上
・メモリ 512MB以上
 
OS Windows 2000、XP、VISTA、7  Windows 8、8.1、10 では動作しません
接続可能
      通信ポート
COM1〜COM8    
電源  DC 8〜15V 約70mA 接続DCプラグ: 外形Φ5.5 内径Φ2.1(マル信無線 MPシリーズ相当品)
基板寸法 本体 :100mm x 70mm
アンテナ部: 49mm x 55mm
1.6t両面ガラススルホール

 注意 

  ・ 超微弱ですが、ループアンテナから電波が出ています。近くに電波時計が有るとボードの時刻に校正されますので、
   影響を与えたくない電波時計と本キットのとは十分に(少なくとも1m以上)距離を離なしてください。


  
<免責事項> 当キツトを使用すること、及び利用方法で生じた損害・損失は、直接・間接を含め如何なるものでも保証・
           責任を負うものでは有りませんのでご了承下さい。




■ キットの組み立て方
    右記 PDFファイルをご覧ください ( → JJY Simulator Kit Manual.pdf )



■ 使い方
 ● 接続の仕方
   キットの製作が終わったら下記の回路図のように接続して実験してください。尚、以下の表のものは本キットには
  付属していませんので、別途用意する必要があります。

  名称 諸元 備考
1 電波時計 JJY日本標準時適合電波時計    
2 ACアダプタ 出力電圧  DC8〜12V
出力電流 100mA以上 
DCプラグ 外形Φ5.5 内径Φ2.1
(マル信無線 MPシリーズ相当品) 
  
3 RS232C
 ケーブル
ストレートケーブル
 Dsub 9ピン(オス)
      〜Dsub 9ピン(メス)
パソコンと接続する場合
4 LANケーブル イーサネット 100BASE ケーブル 電波時計 Ver.2キットのタイムコード解析・
表示キバンと有線で接続する場合


<接続図> (→ PDFファイル


 市販電波時計への電波(無線)送信による時刻設定の場合 電波時計Ver.2キットへの有線送信による時刻設定の場合


 ● 動作確認方法  

@ DCジャックに出力電圧DC8〜12VのACアダプタを
  接続して下さい。
A 液晶のコントラスト調整用半固定抵抗VR1を適当に
  回すと右写真のように液晶に文字が表示されます。
 ・表示時刻はデフォルトで2007年11月3日午前0時
    から始まります。
 ・コントラストは時計回しで文字が濃くなります。
 ・この”時刻表示モード”のときアンテナキバンを取り
  付けるとアンテナキバンからは変調されたタイム
  コードが発信されています。
 
 

 ● 時刻の設定方法 

@ 時刻設定モードへの入り方      
   キバン上にシルク印刷で”MODE/SET”と印字されている
  スイッチSW1を押すと右の写真のような時刻設定モードに
  入ります。時刻設定モードに入った時は西暦年が設定
  できるモードになります。
 
 A 設定値の選択
  年月日時分秒のどの値を設定するかは”SELECT”と印字
  されているスイッチSW2を押します。スイッチを押すと年月日
  時分秒が順次繰り返して選択できます。表示は下記の
  ように変わります。
  (Year) → (Month) → (Day) → (H )→ (Min) → (Sec)
    → (Year) → (Month) ……

   右の写真は”分”が設定値として選択された場合の写真
  です。
   
 B 設定値の増加
  設定されている値を増加させたい場合は”UP”と印字されて
  いるスイッチSW3を押します。1回押すと値が+1増加します。
   
 C 設定値の減少
  設定されている値を減少させたい場合は”DOWN”と印字
  されているスイッチSW4を押します。1回押すと値がー1減少
  します。  
   
 D 時刻設定モードからの抜け方
  ”MODE/SET”と印字されているスイッチSW1を押すと 電源
 投入時と同じ時刻表示モードに戻ります。
   

  電波時計のとの組み合わせ -- やり方
   本キットの時刻を設定し終わったら
  @ 電波時計をアンテナキバン正面から 5〜10cmのところに電波時計を置いてください。
  A  バーアンテナ(フェライト棒)(注3)とアンテナキバンが直角になる向きに置いてください。アンテナで受信する電圧が
     最大となります。
  B 電波時計の時刻をリセット(注2)してください。
  C 4〜7分(注1)ぐらいで電波時計の時刻がキットの時刻にセットされます。        

 
バーアンテナとアンテナキバンは直角な位置関係で置いて下さい

(注1) 設定までの時間は電波の状況、電波時計種類(電波感知感度、タイムコード解析アルゴリズム等)及び設定
     開始のタイミングとマーカ信号のタイミングの時間差等により変わります。したがって同じ電波時計をつかって
     バーアンテナとアンテナキバン間距離が同じでもセットされる時間は異なります。
(注2) リセットしないとキットの時刻にセットされるまで長い時間かかかってしまいます。。
      <実験結果>

電波時計 リセットしなかった場合 リセットした場合
(下記実験結果参照)
備考
電波時計Ver.2キット 8分15秒 4分32秒   
ある国内大手メーカの電波時計 56分10秒 4分10秒   

   このようにリセットしないと時刻変更まで長時間かかるのは、一度セットされた時刻が電波状況、誤動作、いたづら
  などで安易に変わらないように時刻変更の場合はソフトウェアが慎重なアルゴリズムを構成している為です。

(注3) 市販電波時計のバーアンテナ
     下の写真は市販電波時計のバーアンテナ取り付けの様子を調べたものです。



 ● 電波時計との組み合わせ -- 実験結果
   ★ 電波時計キットVer.2の場合
            シミュレータキットの時刻をセットしておいた状態で、電波時計の電源をONした場合の実験です。電波時計の
    時刻は4分32秒後にシミュレータキットの時刻にセットされました。

   @8秒経過後
・ *が表示されていますのでタイムコードは受信されています。
・ まだ電波時計はマーカ信号を確認していません。
  A 1分38秒後
  マーカ信号を2度検出したのでタイムコードの解析に入ったところです。 
  B 4分34秒後
 ・電波時計はシミュレータキットと同じ西暦07年11月3日土曜日 15時24分00秒を示しています。
・4分32秒後、1分づつずれた時刻を連続で受信したので電波時計の時刻がシミュレータキットの時刻にセットされました。その直後の写真です。
           

  
 ★ 市販電波時計の場合
    シミュレータキットの時刻をセットしておいた状態で、ある国内大手メーカの電波時計をリセットした場合の実験
   です。電波時計の時刻は4分10秒後にシミュレータキットの時刻にセットされました。

 @ 13秒経過後
  ・ 電波時計をリセットしてから13秒経過した時の写真です。
  ・ 電波時計は1月1日午後12時0分13秒を示しています。
  
  A4分13秒経過後
 ・電波時計はシミュレータキットの時刻 11月3日午前10時29分7秒と同じ時刻を示しています。
 ・電波時計は4分10秒後にシミュレータキットの時刻にセットされました。その直後の写真です。
 
     


● 電波時計Ver.2キットとのコネクタ接続 -- やり方
  写真のようにLANケーブルで電波時計Ver.2キットと本キットを接続してください。本キットのタイムコードを有線で
  電波時計Ver.2キットに送信できます。ここでLANケーブルを使用していますが、単に市販されている安価なリード
  線として使用しているだけてイーサネットのプロトコル通信とは全く関係ありません。



■ パソコンとの接続
 ●インストールと設定方法

  @ インストール

   ・ エクスプローラを開いて本キット用のPCソフトが入って
        いるフォルダを開いて、ファイルsetup.exe を実行してください。
 






   ・ インストーラが起動して右の写真の画面があらわれます。

   ・ 画面にしたがって操作すると以下のようになります。
     ★Program files のフォルダにJJYSimulatorKitフォルダが
       できて実行ファイルとマニュアルファイルがコピーされます。
     ★”すべてのプログラム”の中に本キット用ソフトが追加され
       ます。 
           ★デスクトップに本キット用ソフトのアイコン
       追加されます。
                 







   ・ 正常にインストールされていれば、デスクトップにできたアイ
     コンをダブルクリックすると右の写真のようなメイン画面が
     モニタにあらわれます。
   
 
 

    A アンインストール
    本キット用プログラムをアンインストールする場合は
   [コントロールパネル] → [プログラムの追加と削除]  から
   アンインストールしてください。

  B パソコンとの接続 

    パソコンとはCOMポートをつかってストレートのシリアルケーブルを
   つかって接続してください。パソコンにシリアルポートがない場合は
   USBシリアルコンバータをつかってください。
    右の写真はケーブル式USBシリアルコンバータをつかってPCと
   本キットを接続した写真です。
    
 

   Cパソコンとの通信条件設定

   本キット付属ソフトの中で使用する通信ポートを
  設定します。キット付属ソフトのメイン画面のメニューバーの
    [設定]をクリックしてください。右の写真の画面があらわれ
    ます。COM1〜COM8の中で使用可能ポートが表示されて
    います。使用するCOMポートのラジオボタンを選択してくだ
    さい。その他の通信条件はプログラムで固定になっています
   ので設定の必要はありません。

  (参考)
   ・パソコンとキット間の通信条件は以下です。
    @ 通信速度   : 19200bps
    A データビット  : 8ビット
    B パリティ    : なし
    C ストップビット : 1
    D フロー制御  : なし

   ・デバイスマネージャを開いて別途通信条件を設定する
    必要はありません。

   
 ●時刻設定方法
    @マニュアル(手動)設定の場合

   ・年月日の設定はDateTimePickerのボタンをクリックして
    カレンダーを表示してマウスで年月日を選択して下さい。

   ・時分秒の設定はアップダウンボタンをクリックして設定して
    下さい。

   ・設定したい時刻の設定が終了したら”送信”ボタンを押して
    ください。送信データがCOMポート経由で本キットに送られ
    時刻が設定されます。(注)
   
 

  Aパソコン時刻設定の場合

   パソコンの時刻(システムタイム)を本キットに送信して
  セットすることが出来ます。
   キット付属ソフトのメイン画面の”パソコン現在時刻”の
  ラジオボタンをチェックするとパソコンの現在時刻が表示され
  ます。送信ボタンを押すと送信データがCOMポート経由で
  本キットに送られ時刻が設定されます。(注)
   
 
 
  (注)設定遅れ時間
   ”送信”ボタンを押してから実際に本キットの時刻がセットされるまでの遅れ時間はパソコンが
   ビジーでなくOSがすみやかに”送信”ボタンの処理をおこなってくれた場合で約30msecです。
   遅れ時間はRS232Cの通信速度)(19200bps)、PIC18F452(システムクロック40MHz)の処理
   速度及びプログラムのアルゴリズムなどに起因するものです。設定の遅れ時間を小さくしたい
   場合は常駐ソフトを可能な限り減らして下さい。
     

 ● キットの時刻モニタ 

    キットが送信している時間をPC画面でモニタするように 
   しています。 メイン画面の”シミュレータキットの時刻
   モニタ”ラベルの下にあるテキストボックスに キットから
   送られてくる時刻が下記フォーマットで表示されます。

       西暦年/月/日(曜日) 時間:分:秒 
 
 

    RS232Cケーブルが接続されていない場合など PC
   側で受信データを検出できない場合は右の写真のように
   モニタようのテキストボックスには
      0/0/0(日) 0:0:0
   が表示されます。、またその下に ”受信信号なし” の
   表示もあらわれます。  

   
 ● タイムコードモニタ
  キットが送信している変調前のタイムコードをリアルタイムでモニタできます。タイムコードモニタ画面を観察する
 場合、ウィルスチェックソフトなど常駐ソフトを停止しないとパルス波形が乱れることがあります。
  タイムコードの概要を把握するのに参考となると思いますので右HPを一読願います(→電波時計タイムコード

  右の写真は実際にキット上でPICが出力している変調前の
  タイムコード信号をデジタルオシロ(岩通 DS-5102)で観測した
  波形です。測定個所はキット上のシル印刷 TC OUT1  部品
  符号番号 PIN3のピンです。(詳細 キットの回路図参照
 

上記ピン3のタイムコード信号と同じ信号を波形をメイン画面の”波形表示”ボタンをクリックすることによりリアルタイム
観察できます。  

  @”波形表示”ボタンをクリックすると右写真の
   ”送信パルスモニタウィンドウ”が表示され
   ます。送信パルスモニタウィンドウが表示
   された直後はマーカ信号は未検出の状態
   です。この状態では横軸の時間軸はモニタが
   開始された時点を座標軸原点としての波形
   モニタ表示がおこなわれています。
    尚、タイムコードは60秒で1サイクルの繰り
   返し信号ですが、波形モニタは前半の0〜30
   秒が上段、後半の30〜60秒が下段に
   されています。(右写真参照)
  
 


  
  Aマーカパルスを検出すると送信パルスモニタ
  ウィンドウの波形はリセットされマーカ信号の
  立ち上がり時点を時間軸原点とする波形表示
  となります。またマーカ信号は青色の”検出
  完了”の表示に変わります。(右写真参照)
  
 B波形のモニタ表示は1サイクル毎(60秒毎)に
  リセットされて消えてしまいます。表示している
  波形をリセットしないで60秒経過した状態で
  保持した場合は”1サイクルホールド”ラベルの
  のラジオボタンを”する”の側にチェックして
  下さい。じっくりとパルス波形を解読したい場合
  などに使って下さい。
   リアルタイム波形表示に戻すと時は”再表示”
  ボタンを押して下さい。

<解読>

@ パルスの上に表示されるM、P、1、0はパルス信号の意味を解読した
  もので以下の意味です。
        M … マーカ信号
             (パルス幅200msecが連続した場合の後のパルス)
        P … ポジションマーカ信号
                (マーカ信号でないパスル幅200msecのパルス)
        1 … 論理”1”
             (幅500msecのパルス)
        0 … 論理”0”
             (幅800msecのパルス)
  
 
A パルス信号解読の上にあるアンダーラインと文字はパルス列を解読
  した結果が表示されます。アンダーラインの範囲はパルス列を解読する
  際の最小単位です。
   ・アンダーラインの範囲が1つの2進数の数値をあらわします。
   ・アンダーラインの一番右が2進数のLSB(最下位 b0ビット)です。
    その左が第1 b1ビット、その左が第2位  b2ビット …となります。
   ・アンダーラインの部分の数値はマーカ信号Mを起点として 時刻に
    関する意味が決められています。

<解読例1>
  右の緑青矢印のアンダーライン部は時刻”分の10進数2桁目”が
 2進数として 第2位 b2ビット、第1位 b1ビット、第0位(LSB)b0ビットの
 順番で送信されていることを意味します。従ってこの場合は
  1 × 1(b0) + 0×2(b1) + 0×2×2(b2) = 1
 すなわち分の10進2桁目は1である(10分〜19分)であるとの解読
 結果が 1■分として表示されています。

<解読例2>
  右の赤矢印のアンダーライン部は時刻”分の10進数1桁目”が
 2進数として 第3位 b3ビット、第2位 b2ビット、第1位 b1ビット、第0位
 (LSB)b0ビットの順番で送信されていることを意味します。従ってこの
 場合は
 0 ×1(b0) + 0×2(b1) + 1×2×2(b2) + 0×2×2×2(b3)
 = 4
 すなわち分の10進数1桁は4である(4分)であるとの解読結果が
 ■4分として表示されています。



■ Q&A

 Q: 本キットに関係する注意事項をまとめておしえてください

 A: 注意事項をまとめると以下です。    

 注意 

    @ 超微弱ですが、ループアンテナから電波が出ています。近くに電波時計が有るとボードの時刻に校正
      されますので、影響を与えたくない電波時計と本キットのとは十分に(少なくとも1m以上)距離を
      離なしてください。

    A 付属ソフトは100msec毎にWindowsによるタイマ割り込みがかかるようになっています。本キットを
      使用していると他のアプリケーションソフトが遅くなります。使用しない時は停止することをお勧め
      します。

    B 本キットをPCのCOMポートにつないでいると20msec毎に割り込み信号が入ってきます。アプリケー
      ションによってはこの信号になんらかの反応をする可能性があります。本キットを使用しいない場合は
      RS232CケーブルはPCには接続しないでください。



 Q: キット付属のPCソフトは常駐して、他のアプリケーションソフトの処理速度に影響を与えませんか?

 A: 常駐はしません。但し、付属ソフトは100msec毎にWindowsによるタイマ割り込みがかかるようになっています。
    本キットをバックグランドで使用していても他のアプリケーションソフトが遅くなります。使用しない時は停止することを
    お勧めします



 Q: キットの液晶に何も表示されません

 A: コントラストの調整が薄くなりすぎている可能性があります。コントラスト調整用半固定抵抗器VR1を時計方向に
   回してみて下さい。(→ 動作確認方法 ) 



 Q:送信パルスモニタウィンドウのパルスの種類の中に時々
 M、P、1、0以外の ”X”(エックス)が表示されて(右波形
 参照)波形が正常にモニタできない場合があります。
 何故でしょうか?
 対策としてどのようにすればよいのでしょうか?

 A: キット付属のPCソフトは20msec毎にキットからのRS232Cの外部割込みを受付ています。この割り込み処理が
    長時間(100msec以上)処理できない(OSがキット付属ソフトに制御を渡してくれない)場合送信されてくる
    パルスを正しく判別できなく(パルス幅がわからなく)なってしまいます。判別できないパルス(パルス幅が
    200msec、500msec、800msecのいずれでもないと判別されたパルス)を検出すると”X”(エックス)が表示
    されます。
    @ 対策としてはキットの制御に悪影響を与えている常駐ソフトを停止してください。ウィルス検知・駆除ソフトを
      停止すると”X”がでにくくなることは実際に確認されています。
       <参考> ・常駐ソフトをはずす
                      ・不要な常駐ソフトを解除する
    A 処理速度の高いPCをつかって下さい。並列処理能力が高い Core Two Duoを推薦します。
    B 最新のソフトにバージョンアップしてみてください。(→ 最新の付属PCソフト Ver 080815
       尚、Verの後の数字はリリースされた日付を表します。 
       (例) Ver.080815  → 2008年8月15日


     確認はしていませんがハード的ノイズでもこの現象は発生する可能性があります。ノイズの可能性が高い
    場合は 
    @ RS232Cのケーブルを短くする。
    A ノイズ発生源をキットやケーブルから離す         



 Q: マウスで付属ソフトメイン画面の”送信”をボタンを押してから実際にキットの時間が設定されるまでの
    遅れ時間はどのくらいありますか?

 
A: ”送信”ボタンを押してから実際に本キットの時刻がセットされるまでの遅れ時間は約30msecです。
   遅れ時間はRS232Cの通信速度)(19200bps)、PIC18F452(システムクロック40MHz)の処理
   速度及びプログラムのアルゴリズムなどに起因するものです。但し、30msecはパソコンのOSがすみやかに
   ”送信”ボタンのイベント処理をおこなってくれた場合の理論値です。 設定の遅れ時間を小さくしたい場合は
   イベント処理を遅らせる原因となる常駐ソフトを可能な限り減らして下さい。


 Q: キット上にあるスイッチを使ってキットの時間設定をおこなった場合 設定したい時刻をセットした後
    MODE/SET スイッチ(SW1)を押してから実際にキットの時刻がセットされるまでの遅れ時間はどのくらい
    ですか?

 
A: 7.3msec(実測値)です。遅れの原因はマイコンの処理能力からきています。 8ビット、40MHzのマイコンでは
    このあたりが限界と思われます。 PCから設定するよりもキット上のスイッチ信号をつかって時刻設定をおこなった
    ほうが少ない遅れ時間でまた不確定要素(Windowsによるイベント処理待ち時間等)による遅れ時間バラツキが
    少ない設定が可能です。


     

Q: キットの時刻がPC画面上でモニタできません。
  ”JJYシミュレータキットの時刻モニタ”のテキスト
  ボックスには   0/0/0(日) 0:0:0 が表示
  されています。またその下に ”受信信号なし” の
  表示もあらわれています。 
    (右画面参照) 

-

 A: キットからの信号を正常に付属ソフトが確認
    できていない場合にこのような画面となります。
    以下をチェックしてください。
   @ RS232CのケーブルがPC側及びキット側
     コネクタにしっかりと挿入されていますか?
   A RS232Cケーブルはストレートケーブルが使用
     されていますか?  クロスケーブルでは通信が
     できません
   B RS232Cケーブルが挿入されているCOMポート
     番号と付属ソフトで設定しているCOMポートの
     番号は同じですか(→パソコンとの通信条件
   C 使用している通信ポートのドライバは正常に
     動作していますか?
      ・デバイスマネージャ等で確認して下さい。
      ・ハイパーターミナル, Tera Term等通信
       ソフトで通信できるか確認してください。
   Dキット上の チェックピンPIN6(シルク印刷文字:
     TX )に右波形のような20msec毎のRS232C
     (19200bps)調歩同期パルス信号がでて
     いるかオシロスコープなどで確認して下さい。
                 (右波形参照)
   








  
  
  
  



 0V 




(参考)
 <PCからの信号チェック方法>
 キット上のチェックピンPIN7(シルク印刷:RX)の波形を
左写真に示します。この信号はPCのTXからの送信信号
です。モニター上の送信ボタンをクリックして時刻設定を
PCから行なった場合に発生します。






0V
     デジタルオシロ岩通 DS-5102




 Q: ”うるう秒”と”うるう年”の扱いはキットではどのようになっていますか?

 A:: うるう秒に関する制御はまったく行っておりません。タイムコードのうるう秒に関するビットは常に論理”0”
   (うるう秒情報なし)で、キット上のスイッチやPCから設定することはできません。現時点(2008/8/15)で
   うるう秒実施時期に関する情報はありません。JJYよりうるう秒実施のアナウンスがあったあとキットの時刻を
   手動で再設定して下さい。
    暦(こよみ)はグレゴリオ暦より正確な以下の改訂ユリウス暦(1923年ギリシャ正教会制定)をつかって
   います。
       @ 西暦年が4で割り切れる年はうるう年
       A ただし,西暦年が100で割り切れる年は平年
       B ただし,西暦年を900で割った余りが200または600になる年はうるう年
  
      (注) @(当初 : 4年に1度は1年を366日と制定)
                  … ユリウス暦(紀元前46年 古代ローマ ユリウス・カエサル制定)
          @+A    … グレゴリオ暦(1582年 ローマ教皇 グレゴリウス13世制定)
          @+A+B … 改訂ユリウス暦(1923年 ギリシャ正教会制定)

   <参考>
     うるう秒とうるう年は無関係です。うるう秒は地球の自転の不整と原子時計の間の調整であるのに対し
    うるう年は地球の公転周期と自転周期が簡単な比になっていないことを調整するものです。うるう秒の
    調整は午前0時に太陽が南中しないようにするためで、うるう年の調整は日本で2月に蝉が鳴いて8月に
    雪が降ることがないようにする調整です。うるう秒が追加されたのは最近では2006年1月1日でこの日は
    24時間1秒の日でした。1年は約365.242199日となっているため、暦(こよみ)のわかりにくい調整は人類
    永遠の課題となっています。 


 Q: キットのアンテナキバンの前に電波時計を置いて電波時計の時刻をキットの時刻にセットしようとしていますが
    セットできません。 4〜7分程度でセットされるとマニュアルには記載されているのですが……


 A:  @電波時計はアンテナキバン正面5〜10cmにアンテナ棒が直角となる向きに置いていますか?
      アンテナ棒がアンテナキバンと平行になっていたりするとほとんど電波を受信できません
      アンテナ棒が直角でも 電波がとどく距離は20cm程度までです。 (→電波時計との組合せ
    A電波時計の時刻をリセットしましたか? リセットボタンが見つからない時は電池をはずしたりして電源を1度
      OFFにしてください。電池をはずしてもコンデンサに充電されている電気で5〜30秒ぐらい動作している電波
      時計もあります。
        リセットされていると4〜7分程度でセットされますが、リセットしないと1時間以上もかかることがあります。
      長時間JJY日本標準時間で動作した電波時計の時刻を電波により変更するにはかなりの時間がかかります。
      一度セットされた時刻が電波状況、誤動作、いたづらなどで安易に変わらないように時刻変更の場合はソフト
      ウェアが慎重なアルゴリズムを構成している為です。 (→電波時計との組合せ

        <実験結果>

電波時計 リセットしなかった場合 リセットした場合 備考
電波時計Ver.2キット 8分15秒 4分32秒  
ある国内大手メーカの電波時計 56分10秒 4分10秒  

 

    B近くに強い電波を出す装置などはありませんか? 装置を
      停止させてくだい。
       また、強い電波環境からのがれにくい場合(注)は、電磁波の
      遮蔽を検討して下さい。金属で蔽われた建物や構造物内
      あるいは地下の室などで確認してください。携帯の電波が
      届かないところがよいと思います。あるいは、シールドボックスを
      つくり、キットと電波時計を入れる方法なども検討してみて下さい。
       右の写真は靴箱に料理で使うアルミ箔を貼り付けた電磁波
      遮蔽ボックスです。


  (注)JJY電波送信所及び米軍や自衛隊の通信施設等に近い場合
     などは強烈な電磁波環境となっています。
      尚、日本のJJY電波送信所は下記2か所にあります。
    @おおたかど山標準電波送信所(40KHz)
        福島県田村市都路町大鷹鳥谷山山頂付近
    Aはがね山標準電波送信所(60KHz)
        佐賀県佐賀市富士町羽金山山頂付近
       



 参考
 ● 組立て前 外観



 ● 組立て完了品 外観



 ● キット添付のマニュアル ( → PDFファイル

 ● 電気回路図 ( → PDFファイル


 ● PIC側プログラム   (→ ソースコード & 実行ファイル Ver.170128 )      

以下のプログラムの中にある液晶表示器制御ライブラリ 1llcd_lib.cは 後閑哲也さんが設計されたものです。

   <プログラム>                // コンパイラはCCSです。
//*****************************************************************************
//電波時計用タイムコード
//            発生プログラム   Ver.170128                               PIC18F452 
//*****************************************************************************
			//Ver.080706a → Ver.160515 //内容: 年またぎの西暦年に係るバグ修正
			//ver.160515 → ver.170128  //内容:年またぎの1月1日の累計日数 366(367)日 → 1日
											
#include "18f452.h"
#include "string.h"
#include "stdio.h"
#use delay(clock=40000000)
#FUSES  H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP   //システムクロック:40MHz (=10MHz×4PLL)

#use RS232(BAUD=19200,XMIT=PIN_C6,RCV=PIN_C7)   // ボーレート = 19200bps  TX=RC6,RX=RC7

#define NAK             0x15            //  NAK
#define ETX             0x03            //  ETX  
#define ESC             0x1b            //  ESC
#byte   PIR1=0x0F9E                     //  UART割込み制御レジスタへPIR1の変数割付
                                        //b4:TXIF UART送信割込みフラグ  1:割込み中 0:割込みなし
                                        //b5:RCIF UART受信割込みフラグ      同上
#byte   RCREG=0x0FAE                    //受信バッファ
#byte   RCSTA=0x0FAB                    //受信動作モード設定レジスタ
#byte   INTCON2=0x0FF1                  //割込み制御レジスタ2
#byte   INTCON3=0x0FF0                  //割込み制御レジスタ3
#byte   PIR2=0x0FA1                     //ペリフェラル割込みレジスタ


#use fast_io(B)
//////// Port define and link LCD library 
//#define mode   0
#define mode     0b00000010     //RB1をINT1の入力モードに設定

//   液晶
#define input_x     input_B
#define output_x    output_B
#define set_tris_x  set_tris_B
#define rs PIN_B3   //chip select
#define stb PIN_B2  //strobe

#include <1lcd_lib.c>



int ix = 0;
int Out_Mae,Flag_M,Flag_P,Flag_1,Flag_0;


long int Count_20msec = 0,Count_100msec = 0;

signed long int Year = 2007,Month = 11,Day = 3,H = 0,Min = 0,
                                            Sec = 0,Sec_PC,mSec = 10000,Week;
int32  Day_total,Day_Year,Day_This_Year;
unsigned long int Day1,Day2,Day3,Day4,Day5,Day6,Day7,Day8,Day9,Day10,Day11,Day12;   //Year年の1月1日から各月までの日数累計
short int OutputMode = 1;                                                           //1:タイムコード出力モード   0:年月日時分秒 設定モード
int swCount_Select = 0,swCount_Up = 0,swCount_Down = 0;
int SelectMode = 0; // 設定モード → 0:年 1:月 2:日 3:時 4:分 その他:秒

char Sun[]   = "Sun";
char Mon[]   = "Mon";
char Thues[] = "Thu";
char Wed[]   = "Wed";
char Thurs[] = "Thr";
char Fri[]   = "Fri";
char Sat[]   = "Sat";
char str[];
char str_Mode[10];




int Out = 0,PAm,PAh;

                                            
unsigned int buf[16];


unsigned long int temp_Count = 0;

void LedOut();
void WeekFunc();
void MonthFunc();
void YearFunc();
void TimeCode();
void time_output();
void sw_check();
void Decode();
char timed_getc();




void WeekFunc()
{
    unsigned long int i,Year1,Day_Feb,Weekx;

    // 2000年から(Year -1)年までの日数計算-----------------------------------------------------
    Day_Year = 0;
    for(i = 2000; i < Year; i++)    
    {
        if((((i % 4) == 0) && ((i % 100) != 0)) ||          //100で割り切れないで4で割れる西暦年はうるう年である。
            ((i % 900) == 200) ||                           //但し、900で割った時あまりが200または、600の西暦年も
            ((i % 900) == 600))                             //うるう年である。(改定ユリウス暦)    
        {
            Year1 = 366;
        }
        else Year1 = 365;

        Day_Year = Day_Year + (int32)Year1;
    }
        
    //Year年の累計日数計算-----------------------------------------------------------------------
            //2月の日数計算
        if((((Year % 4) == 0) && ((Year % 100) != 0)) ||    //100で割り切れないで4で割れる西暦年はうるう年である。
            ((Year % 900) == 200) ||                        //但し、900で割った時あまりが200または、600の西暦年も
            ((Year % 900) == 600))                          //うるう年である。(改定ユリウス暦)    
        {
            Day_Feb = 29;
        }
        else Day_Feb = 28;

        Day1  = Day;
        Day2  = Day1 + 31;
        Day3  = Day2 + Day_Feb;
        Day4  = Day3 + 31;
        Day5  = Day4 + 30;
        Day6  = Day5 + 31;
        Day7  = Day6 + 30;
        Day8  = Day7 + 31;
        Day9  = Day8 + 31;
        Day10 = Day9 + 30;
        Day11 = Day10 + 31;
        Day12 = Day11 + 30;

    switch(Month)
    {
        case 1:                     //1月の場合
            Day_This_Year = Day1;
            break;
        case 2:                     //2月の場合
            Day_This_Year = Day2;
            break;
        case 3:
            Day_This_Year = Day3;   //3月の場合
            break;
        case 4:
            Day_This_Year = Day4;   //4月の場合
            break;
        case 5:
            Day_This_Year = Day5;   //5月の場合
            break;
        case 6:
            Day_This_Year = Day6;   //6月の場合
            break;
        case 7:
            Day_This_Year = Day7;   //7月の場合
            break;
        case 8:
            Day_This_Year = Day8;   //8月の場合
            break;
        case 9:
            Day_This_Year = Day9;   //9月の場合
            break;
        case 10: 
            Day_This_Year = Day10;  //10月の場合
            break;
        case 11:
            Day_This_Year = Day11;  //11月の場合
            break;
        case 12:
            Day_This_Year = Day12;  //12月の場合
            break;
        default: break;
    }

    //2000年1月1日(土)から Year年Month月Day日間での累計日数Day_total ----------------------------------------
    Day_total = Day_This_Year + Day_Year;
            // Year年の累計日数 + 2000年1月1日から ( Year - 1)年12月31日までの日数累計
    Weekx = (unsigned long int)( Day_total % 7);

    switch(Weekx)
    {
        case 0:                                             //金曜日
            str = Fri;
            Week = 5;
            break;
        case 1:                                             //土曜日
            str = Sat;
            Week = 6;
            break;
        case 2:                                             //日曜日
            str = Sun;
            Week = 0;
            break;
        case 3:                                             //月曜日
            str = Mon;
            Week = 1;
            break;
        case 4:                                             //火曜日
            str = Thues;
            Week= 2;
            break;
        case 5:                                             //水曜日
            str = Wed;
            Week = 3;
            break;
        case 6:                                             //木曜日
            str = Thurs;
            Week = 4;
            break;
        default: break;
    }
}



void MonthFunc()
{

    if(Month == 2)                                          //2月の場合
    {                               
                                                            //うるう年の場合
        if(((Year % 4 == 0) && (Year % 100 != 0)) ||        //100で割り切れないで4で割れる西暦年はうるう年である。
            (Year % 900 == 200) ||                          //但し、900で割った時あまりが200または、600の西暦年も
            (Year % 900 == 600))                            //うるう年である。(改定ユリウス暦)    
        {
            if(Day >= 30)
            {
                Day = 1;
                Month++;
            }
        }
        else                                                //うるう年でない場合
        {
            if(Day >= 29)
            {
                Day = 1;
                Month++;
            }
        }
    }
    else if(Month == 12)                                    //12月の場合
    {
        if(Day >= 32)
        {   
            Day = 1;
			Day_This_Year = 1;				//追加(Ver.160515 → Ver.170128)	//バグ修正
											//1月1日の累計日数 365(366)日を1日に修正	//バグ修正
            Month = 1;
            Year++;
        }
    }

    else if( (Month == 4) || (Month == 6) ||                //4、6、9、11月の場合 
        (Month == 9) || (Month == 11) )                 
    {
        if(Day >= 31)
        {
            Day = 1;
            Month++;
        }

    }
    else                                                    //2、4、6、9、11、12月以外の月
    {
        if(Day >= 32)
        {
            Day = 1;
            Month++;
        }
    }
}

/*
//YearFunc()をコメントアウト(Ver.080706a → Ver.160515)
void YearFunc()
{                               
                                                            //うるう年の場合
    if(((Year % 4 == 0) && (Year % 100 != 0)) ||            //100で割り切れないで4で割れる西暦年はうるう年である。
        (Year % 900 == 200) ||                              //但し、900で割った時あまりが200または、600の西暦年も
        (Year % 900 == 600))                                //うるう年である。(改定ユリウス暦)    
    {
        if(Day_This_Year >= 367)                            //Year年の累計日数が367日を超えた場合
        {
            Day = 1;
            Year++;
        }
    }
    else                                                    //うるう年以外
    {
        if(Day_This_Year >= 366)                            //Year年の累計日数が366日を超えた場合
        {
            Day = 1;
            Year++;
        }
    }
}

*/




void TimeCode()
{
    unsigned long int i;
    unsigned long int Temp1,Temp2,Temp3;    
    unsigned long int Temp16,tempYear;

//(1) 全タイムコードパルスの立ち上がり信号(1sec毎にOut=1)
    for(i = 0; i < 60; i++) if(Count_100msec == i*10)Out = 1;

//(2) マーカー(M)信号OFFタイミング制御  パルス幅200msec
    if(Count_100msec == 2)Out = 0;          //先頭マーカー(M)off 

//(3) ポジションマーカ(P0〜P5)信号OFFタイミング制御 パルス幅200msec
    for(i = 0; i < 6; i++)
    {
        if(Count_100msec == (i * 100 +  92) )Out = 0;           //ポジションマーカーP0~P5 off
    }

//(4) 0〜10sec: 分データ信号出力タイミング制御
    Temp2 = (unsigned long int)Min / 10;                        //10進2桁目(BCD) :3ビット
    Temp1 = (unsigned long int)Min % 10;                        //10進1桁目(BCD) :4ビット
    Temp16 = (Temp2 << 5) + Temp1;                              //16ビットの送信順文字列作成
    Temp16 = Temp16 & 0b1111111111101111;                       //第4ビットに0をセット
    Temp16 = Temp16 << 8;                                       //MSBに先頭データビットを移動
        //パリティ計算
    PAm =bit_test (Temp2,2)^bit_test(Temp2,1)^bit_test(Temp2,0)
            ^bit_test(Temp1,3)^bit_test(Temp1,2)^bit_test(Temp1,1)^bit_test(Temp1,0);


    for(i = 1; i < 9; i++)                                      //MSBから8bit送出   
    {
        if( (Count_100msec == (10*i + 5)) && ((0x8000 & Temp16) != 0) )Out = 0;//1の場合 15〜85
        if( (Count_100msec == (10*i + 8)) && ((0x8000 & Temp16) == 0) )Out = 0;//0の場合 18〜88
        Temp16 = (Temp16 << 1);
    }

//(5) 10〜20sec: 時間データ信号出力タイミング制御
    Temp2 = (unsigned long int)H /10;                           //10進2桁目(BCD) :2ビット
    Temp1 = (unsigned long int)H % 10;                          //10進1桁目(BCD) :4ビット
    Temp16 = (Temp2 << 5) + Temp1;                              //16ビットの送信順文字列作成
    Temp16 =  Temp16 & 0b1111111001101111;                      //第4位と第7,8位に0をセット
    Temp16 = (Temp16 << 7);                                     //MSBに先頭データビットを移動
            //パリティ計算
    PAh = bit_test(Temp2,1)^bit_test(Temp2,0)
            ^bit_test(Temp1,3)^bit_test(Temp1,2)^bit_test(Temp1,1)^bit_test(Temp1,0);

    for(i = 0; i < 9; i++)                                                          //MSBから9ビット送出
    {
        if( (Count_100msec == (10*i + 105)) && ((0x8000 & Temp16) != 0) )Out = 0;   //1の場合
        if( (Count_100msec == (10*i + 108)) && ((0x8000 & Temp16) == 0) )Out = 0;   //0の場合
        Temp16 = (Temp16 << 1); 
    }

//(6) 20〜30sec: 日データ信号出力タイミング制御(1)
    Temp3 = (unsigned long int)Day_This_Year / 100;                                 //10進3桁目(BCD) :2ビット
    Temp2 = ((unsigned long int)Day_This_Year % 100) / 10;                          //10進2桁目(BCD) 4:ビット
    Temp1 = ((unsigned long int)Day_This_Year % 100) % 10;                          //10進1桁目(BCD) 4:ビット
    Temp16 = (Temp3 << 5) + Temp2;                                                  //16ビットの送信順文字列作成
    Temp16 =  Temp16 & 0b1111111001101111;                                          //第4位と第7,8位に0をセット
    Temp16 = (Temp16 << 7);                                                         //MSBに先頭データビットを移動
    for(i = 0; i < 9; i++)                                                          //MSBから9ビット送出    
    {
        if( (Count_100msec == (10*i + 205)) && ((0x8000 & Temp16) != 0) )Out = 0;   //1の場合
        if( (Count_100msec == (10*i + 208)) && ((0x8000 & Temp16) == 0) )Out = 0;   //0の場合
        Temp16 = (Temp16 << 1); 
    }
//(7) 30〜40sec: 日データ信号出力タイミング制御(2)
    Temp16 = (Temp1 << 5) + (PAh << 2) + (PAm << 1); 
    Temp16 =  Temp16 & 0b1111111111100111;                                          //第3位と4位に0をセット

    Temp16 = (Temp16 << 7);//MSBに先頭データビットを移動
    for(i = 0; i < 9; i++)//MSBから9ビット送出  
    {
        if( (Count_100msec == (10*i + 305)) && ((0x8000 & Temp16) != 0) )Out = 0;   //1の場合
        if( (Count_100msec == (10*i + 308)) && ((0x8000 & Temp16) == 0) )Out = 0;   //0の場合
        Temp16 = (Temp16 << 1); 
    }

//(8) 40〜50sec: 西暦年信号(西暦下2桁)
    TempYear = Year % 100;                                                          //西暦は下2桁のみ送信
    Temp2 = TempYear / 10;                                                          //10進2桁目 :4ビット
    Temp1 = TempYear % 10;                                                          //10進1桁目 :4ビット
    Temp16 = (Temp2 << 4) + Temp1;                                                  //16ビットの送信順文字列作成 (予備ビット=0)
    Temp16 = (Temp16 << 7);                                                         //MSBに先頭データビットを移動
    for(i = 0; i < 9; i++)  
    {
        if( (Count_100msec == (10*i + 405)) && ((0x8000 & Temp16) != 0) )Out = 0;   //1の場合
        if( (Count_100msec == (10*i + 408)) && ((0x8000 & Temp16) == 0) )Out = 0;   //0の場合
        Temp16 = (Temp16 << 1); 
    }

//(9) 50〜60sec: 曜日、うるう年、予備信号制御
    Temp2 = (unsigned long int)Week;                                                //曜日 10進1桁    :3ビット
                                                                                    //0:日曜日 1:月曜日 2:火曜日 3:水曜日 4:木曜日 5:金曜日 6:土曜日
    Temp1 = 0x00;                                                                   //うるう秒、予備 :6ビット
    Temp16 = Temp16 = (Temp2 << 6) + (Temp1 << 4);                                  //16ビットの送信順文字列作成
    Temp16 =  Temp16 & 0b1111111111110000;                                          //第0〜3位に0をセット
    Temp16 = (Temp16 << 7);                                                         //MSBに先頭データビットを移動
    for(i = 0; i < 9; i++)  
    {
        if( (Count_100msec == (10*i + 505)) && ((0x8000 & Temp16) != 0) )Out = 0;   //1の場合
        if( (Count_100msec == (10*i + 508)) && ((0x8000 & Temp16) == 0) )Out = 0;   //0の場合
        Temp16 = (Temp16 << 1); 
    }

    if(Out == 1)
    {
        output_high(PIN_B0);    //アンテナ出力          // タイムコード出力 : ”1" = High
        output_high(PIN_B1);    //コネクタ出力
    }

    if(Out == 0)
    {
        output_low(PIN_B0);                 // タイムコード出力 : ”0” = Low 
        output_low(PIN_B1);
    }


    if((Count_100msec == 2) && (Out_Mae == 1) && (Out == 0))
    {
        output_low(PIN_C5);
        Flag_M = 0;
    }

    for(i = 0; i < 6; i++)  //  タイムコード出力”P”の場合
    {
        if((Count_100msec == (92 + i*100)) && (Out_Mae == 1) && (Out == 0 ))
        {
            output_low(PIN_C4);
            Flag_P = 0;
        }
    }

    for(i = 0; i < 60; i++) //  タイムコード出力”1”の場合
    {
        if((Count_100msec == (5 + i*10)) && (Out_Mae == 1) && (Out == 0 )) 
        { 
            output_low(PIN_D3);
            Flag_1 = 0;
        }
    }


    for(i = 0; i < 60; i++) //  タイムコード出力”0”の場合
    {
        if((Count_100msec == (8 + i*10)) && (Out_Mae == 1) && (Out == 0 )) 
        {
            output_low(PIN_D2);
            Flag_0 = 0;
        }
    }

    Flag_M++;
    if(Flag_M >= 8)
    {
        Flag_M = 9;
        output_high(PIN_C5);
    }


    Flag_P++;
    if(Flag_P >= 8)
    {
        Flag_P = 9;
        output_high(PIN_C4);
    }
    
    Flag_1++;
    if(Flag_1 >= 5)
    {
        Flag_1 = 6;
        output_high(PIN_D3);
    }
    
    Flag_0++;
    if(Flag_0 >= 5)
    {
        Flag_0 = 6;
        output_high(PIN_D2);
    }

    Out_Mae = Out;

}


void time_output()              // タイムコード出力モード(100msec毎)
{
    TimeCode();                 //タイムコードを出力
    Sec = Count_100msec / 10;
    Count_100msec++;
    if(Count_100msec >= 600)
    {
        Count_100msec = 0;
        Min++;
        if(Min >= 60)
        {
            Min = 0;
            H++;
            if(H >= 24)
            {
                H = 0;
                Day++;
                WeekFunc();
                MonthFunc();
              //  YearFunc();	//YearFunc()をコメントアウト(Ver.080706a → Ver.160515)
            }
        }
            
    }
}

void sw_check()     //各スイッチ検出
{
    unsigned long int pr2;  //priod register : 10bit
    unsigned long int DC1; //Duty Comparator : 10bit 

    //セレクトスイッチ検出-------------------------------------------------------
    if((input(PIN_E0) == 0) && (OutputMode == 0))swCount_Select++;  //RA3のセレクトスイッチが押されていた場合
    else swCount_Select = 0;
    if(swCount_Select == 4)                                         //25msec毎に4回スイッチONが連続検出された場合
    {
        if(SelectMode == 0)SelectMode = 1;                          //西暦年設定モードの場合 → 月設定モード
        else if(SelectMode == 1)SelectMode = 2;                     //月設定モードの場合 → 日設定モード
        else if(SelectMode == 2)SelectMode = 3;                     //日設定モードの場合 → 時設定モード
        else if(SelectMode == 3)SelectMode = 4;                     //時設定モードの場合 → 分設定モード
        else if(SelectMode == 4)SelectMode = 5;                     //分設定モードの場合 → 秒設定モード
        else SelectMode = 0;                                        //秒設定モードの場合 → 西暦年設定モード
    }   
    if(swCount_Select >= 5)swCount_Select = 5;                      //スイッチが押されつづけられた場合は


    //アップスイッチ検出---------------------------------------------------------------
    if((input(PIN_E1) == 0) && (OutputMode == 0))swCount_Up++;      //RA5のアップスイッチが押されていた場合
    else swCount_Up = 0;
    if(swCount_Up == 4)                                             //25msec毎に4回スイッチONが連続検出された場合
    {
        if(SelectMode == 0)Year++;                                  //西暦年設定モードの場合 
        else if(SelectMode == 1)                                    //月設定モードの場合 
        {
            Month++;
            if(Month >= 12)Month = 12;
        }
        else if(SelectMode == 2)                                    //日設定モードの場合 
        {
            Day++;
            
            if( (Month == 4) || (Month == 6) ||                     //4、6、9、11月の場合 
                (Month == 9) || (Month == 11) )
            {
                if(Day >= 31)Day = 30;
            }
            else if(Month == 2)                                     //2月の場合
            {
                                                                    //うるう年の場合
                if(((Year % 4 == 0) && (Year % 100 != 0)) ||        //100で割り切れないで4で割れる西暦年はうるう年である。
                (Year % 900 == 200) ||                              //但し、900で割った時あまりが200または、600の西暦年も
                (year % 900 == 600))                                //うるう年である。(改定ユリウス暦)    
                {
                    if(Day >=30)Day = 29;
                }
                else                                                //うるう年以外
                {
                    if(Day >=29)Day = 28;
                }
            }
            else                                                    //1月、3月、5月、7月、8月、10月、12月の場合
            {
                if(Day >= 32)Day = 31;
            }
        }
        else if(SelectMode == 3)                                    //時設定の場合
        {
            H++;
            if(H >= 24)H = 23;
        }
        else if(SelectMode == 4)                                    //分設定の場合
        {
            Min++;
            if(Min >= 60)Min = 59;
        }
        else                                                        //秒設定の場合
        {

            Sec++;
            Count_100msec = Count_100msec + 10;
            Count_20msec = 0;
    

            if(Sec >= 60)
            {
                Sec = 59;
                Count_100msec = 590;
            }
        }
        WeekFunc();
    }
    if(swCount_Up >= 5)swCount_Up = 5;                              //スイッチが押されつづけられた場合は


    //ダウンスイッチ検出---------------------------------------------------------------
    if((input(PIN_E2) == 0) && (OutputMode == 0))swCount_Down++;    //RA3のセレクトスイッチが押されていた場合
    else swCount_Down = 0;
    if(swCount_Down == 4)                                           //25msec毎に4回スイッチONが連続検出された場合
    {
        if(SelectMode == 0)                                         //西暦年設定モードの場合 
        {
            Year--;
            if(Year <= 1999)Year = 2000;
        }
        else if(SelectMode == 1)                                    //月設定モードの場合
        {
            Month--;
            if(Month <= 0) Month = 1;
        }
        else if(SelectMode == 2)                                    //日設定モードの場合
        {
            Day--;
            if(Day <= 0) Day = 1;
        }
        else if(SelectMode == 3)                                    //時設定モードの場合 
        {
            H--;
            if(H <= -1)H = 0;
        }
        else if(SelectMode == 4)                                    //分設定モードの場合 
        {
            Min--;
            if(Min <= -1)Min = 0;
        }
        else                                                        //秒設定モードの場合
        {

            Sec--;
            Count_100msec = Count_100msec - 10;
            Count_20msec = 0;
    
            if(Sec <= -1)
            {
                Sec = 0;
                Count_100msec =0;
            }
        }
        WeekFunc();
    }   
    if(swCount_Down >= 5)swCount_Down = 5;                          //スイッチが押されつづけられた場合は

    //40/60 KHz搬送波周波数切り替えスイッチ検出---------------------------------------------------
    if(input(PIN_A4) == 0)          //40KHz
    {
        pr2 = 249;  // 周期 T0 = (pr2 + 1) * 4 * Tosc * (TMR2 Prescale Value)
                    //        = (249 + 1) * 4 * 0.025 * 1 = 25μsec (40KHz)
        DC1 = 500;  // ON時間 Ton = DC1 * Tosc * (TMR2 Prescale Value)
                    //           = 500 * 0.025 * 1 = 12.5μsec (duty = 12.5/25 = 50%)

    }
    else 
    {

        pr2 = 166;  //T0 = (166 + 1) * 4 * 0.025 * 1 = 16.7μsec (59.88KHz)
                    // 誤差 =(60-59.88)/60 = 0.2%
        DC1 = 334;  //Ton = 334 * 0.025 * 1 = 8.35μsec (duty = 8.35/16.7 = 50.00%)
    }


    setup_timer_2(T2_DIV_BY_1,pr2,1);   //プリスケーラ:1/1  pr2:0〜255  ポストスケーラ:1(PWMでは使わない)
    setup_ccp1(CCP_PWM);    //CCPをPWMモードでセット

    DC1 =(unsigned long int) pr2*2 +2;  //
    set_pwm1_duty(DC1);                 //PWMのdutyをセット

}



void Decode()
{
        signed long int Sum_Transmit,Sum_Receive;
        signed long int temp_Year,temp_Month,temp_Day,temp_H,temp_Min,temp_Sec,temp_mSec;

        temp_Year = (((signed long int)buf[1]) << 8) + buf[0];
        temp_Month =    (((signed long int)buf[3]) << 8) + buf[2];
        temp_Day =  (((signed long int)buf[5]) << 8) + buf[4];
        temp_H =    (((signed long int)buf[7]) << 8)    + buf[6];
        temp_Min =  (((signed long int)buf[9]) << 8)    + buf[8];
        temp_Sec =  (((signed long int)buf[11]) << 8)   + buf[10];
        temp_mSec = (((signed long int)buf[13]) << 8)   + buf[12];
        Sum_Transmit = (((signed long int)buf[15]) << 8) + buf[14];

        Sum_Receive = 0;        
        Sum_Receive = temp_Year + temp_Month + temp_Day 
                                + temp_H + temp_Min + temp_Sec + temp_mSec;

        if((Sum_Transmit == Sum_Receive) &&
            ((temp_Year >= 2000) && (temp_Year <= 9999)) &&
            ((temp_Month >= 1) && (temp_Month <= 12)) &&
            ((temp_Day >= 1) && (temp_Day <= 31)) &&
            ((temp_H >= 0) && (temp_H <= 23)) &&
            ((temp_Min >= 0) && (temp_Min <= 59)) &&
            ((temp_Sec >= 0) && (temp_Sec <= 59)) &&
            ((temp_mSec >= 0) && (temp_mSec <= 999)) ) 
        {
            OutputMode = 1;
            Year = temp_Year;
            Month = temp_Month;
            Day = temp_Day;
            WeekFunc();
            H = temp_H;
            Min = temp_Min;
            Sec_PC = temp_Sec;
            mSec = temp_mSec;
        
        }

}


#int_timer0                     //タイマ1割込み(20msec毎に割込み発生)
interval()
{


//RTS/CTSフロー制御

     output_high(PIN_C1);//PC側からの送信を禁止: PIC側ソフト:1(High) をRC2ピンにセット
                                                //→ MAX232のT2in出力電圧(=PICのRC2ピン):5V
                                                //→ PIC側のRTS信号(MAX232のT2out7番ピン):-8V 
                                                //→ COMポートCTS(8番ピン); -8V
                                                //→ Comstat.fCtsHold(送信禁止) = true


    PIR1 =  (PIR1  & 0b11011111);   //割込み制御レジスタPIR1の第5ビットをクリア → 受信の割込みフラグクリア
    RCSTA = (RCSTA & 0b11101111);   //CREN = 0(連続受信不可)
    RCSTA = (RCSTA & 0b11111101);   //OERR = 0 : オーバーランエラー(データが残っているのに次のデータを受信)クリア) 
    RCSTA = (RCSTA & 0b11111011);   //FERR = 0 : フレーミングエラー(ストップビットがこない)クリア
    RCSTA = (RCSTA | 0b00010000);   //CREN = 1(連続受信可)



    set_timer0(40536);      // 0.025μsec × 4 × 8 × 25000 = 20000μsec = 20msec (at システムクロック40MHz)
                            // 256×256 - 25000 = 40536



    ix = 0;                 //RS232データリセット

    sw_check();             //スイッチ入力をチェック




    sw_check();             //スイッチ入力をチェック
    
    Count_20msec++;






    if(mSec > 1000) mSec = 5555;
    else if((mSec > 980) && (mSec <= 1000)) //PC からのセットで "Set_PC秒 980-1000msec" になった場合
    {
        mSec = 5555;    //PCからの時刻設定が終了したらこのループには入らない
        Count_20msec = 0;

        Count_100msec = (Sec_PC + 1)  * 10; //Sec_PC = 59の場合 : Count_100msec = 600
                                    //  → time_output()のなかで1秒繰り上がる
        time_output();  //時刻をセット
    }
    else    mSec = mSec + 20;

    
    if(Count_20msec >= 5)       //100msec毎


    {
        Count_20msec = 0;

        if(OutputMode == 1) time_output();  // タイムコード出力モードであれば100msec毎
          
    }

    

    
        putc((signed long)Year);
        putc(((signed long)Year) >> 8);

        putc((signed long int) Month);
        putc(((signed long int) Month) >> 8);

        putc((signed long int)Day);
        putc(((signed long int)Day) >> 8);

        putc((signed long int)Week);
        putc(((signed long int)Week) >> 8);
    
        putc((signed long int)H);
        putc(((signed long int)H) >> 8);
    
        putc((signed long int)Min);
        putc(((signed long int)Min) >> 8);

        putc((signed long int)Sec);
        putc(((signed long int)Sec) >> 8);

        putc((signed long int)Out);
        putc(((signed long int)Out) >> 8);



    //RTS/CTSフロー制御 
    output_low(PIN_C1);//PC側からの送信を許可: PIC側ソフト:0(Low) をRC1ピンにセット
                                                //→ MAX232のT2in入力電圧(=PICのRC2ピン):0V
                                                //→ PIC側のRTS信号(MAX232のT2out7番ピン):+8V 
                                                //→ COMポートCTS(8番ピン); +8V
                                                //→ Comstat.fCtsHold(送信禁止) = false
                                                //→ 送信許可                                        



    return 0;
}


char timed_getc()
{
        char    returnValue;
                int32 timeout;

        timeout = 0;
        while(!kbhit()&&(++timeout< 20000))        // タイムアウト時間内にデータを受信しなければwhile()ループを抜ける
                                                        //タイムアウト時間 = 200 msec 
        delay_us(10);                                    // 10μsec
  
        if(kbhit())                     //タイムアウト時間内にデータを取得した場合はデータを取得し、そのデータを返す
                returnValue = getc();
        else                            // タイムアウト時間内でデータを取得できなかった場合はNAKを返す
                returnValue = NAK;
        return returnValue;
}

#INT_EXT1
void EXTX()             // RB1端子からの外部割り込みで実行
{

            if(OutputMode == 1)                             //タイマコード出力モード
            {
                OutputMode = 0;                             //タイムコード出力モードの場合 → 時刻設定モード
                SelectMode = 0;                             //西暦年設定モードにセット
            }
            else
            {
                OutputMode = 1;                         //時刻設定モードの場合 → タイムコード出力モードにセット
                set_timer0(65534);                      //タイマ割込みをすぐかける
            }
                

}


#INT_RDA
void rs232c()
{

    temp_Count++;

    PIR1 = (PIR1 & 0b11011111); //割込み制御レジスタPIR1の第5ビットをクリア → 受信の割込みフラグクリア
    buf[ix] = timed_getc();
    if(ix >= 15)
    {
        ix = 0;
        Decode();

        RCREG = 0;
    }
    else ix++;

}



main()
{

    char char_Pulse;
    char char_Time;

    char Slash[] = "/";
    char Slash_Zero[] = "/0";
    char No_Zero[] = "";
    char Zero[] = "0";
    char Semi[] = ":";
    char Semi_Zero[] = ":0";
    char T_200msec[] = "200msec";
    char T_500msec[] = "500msec";
    char T_800msec[] = "800msec";
    char T_blk[]     = "       "; 
    char* BeforeMonth;
    char* BeforeDay;
    char* BeforeH;
    char* BeforeMin;
    char* BeforeSec;


    setup_timer_0(RTCC_INTERNAL |RTCC_DIV_8);
    set_timer0(49911);

    set_tris_b(0xFF);
    set_tris_c(0b10000001);// 必須 in = RC7 & RC1

    ext_int_edge( 1, H_TO_L); //Set up PIC18 EXT1
                                                     //RB1(INT1)ポートが highからlowに変化した時割込みがかかるように設定


    
    lcd_init();
    lcd_cmd(0b00001100);                                            // カーソル:OFF    ブリンク:OFF
    lcd_clear();
    printf(lcd_data,"JJY SimulatorKit");
    lcd_cmd(0xC0); // 2行目の先頭へ
    printf(lcd_data,"     Ver.170128");

    WeekFunc();
    delay_ms(2000);

    enable_interrupts(INT_EXT1);    //外部割込み1割込み解除
    enable_interrupts(INT_RDA);     //RS232C割込み解除
    enable_interrupts(INT_TIMER0);  //T0の割込み解除
    enable_interrupts(GLOBAL);      //全割込み解除

    PIR2=(PIR2 & 0b11111011);       //タイマ0の割込みを下位レベルに設定
                                    //→ペリフェラル割込みレジスタ2(PIR2)の第2位ビットを"0"にセット
    INTCON2=(INTCON2 | 0b00100000); //UART受信用の割込みを上位レベルに設定
                                    //→割込み制御レジスタ2(INTCON2)の第5ビットを"1"にセット
    INTCON3=(INTCON3 | 0b01000000); //INT1の割込みを上位レベルに設定
                                    //→割込み制御レジスタ3(INTCON3)の第6ビットを"1"にセット


    while(1)                                                        // 割込みを待つ
    {


    // 液晶表示
    if(OutputMode == 1)                                     //タイムコード出力モード
        {
                if(Month <= 9)BeforeMonth = Slash_Zero;
                else BeforeMonth = Slash;
                if(Day <= 9)BeforeDay = Slash_Zero;
                else BeforeDay = Slash;
                if(H <= 9)BeforeH = Zero;
                else BeforeH =No_Zero;
                if(Min <= 9)BeforeMin = Semi_Zero;
                else BeforeMin = Semi;
                if(Sec <= 9)BeforeSec = Semi_Zero;
                else BeforeSec = Semi;

            lcd_clear();
            if(Flag_M <= 8)         //パルス幅200msec マーカ信号検出
            {
                char_Pulse = 'M';
                char_Time = T_200msec;
            }           
            else if(Flag_P <= 8)    //パルス幅200msec ポジションマーカ検出
            {
                char_Pulse = 'P';
                char_Time = T_200msec;
            }
            else if(Flag_1 <= 5)    //パルス幅500msec 論理”1”
            {
                char_Pulse = '1';
                char_Time = T_500msec;
            }
            else if(Flag_0 <= 5)
            {
                char_Pulse = '0';   //パルス幅800msec 論理”0”
                char_Time = T_800msec;
            }
            else 
            {
                char_Pulse = ' ';
                char_Time = T_blk;
            }
            printf(lcd_data,"%ld%s%ld%s%ld %s %c",Year,BeforeMonth,Month,
                                BeforeDay,Day,str,char_Pulse);      //   
            lcd_cmd(0xC0); // 2行目の先頭へ Day_This_Year

            printf(lcd_data,"%s%ld%s%ld%s%ld %s",
                            BeforeH,H,BeforeMin,Min,BeforeSec,Sec,char_Time);           //
        }
    
        else                                                        // 年月日時分秒の設定モード
        {
            switch(SelectMode)
            {
                case 0:     //西暦年設定
                    sprintf(str_Mode,"(Year)");
                    break;
                case 1:     //月設定
                    sprintf(str_Mode,"(Month)");
                    break;
                case 2:     //日設定
                     sprintf(str_Mode,"(Day)");
                    break;
                case 3:     //時設定..
                     sprintf(str_Mode,"(H)");
                    break;
                case 4:     //分設定
                     sprintf(str_Mode,"(Min)");
                    break;
                case 5:     //秒設定
                     sprintf(str_Mode,"(Sec)");
                    break;
                default:    break;
            }

        lcd_clear();
        printf(lcd_data,"%ld.%ld.%ld %s ",Year,Month,Day,str);      //   

        lcd_cmd(0xC0); // 2行目の先頭へ
    
        printf(lcd_data,"%ld:%ld:%ld  %s",H,Min,Sec,str_Mode);          //

        }

    
    

        delay_ms(100);

    
    }




    return 0;
}





//-----------------------------------------------------------------------

//**************************************
//インクルードファイル    1lcd_lib.c
//このファイルは後閑哲也さんが設計されたものです
//**************************************

///////////////////////////////////////////////
//  液晶表示器制御ライブラリ
//  内蔵関数は以下
//    lcd_init()    ----- 初期化
//    lcd_cmd(cmd)  ----- コマンド出力
//    lcd_data(chr) ----- 1文字表示出力
//    lcd_clear()   ----- 全消去


//////////////////////////////////////////////

//////// データ出力サブ関数
void lcd_out(int code, int flag)
{
	output_x((code & 0xF0) | (input_x() & 0x0F));
	if (flag == 0)
		output_high(rs);		//表示データの場合
	else
	output_low(rs);			//コマンドデータの場合
	delay_cycles(4);			//NOP 1		
	output_high(stb);			//strobe out
	delay_cycles(8);			//NOP 2
	output_low(stb);			//reset strobe
}
//////// 1文字表示関数
void lcd_data(int asci)
{
	lcd_out(asci, 0);			//上位4ビット出力
	lcd_out(asci<<4, 0);		//下位4ビット出力
	delay_us(50);				//50μsec待ち
}
/////// コマンド出力関数
void lcd_cmd(int cmd)
{
	lcd_out(cmd, 1);			//上位4ビット出力
	lcd_out(cmd<<4, 1);			//下位4ビット出力
	delay_ms(2);				//2msec待ち
}
/////// 全消去関数
void lcd_clear()
{
	lcd_cmd(0x01);				//初期化コマンド出力
	delay_ms(15);				//15msec待ち
}
/////// 初期化関数
void lcd_init()
{
	set_tris_x(mode);			//モードセット
	delay_ms(15);
	lcd_out(0x30, 1);			//8bit mode set
	delay_ms(5);
	lcd_out(0x30, 1);			//8bit mode set
	delay_ms(1);
	lcd_out(0x30, 1);			//8bit mode set
	delay_ms(1);
	lcd_out(0x20, 1);			//4bit mode set
	delay_ms(1);
	lcd_cmd(0x2E);				//DL=0 4bit mode
	lcd_cmd(0x08);				//display off C=D=B=0
	lcd_cmd(0x0D);				//display on C=D=1 B=0
	lcd_cmd(0x06);				//entry I/D=1 S=0
	lcd_cmd(0x02);				//cursor home
}





 

 ● キット付属パソコンソフト (→キット付属PCソフト(実行ファイル) Ver.080815
    ダウンロードされるファイルは実行ファイルだけです。ソースコードは含まれていません。