秋月時計(大型) その1改造編

RaspberryPi

超大型表示秋月時計

秋月の組み立てキットに、 超大型表示マイコンデジタル時計キットVer.4 というのがあり、これを購入して作ってみた。PIC(PIC16F57)を使った普通の時計で、 タイマーや目覚ましなどの簡単な機能も入っている。特徴は何といっても大型の7セグ表示で、57mmx32mmの超大型となっている。 4桁表示で全体としては200mm×80mmの大きさだ。

大型表示なので遠目にも見やすく便利。
しかし時計の精度が長く使うには少し悪い。トリマーコンデンサでこのあたりは自分で調整することとなっており、 1日では狂うことはないが、1か月程度では1分位ずれてしまう。 簡単に時間設定変更はできるとはいえ、ちょっと面倒。

PI化検討

狂わない時計としては、ラズベリーパイがある。NTP設定をしておけば自動でネットで時刻調整をするので、時計が大きく狂うことはない。 秋月時計はCPUはPICだが、CPUをラズベリーパイにすれば、時刻調整不要な時計に変身できるのでは?

ということで、大型表示時計の時計部分のラズパイ化に取り組む。 実は秋月では表示部分だけの別売り もしているので、これだけ買ってラズベリーパイで表示させるといった手もあるのだが、 ラズパイのGPIOだけで7セグをドライブするほどのパワーはないので(各ピンの電源容量的に) CPU部分だけを乗っ取る方向でラズパイ化を行ってみようと思う。

ちなみに、公式ページを見ると、GPIOはMax3mAで設計されており、16mAでダメになるらしい。 なので、ledを一つ優しく点灯させる程度のドライブ能力しかないようだ。

幸い、PICはソケットで取り付けるようになっているので、CPUの取り外しは容易。 ここにラズパイのピンを接続して、CPU乗っ取りを行うこととする。

組立

ではCPU乗っ取り機の作成を行う。といっても何のことはない、ただのピンソケットとラズパイのGPIOの結合ケーブルだ。 秋月時計側向けにはオスのピンを用意し、ラズパイ側にはメスソケットを用意して、電線でつなぐ予定。 まずはPICと時計の配線図から、PICのソケットの必要な部分を洗い出してみる。

なんだかんだと、電源を除いて16ピン接続が必要になりそうだ。 せっかくなので、秋月時計の機能は一通り操作できるように、ラズパイに接続しておきたいと思う。
PIC側の差し替えは、ユニバーサル基盤にオスピンを接続して、ICっぽくしたものを作ってみる。

基盤を用意したら、PICサイズに合わせてユニバーサル基盤をカットする。 PICの周りに、ブザーやクリスタルがあるため、きっちりとICサイズにしておかないと干渉してしまう。

基盤をカットしたら、オスピンを差し込む。このようなダミーICを作り、 既存のソケットに差し込んで乗っ取る作戦だ。

秋月時計のソケットに差し込んで、周りとの干渉がないかを確認。特に問題なさそう。 このまますすめよう。

このICもどきゲタに、接続用の配線を取り付ける。 案外本数が多いと、大変だな。

次は、ラズパイ側に接続用の40ピンの雌コネクタを準備。 配線時に間違えないように、側面にはテプラでGPIOの番号を張り付けておいた。 また、ラズパイに差し込むときにも方向を間違えないように、内側、外側を記載しておいた。

では、ラズパイ用40ピンコネクタにもコードをつなぐ。 配線通りにつなぐのは大変だったので、電源以外は目についたケーブルを次々と接続してみた。 どれがどこにつながっているかは、後で手繰って調べよう。少し長めの線を外側に、短めの線を中心側につなげば、 大体うまくいくはずだ。

とりあえず全部接続できたので、何がどこにつながっているかを確認。 配線図にフィードバックしておく。

惨事

では接続。コネクタはなかなかに固く、刺さりが悪いが、しっかりと突き刺して接続する。 そして、ラズパイ側からGPIOを操作してみるが、反応がない。

その後、異臭があり気が付くとレギュレータがなんだか黒い。 あれ?と触ってみると猛烈に熱くなっていて、指を火傷した。やばい、何かひどい失敗をしているようだ。
ひとまず接続を外して秋月時計の基盤をよく見る。レギュレータがひどいことになっているが、 コンデンサなどはおかしなことにはなってなさそう。とりあえずレギュレータは破壊されたと思うので、とりはずす。 レギュレータや基盤あたりが丸焦げだ。火が出なくてよかった。

原因を考察。レギュレータの出力側のみに電源をつないでおり、入力側には何もつないでいないから、 それでレギュレータがやられたのかも。と思っていたが、よくよく調べてみると、あれ?電源逆じゃん!

5Vの電源はPICのVssにつながっており、GNDがVddにつながっているぞ? あれ、VddとかVssって何だっけ? こちらによると FET的なドレインとソースのことらしく、Vddがプラス側、Vssがマイナス側となる。 そして、今回はそれを逆につないでいた。プラスとマイナスを逆につないだら、そりゃ壊れるよな。

幸いなことに、壊れたのはレギュレータのみで、ほかは問題ないようだ。 LEDが主体の部品なので、逆電圧がかかっても導通しないだけだから、大丈夫だったのかも。 7セグも個別に通電確認すると動作するので、問題ないようだ。 電源は直接ICピン供給となるから、レギュレータは不要なので、コレだけが壊れたのなら影響はなさそう。よかった。

ピン更新

些細?なアクシデントがあったが、接続を変更すればよいので、電線の接続を修正。 ついでにICソケット側のピンも変更しようと思う。 ちょっと細いピンコネクタがあるのでこちらに引っ越しさせよう。もとのやつだとコネクタが硬くて大変。

初回と同様、基盤をカットし、細ピンをはんだで基盤に結合。一緒に電線も間違えないように移植。 電源ラインだけは正しく接続しなおせば完成だ。 う~んVssって何だよ。GNDにしておいてよ。いや自分の知識不足なだけなんだけどね。

ピンも細くなって差し込みやすくなり、ラズベリーパイと秋月時計を接続して、 ラズベリーパイ側から簡単にGPIOを操作してみる。 左から2つ目の出力を開き、7セグのgをオンにすると、予定通り7セグの真ん中の横棒が点灯した。 そのほかの7セグのa~fも点灯確認OKで、4桁それぞれで確認してみると、どれも制御ができた。 秋月時計とラズベリーパイの接続は完了だ。

最後に、最終版の接続図を載せておこう。電源は要注意だな。

GPIO制御

ハードウェア側の作成は終わったので、ソフト側の作成に取り掛かる。
まずはGPIO制御を行ってみる。bashでのコマンドで実施してみる。 以下のコマンドでPIOが制御可能。

# GPIO6の使用宣言
echo 6 > /sys/class/gpio/export
# GPIO6を出力用とする
echo out > /sys/class/gpio/gpio6/direction
# GPIO6をHighに
echo 1 > /sys/class/gpio/gpio6/value
# GPIO6をLowに
echo 1 > /sys/class/gpio/gpio6/value
# GPIO6を解放
echo 6 > /sys/class/gpio/unexport

今回の7セグはダイナミック点灯用の接続となっているので、 1か所のLEDをつけるには、2か所のGPIOをONにする必要がある。 左から2桁目の真ん中の横棒を点灯させる場合には、 桁選択となるGPIO25と7セグ操作のGPIO16をONにすればよい。

一通り試してみて、7セグとのLED接続は問題なし。 また、秋月時計基板上の黄色LEDについてはトランジスタ接続なしの直結なのだが、1kΩ抵抗で接続なので、 電流は3mA程度だと思うので、ラズベリーパイへの負担は少ない。こちらも操作ができて、点灯確認ができた。 またブザーがついているが、ジャンパでX-OutかY-Outにつないで制御となる。 こちらも電圧をかけるとブザーが鳴り問題なく動作できた。

プログラム

では、プログラム製造を行う。bashでガシガシ書いてもよいが、今回はラズパイらしくpyhonを使うこととする。 デフォルトでpythonが入っているが、バージョンを見ておく。

python --version

Python 3.9.2

まずは時計のために、現在時刻を知る必要がある。 datetimeモジュールで時刻を知ることができるようなので、以下のサンプルを作成して試す。

#!/usr/bin/env python3
 
import sys
import time
import datetime
from zoneinfo import ZoneInfo
 
if __name__ == '__main__':
  dt = datetime.datetime.now(ZoneInfo("Asia/Tokyo"))
  hh = str(dt.hour).rjust(2, '0')
  mm = str(dt.minute).rjust(2, '0')
  print(hh,mm,sep=':')
  print('%s%s:%s%s' % (hh[0],hh[1],mm[0],mm[1]))
  sys.exit()
$ python3 test_time.py
18:31
18:31

うまく現在時刻を拾うことができた。 後々、時分の4桁を使うこととなるので、各桁を取得できるようにしておいた。

次にpythonからのgpio制御だ。こちらはGPIOライブラリを使う。使い方は、
1.GPIO.setmode(GPIO.BCM)で、使用宣言
2.GPIO.setup( ピン番号, 入出力指定)で、ピンの使用方法定義(入力用か出力用か)
3.(出力時)GPIO.output(ピン番号、High/Low)
4.(終了時)GPIO.cleanup()でGPIOを開放
最後に解放をしておかないと、次動かすときにエラーが出てしまう。

では、簡単なサンプルを作って動かす。

#!/usr/bin/env python3
 
import RPi.GPIO as GPIO # RPi.GPIOモジュールを使用
import sys
 
def setup():
  # GPIO番号指定の準備
  GPIO.setmode(GPIO.BCM)
 
  # GPIO出力に設定
  GPIO.setup( 8, GPIO.OUT)
  GPIO.setup( 7, GPIO.OUT)
  GPIO.setup(25, GPIO.OUT)
  GPIO.setup( 5, GPIO.OUT)
   
  GPIO.setup( 6, GPIO.OUT)
  GPIO.setup(13, GPIO.OUT)
  GPIO.setup(26, GPIO.OUT)
  GPIO.setup(21, GPIO.OUT)
  GPIO.setup(20, GPIO.OUT)
  GPIO.setup(19, GPIO.OUT)
  GPIO.setup(16, GPIO.OUT)
 
# 表示桁を選択
def selectDigit(digit):
  GPIO.output( 8,GPIO.HIGH if (digit == 0x01) else GPIO.LOW)  # 1桁目
  GPIO.output( 7,GPIO.HIGH if (digit == 0x02) else GPIO.LOW)  # 2桁目
  GPIO.output(25,GPIO.HIGH if (digit == 0x04) else GPIO.LOW)  # 3桁目
  GPIO.output( 5,GPIO.HIGH if (digit == 0x08) else GPIO.LOW)  # 4桁目
 
# 数値表示
def setNumber(val):
  GPIO.output( 6, GPIO.HIGH)
  GPIO.output(13, GPIO.HIGH)
  GPIO.output(26, GPIO.HIGH)
  GPIO.output(21, GPIO.HIGH)
  GPIO.output(20, GPIO.HIGH)
  GPIO.output(19, GPIO.HIGH)
  GPIO.output(16, GPIO.LOW)
 
 
def loop():
  while True:
    setNumber(0)
    selectDigit(1)
 
def destroy():
  # GPIOを解放
  GPIO.cleanup()
  sys.exit()
 
if __name__ == '__main__':
  print ('Program is starting ... ')
  setup()
  try:
    loop()
    destroy()
    sys.exit()
  except KeyboardInterrupt:
    destroy()

右の桁に「0」を表示するだけなのだが、操作すべきピンが多いので、結構コマンドが必要だ。 しかし、しっかりと設定してやることで、表示できた。いい感じで動作した。

次に4桁表示を行う。 7セグは4桁分あるが、信号線の7セグ部分は4桁共通のダイナミックドライブで接続されている。 なので、1桁ずつ表示しては消してを各桁で高速で行うことで、4桁表示をする必要がある。 これをダイナミック点灯というらしい。

表示のさせ方は、
1.桁表示部分はスイッチを切った状態で7セグの表示設定を行う。
2.1桁目のスイッチを入れて、1桁目の数字を表示させる。
3.少しsleepを入れてしっかり表示
4.桁表示スイッチを切る。
5.次の桁で上記1から繰り返す
といったことを行う。高速で行うことで、4桁同時に表示しているようにみえるようになる。

ということで、試してみる。以下の処理でうまく表示ができた。

#!/usr/bin/env python3
 
import RPi.GPIO as GPIO # RPi.GPIOモジュールを使用
import time
import sys
 
# GPIO番号定義
gpio_keta = [8, 7, 25, 5]
gpio_7seg = [6, 13, 26, 21, 20, 19, 16]
 
def setup():
  # GPIO番号指定の準備
  GPIO.setmode(GPIO.BCM)
 
  # GPIO出力に設定
  for i in range(0, 4):
    GPIO.setup(gpio_keta[i], GPIO.OUT)
  for i in range(0, 7):
    GPIO.setup(gpio_7seg[i], GPIO.OUT)
 
# 表示桁を選択
def selectDigit(digit):
  for i in range(0, 4):
    GPIO.output(gpio_keta[i],GPIO.HIGH if (digit == 0x01<<i) else GPIO.LOW)
 
# 数値表示
def setNumber(val):
  for i in range(0, 7):
    GPIO.output(gpio_7seg[i], GPIO.HIGH)
 
def destroy():
  # GPIOを解放
  GPIO.cleanup()
  sys.exit()
 
def loop():
  while True:
    setNumber(0)
    selectDigit(1)
    time.sleep(0.1)
    setNumber(0)
    selectDigit(2)
    time.sleep(0.1)
    setNumber(0)
    selectDigit(4)
    time.sleep(0.1)
    setNumber(0)
    selectDigit(8)
    time.sleep(0.1)
 
if __name__ == '__main__':
  print ('Program is starting ... ')
  setup()
  try:
    loop()
    destroy()
    sys.exit()
  except KeyboardInterrupt:
    destroy()

しかし、この表示sleep時間を0.1秒としてみたが、これでは全然遅くて、 各桁を数字が流れて表示しているのが目に見えてわかる。 4桁同時に表示しているように見えるためには、もっと高速に表示させなければ駄目なようだ。

いろんなsleep値で試してみると、0.007秒(7ms)ではギリギリでチカチカがわかる感じ。 0.005秒(5ms)だとほぼ点滅しているのがわからない感じ。なので、0.004~0.003くらいのsleepで表示させてやれば 違和感なく4桁が表示できそうだ。4桁あるので16msくらいの周期で表示だ。

写真ではシャッタースピードの関係で、チカチカ感はあらわせられないなぁ。