Hobby Gardens パソコン関連を主として
  様々な趣味の記録を書き綴っています。
Top Diary Create PC Tips Review &  
  Introduction
Anime & Games Homebuilt PC Machine Download Profile

Raspberry Piで電波時計の時刻合わせ

最終更新日2018-02-13 01:30:14
カテゴリ:Diary 閲覧数:14814

あじぇんだ

部屋にある電波時計が電波拾ってくれずに時間がずれる。

電子工作好きだけど,なんだかんだRaspberry PiのGPIOって使ったこと無いなぁ。

ということでRaspberry Piで電波時計用の電波(JJY信号)を出力してみる。

環境

このRaspberry Piは諸々の事情によりインターネットに常時接続されていない。

なので,インターネットの接続がある時間(起動直後と15:30前後)にntpdateコマンドで時刻同期をすることにする。

JJY信号は常時発信する。

fake-hwclockの削除

RaspberryPiにはRTCが無い代わりに擬似的なハードウェアクロックを実現するfake-hwclockが存在する。
しかしこいつのせいで時間が進んでいた時の修正(時間の巻き戻し)ができない。

設定ファイルいじったりしても良いのだが,NTPベースで時刻合わせをするので,こいつはまるごと削除してしまおう。

$ sudo apt purge fake-hwclock

時刻同期の設定

まずはntpdateコマンドをインストール。

$ sudo apt install ntpdate

起動時の実行はrc.local,定期実行はcronを使う

$ sudo nano /etc/rc.local
  /usr/sbin/ntpdate ntp.jst.mfeed.ad.jp	# この一行を“exit 0”の直前に追記
$ sudo crontab -e
  30 19 * * * /usr/sbin/ntpdate ntp.jst.mfeed.ad.jp	# 追記

dateコマンドで時間を適当にずらし,ntpdateがちゃんと動いているかを確認する。

JJY信号を発信するアンテナの作成

40KHzはラズパイの外で作る。ちょうど赤外線の工作で38kHz作るようにNE555買ってあったから,その在庫をそのまま使う。抵抗値だけ変えて40kHzになるように調整する。

電源はラズパイの5Vを使用,GPIOからは変調波(で言葉あってるよね)を出力,トランジスタのベースに繋いでスイッチング。

あとついでに,GPIOからの信号が分かるようにLEDもつける。

こんなかんじ。ブレッドボードで動作確認ができたら回路図(右)も作成。

回路図ができたらさくっとハンダ付け。あと,アンテナの作成もする。

はんだ付け終わってから思ったけど,アンテナって抵抗より上にした方が良かったのではないだろうか。というかこれじゃアンテナずっと0Vじゃん。でもブレッドボードでは動いたし,電波は電流が生み出すから良いのか?(←電波の仕組みよくわかってない人)

JJY信号発信用プログラムの作成・サービス化

jjy.pyの作成

作成っていっても,Raspberry Pi で作る Wi-Fi 式電波時計用リピータ こちらのページに合ったプログラムをそのまま拝借しました。

テストのときとかパスが通ってたほうが良いから,/usr/local/bin/jjy.pyに直接スクリプトを書き込む。

jjy.pyのサービス化

/etc/init.d/ 以下にサービス名(jjyとする)と同じ名前のファイルを作成して,実行権限を与える。

jjyの中身は後述の通り。詳細は省くが,最初のコメントアウトの中と,daemon,appdirを編集,あとは38行目のstart-stop-daemonの引数を編集(python用に作ったので,phpとかbashとかのスクリプトの場合は要編集)。

$ sudo nano /etc/init.d/jjy		# 内容は後述
$ sudo chmod 755 /etc/init.d/jjy	# 実行権限を付与
$ sudo systemctl daemon-reload		# daemonのリロード

jjyが出来たら,あとはsystemctlなりserviceなりで起動できる。

$ sudo service jjy start		# 起動
$ sudo service jjy status		# 確認
  Active: active (running)	# 動いていることを確認

再起動して自動起動が確認できればOK。

ラズパイにアンテナとかを接続

ラズパイに接続,光った!オシロで40kHzでてることも確認できたし,JJY信号もちゃんと出てる!

アンテナも接続して,電波時計をアンテナ近くに移動,どうだ!

完璧!

後ろに映ってるのなにかって?iMacだよ。
え?時間なら電波時計じゃなくてiMacで確認すればいいって?
ばっか,あじぇんだに書いだたろ,工作は手段じゃなくて目的なんだよ!
楽しかったから何も問題ない!

電波法についての確認

今回の工作は電波を出すものだから,電波法に抵触してないかの確認。
※電波については完全な素人なので,言い回しや内容がおかしかったりするかも。間違いがあれば指摘をお願いします。

手元にある電波時計のマニュアルを見てみると,どうやらこの時計は1200km離れていても電波を受信出来るらしい。
今回の実験に使った40kHzを出してる福島局から1200km離れたところというと,ちょうど鹿児島県あたりがそれに相当する。

NICTの長波標準電波の電界強度予測値のページの情報から,鹿児島に届く40kHzの電波の電界強度は平均0.71mV/m。

つまりこの電波時計は0.7mV/mぐらいの電界強度の電波なら受信できる。

総務省の微弱無線局の規定のページから,40kHzの電波は3m離れた場所における電界強度が0.5mV/m未満なら免許は不要。

実際に電波時計動かしながら受信できる最長距離を測ってみたら,30cmぐらいが限界で,60cmぐらい離すと完全に反応しない。

ということで,アンテナの周囲30cmぐらいは0.71mV/mの強度があるけど,それより離れるとどんどん減衰していくようだ。
なら,3mもはなれれば流石に0.5mV/mは下回ってるだろう。

参考文献

付録:スクリプトとか

/usr/local/bin/jjy.py

#!/usr/bin/python
# coding: utf-8
# 
# JJY タイムコードを出力するスクリプト.
# GPIO に H を出力する事で 40kHz パルスが停止する回路を想定
# しています.
 
import RPi.GPIO as GPIO
import datetime
import time
 
# JJY 時刻符号を出力する端子
GPIP_PORT = 4
 
def set_pin(mode):
    GPIO.output(GPIP_PORT, mode)
 
def send_bit(bit):
    if bit == -1: # マーカ
        set_pin(1)
        time.sleep(0.2)
        set_pin(0)
        time.sleep(0.799)
    elif bit == 0: # 0
        set_pin(1)
        time.sleep(0.799)
        set_pin(0)
        time.sleep(0.2)
    elif bit == 1: # 1
        set_pin(1)
        time.sleep(0.499)
        set_pin(0)
        time.sleep(0.5)
 
def send_bcd(num, count, parity=0):
    for i in range(count):
        bit = (num >> ((count-1) - i)) & 0x1
        send_bit(bit)
        parity ^= bit
    return parity
 
def send_datetime(now):
    now = datetime.datetime.now()
    minute = now.minute
    hour = now.hour
    day = now.toordinal() - datetime.date(now.year, 1, 1).toordinal() + 1
    year = now.year % 100
    wday = now.isoweekday() % 7
    sec = now.second
    usec = now.microsecond
 
    min_parity = 0
    hour_parity = 0
 
    ############################################################
    send_bit(-1)
    
    # 10分位のBCD
    min_parity = send_bcd(minute/10, 3, min_parity)
    
    send_bit(0)
    
    # 1分位のBCD
    min_parity = send_bcd(minute%10, 4, min_parity)
    
    send_bit(-1)
 
    ############################################################
    send_bit(0)
    send_bit(0)
    
    # 10時位のBCD
    hour_parity = send_bcd(hour/10, 2, hour_parity)
    
    send_bit(0)
    
    # 1時位のBCD
    hour_parity = send_bcd(hour%10, 4, hour_parity)
    
    send_bit(-1)
    
    ############################################################
    send_bit(0)
    send_bit(0)
    
    # 累計日数100日位のBCD
    send_bcd(day/100, 2)
    
    send_bit(0)
 
    # 累計日数10日位のBCD
    send_bcd((day%100) / 10, 4)
    
    send_bit(-1)
 
    ############################################################
    # 累計日数1日位のBCD    
    send_bcd(day%10, 4)
    
    send_bit(0)
    send_bit(0)
    
    # パリティ
    send_bit(hour_parity)
    send_bit(min_parity)
    
    send_bit(0)
    send_bit(-1)
 
    ############################################################
    send_bit(0)
    
    # 西暦年10年位のBCD
    send_bcd((year%100)/10, 4)
    
    # 西暦年1年位のBCD
    send_bcd(year%10, 4)
    
    send_bit(-1)
 
    ############################################################
    # 曜日のBCD
    send_bcd(wday, 3)
    
    send_bit(0)
    send_bit(0)
    send_bit(0)
    send_bit(0)
    send_bit(0)
    send_bit(0)
 
    # マーカ
    set_pin(1)
    time.sleep(0.2)
    set_pin(0)
    # 0.8 秒残しておき,次回呼び出しタイミングの調整代とする
 
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIP_PORT, GPIO.OUT)
set_pin(0)
 
while True:
    now = datetime.datetime.now()
    minute = now.minute
    sec = now.second
    usec = now.microsecond
 
    # 0 秒になるまで待つ
    time.sleep(60 - (sec + usec/1000000.0))
 
    send_datetime(now + datetime.timedelta(minutes=1))

/etc/init.d/jjy

#!/bin/sh
### BEGIN INIT INFO
# Provides: jjy
# Required-Start: $network $local_fs $remote_fs
# Required-Stop:  $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 1
# Short-Description: Start jjy daemon
### END INIT INFO
 
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

daemon="jjy"
 
appdir=/usr/local/bin/
pidfile=/var/run/${daemon}.pid
logfile=/var/log/${daemon}.log

. /lib/lsb/init-functions
 
RETVAL=0
 
# System configuration
unset TMPDIR
 
start() {
    echo -n "Starting ${daemon} services: "
    echo -n "waiting "    # wait for boot of mysql, only needed raspberry pi
    sleep 1m
    echo -n "restart "
    # cheking already run?
    if start-stop-daemon --stop --quiet --signal 0 --pidfile $pidfile
    then
      pid=`cat ${pidfile}`
      log_warning_msg "daemon is already running? (pid=${pid})"
      exit 1
    fi
    start-stop-daemon --start --background --exec "/usr/bin/python" --pidfile "$pidfile" --make-pidfile -- "$appdir$daemon.py"
    status=$?
    log_end_msg $status
}
stop() {
    log_daemon_msg -n $"Stopping ${daemon} service: "
    # cheking already run?
    if start-stop-daemon --stop --signal 0 --pidfile $pidfile ; then
        start-stop-daemon --stop --pidfile $pidfile
        status=$?
        rm -f $pidfile
        log_end_msg $status
    else
        log_warning_msg "daemon not running? (check ${pidfile})."
    fi
}
 
case "$1" in
     start)
          start
          ;;
     stop)
          stop
          ;;
     restart)
          stop
          start
          ;;
     *)
     echo $"Usage: ${daemon} {start|stop|restart}: "
     RETVAL=2
esac
 
exit $RETVAL

Comments

All Comments

このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは管理者のみが閲覧できます。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは管理者のみが閲覧できます。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。
このコメントは現在管理者の承認待ちです。

Post Comment

Name :

Title :

URL :

Comment:
※<a>, <b>, <font>, <i>, <s>を使用できます。

管理者にのみ表示