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が空いてるなら、シリアル通信のほうがいいのかな?時間を見つけてそのうちやってみようと思います。
コメント