Raspberry Pi でI2Cを使った7セグメントLEDで現在時刻を表示

[投稿日] 2015年10月9日
[最終更新] 2016年7月25日

00

Raspberry Piで7セグメントLEDを、I2Cで使用します。

スポンサーリンク

使ったもの

今回使ったのは、スイッチサイエンスで販売している「シリアル接続7セグメント4桁LED(緑) – スイッチサイエンス」です。色は赤とかもあります。

SPIやシリアル通信も対応しているのですが、UARTをこれで潰したくないなぁというのと、SPIは使ったことがないので、I2Cを使うことにしました。説明書きが一番多いのはシリアル通信なので、シリアル通信でやるのが一番安定しているのかなとも思います。

使用方法

接続とかI2C設定とか

Raspberry Pi で温度センサ LM75B を使う : 或る阿呆の記」の2、3節と同じなので繰り返しません。電圧は「Hardware specifications · sparkfun/Serial7SegmentDisplay Wiki · GitHub」によると2.4 – 6.0Vに対応しているようなので、3.3V でも 5V でも好きなほうでやればよいと思います。私は3.3Vでしています。他のI2C機器と電源を共有するときも、そちらのほうが都合がよいことが多いでしょう。

コマンド

基本的には、Linuxで使えるI2C用のコマンドでやりとりします。すなわちシェルスクリプトで簡単に書けるということで、たいへんお手軽です。なにはともあれ、機器のチップアドレスを確認します。

$ i2cdetect -y 1

引数の1は1chという意味で、-yは対話モードではないということです。昔のラズパイでは、0chのほうがデフォで使われていたようです。なお、初期設定では、0x71となっています。

チップアドレスがわかったら、今度は機器のデータアドレスを調べて、任意のビットを送るようにします。アドレスについては「Special Commands · sparkfun/Serial7SegmentDisplay Wiki · GitHub」を参照します。

まず、ディスプレイをクリアしてみます。

$ i2cset -y 1 0x71 0x76

チップアドレス0x71にある機器の、0x76にビットを送っています。ディスプレイがクリアされたら、今度は数値を入力してみます。以下のコマンドで、下一桁を1にすることができます。

$ i2cset -y 1 0x71 0x7e 0x06

データアドレス0x7eに、データ0x06を送っています。これで、1が表示されたはずです。なぜ0x06で1になるかですが、7セグメントの一つ一つにビットが割当られており、7ビット、即ち127パターンの表示が可能で、1になるような光らせ方は0x06ということです。127パターンといっても実際に使うのは0-9の10パターンと、せいぜいマイナスくらいでしょう。毎回計算するのでは煩わしいですから、使いやすいように、以下のようなシェルスクリプトを組んでみました。仮に7seg-disp.shとします。

#!/bin/bash
set -eu
address=0x71
# 上一桁目から下一桁目 0x77はコロンなどに用いる
digit=(0x7b 0x7c 0x7d 0x7e 0x77)
# 0,1,2,..,9
num=(0x3f 0x06 0x5b 0x4f 0x66 0x6d 0x7d 0x27 0x7f 0x6f)
i2cset -y 1 $address ${digit[$1]} ${num[$2]}

digitが、桁数のデータアドレスで、numが数値を表示するためのデータです。このシェルスクリプトを、たとえば以下のように実行してやると、2015と表示できます。

./7seg-disp.sh 0 2
./7seg-disp.sh 1 0
./7seg-disp.sh 2 1
./7seg-disp.sh 3 5

第一引数が桁数の指定で、第二引数が数値の指定となっています。簡単な使い方としては、こんなところです。

現在時刻を表示してみる

上記のスクリプトをもうちょっと拡張して、現在時刻を表示するようにしてみます。まず、7seg-disp.shを以下のようにします。

#!/bin/bash
set -eu
function help_msg(){
echo "usage: ${0} digit num"
echo "digit: 0,1,2,3,dot,colon,minus"
echo "num(digit 1-4): 0,1,2,..,9"
echo "num(dot): 0,1,2,3,4"
echo "num(colon,minus): needless"
exit 0
}
if [ $# -eq 0 ]; then help_msg; fi
if [ $1 = "-h" ]; then help_msg; fi
address=0x71
# 0x7b 0x7c 0x7d 0x7e, :. -> 0x77
digit=(0x7b 0x7c 0x7d 0x7e 0x77)
# 0,1,2,..,9
num=(0x3f 0x06 0x5b 0x4f 0x66 0x6d 0x7d 0x27 0x7f 0x6f)
minus=0x40
colon=0x10
dot=(0x10 0x01 0x02 0x04 0x08)
if [ $1 = "colon" ]; then i2cset -y 1 $address ${digit[4]} $colon; exit 0;fi
if [ $1 = "dot" ];then i2cset -y 1 $address ${digit[4]} ${dot[$2]}; exit 0;fi
if [ $1 = "minus" ];then i2cset -y 1 $address ${digit[0]} $minus; exit 0;fi
i2cset -y 1 $address ${digit[$1]} ${num[$2]}

変わったところは、ヘルプメッセージを出力できること、マイナス、コロン、ドット(小数点)に対応しているところです。使用方法は ./7seg-disp.sh -h でだいたいわかるはずとして、これを利用し、時刻を表示するようなスクリプトを組みます。7seg.sh とします。7seg.shと7seg-disp.shは同じディレクトリに置きます。

#!/bin/bash
#################################################
# 現在時刻を7seg-LEDで表示するためのスクリプト
# 同じディレクトリに 7seg-disp.sh が必要
#################################################
set -u
cd $(dirname $0)
current_dir=`pwd`
# clear display
i2cset -y 1 0x71 0x76
now=`date +%H%M`
digit=(`echo $now | cut -c 1` `echo $now | cut -c 2` `echo $now | cut -c 3` `echo $now | cut -c 4`)
for i in `seq 0 3`; do
${current_dir}/7seg-disp.sh $i ${digit[$i]}
done
${current_dir}/7seg-disp.sh colon

上記スクリプトをそのまま実行すると、現在時刻が表示されます。冒頭のゴチャゴチャした写真がそれです。16時04分ですね。

$ ./7seg.sh

以上です。まだしっかり使っていないのですが、I2Cだと長時間運用してるとけっこうエラーも頻発していて、あまり安定していないのかもしれません。UARTが空いてるなら、シリアル通信のほうがいいのかな?時間を見つけてそのうちやってみようと思います。

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。