今回は秋月さんで販売されているSPI通信で操作可能な7セグをRaspberryPiで使ったみたいと思います。ちなみに、自分はプログラムは得意という感じでもないので、コードが汚かったり、良い書き方があると思いますがご了承ください。
7セグが手軽に扱えるモジュール
一般的な7セグを使用するときは、回路が複雑になりがちですが、秋月電子で販売されている、7セグメントLEDシリアルドライバキット(DIP化キット LED別売)を使うと、桁数を増やしても回路が比較的簡単に組めます。
今回使用した7セグ
今回は、最初からLEDが実装されている、
赤色7セグメントLEDシリアルドライバモジュール 完成品
を使いました。はんだ付けをする手間が省けますし、シリアルドライバモジュール+LED単体と比べると、1つ15円の差です。(これを安いと捉えるか高いと捉えるかは人次第)
1桁 0から9までのカウントアップ
回路図
RaspberryPiと7セグの接続を以下に示します。
SPI通信させますが、7セグからRaspberry Piにはデータを送らないので、MISOピンは使用しません。
電源は5Vでもいけますが、3.3Vでも問題なく動作したので、3.3Vにしました。
SPI有効化
まだRaspberry PiのSPI通信を有効化していない場合は有効化します。
以下のコマンドを入力します。
sudo raspi-config
次に、以下のように、Interfacing Optionsを矢印キーで選んでEnterします。
SPIを選びます。
Yesを選択します。
OKを選択します。
メニュー画面に戻るので、ESCキーで終了させます。
プログラム
実行方法:例えばファイル名が7seg.pyなら以下のようにして実行します。
python 7seg.py
以下のようにPythonでコードを書きました。実行すると、7セグがインクリメント(0.5秒毎)し、ループします。0,1,2・・・9→0,1,2,・・のような感じです。
import spidev import time dot = 0b10000000 data = [0b00111111,#0 0b00000110,#1 0b01011011,#2 0b01001111,#3 0b01100110,#4 0b01101101,#5 0b01111101,#6 0b00000111,#7 0b01111111,#8 0b01101111]#9 spi = spidev.SpiDev() spi.open(0,0) spi.max_speed_hz = 1000000 while True: for i in range(10): spi.xfer([data[i]]) time.sleep(0.5)
SPI通信させるとき、WiringPiを使おうと思ったのですが、ループ文で動きがおかしくなってしまい、時間かかったのですが、spidevを使ったことによりうまく動くようになりました。
動作ついてですが、以下のように7セグの各LEDにはアルファベットが割当てられています。秋月電子のArduinoのサンプルプログラムを見る限り、この7セグシリアルドライバに SPI 通信を用いてDP,G,F,E,D,C,B,Aの順で 0 or 1を送信すれば良さそうです。(合計8bit)
例えば、7を表示したいときは、AとBとCだけ光らせれば良いので、00000111を送信すれば良いです。
ちなみに、秋月電子のサンプルプログラムでは7のとき11100000を送っていますが、設定で最下位ビット(LSB)から送信しているので、順番的には00000111を送っていることになります。
2桁 0から99までのカウントアップ
回路図
今度は7セグを2つに増やして0から99をカウントしていくものを作ります。
前回と違う点はSDOを使う点です。SDOはデータをアウトプットするピンで、SDIはデータをインプットするピンです。(図中の注意と書いてある部分です。)
つまり、7セグ(1の位)のSDOから7セグ(10の位)のSDIに配線します。
プログラム
以下を実行すると、0.2秒ごとに0から99までのインクリメントをループします。
import spidev import time dot = 0b10000000 data = [0b00111111,#0 0b00000110,#1 0b01011011,#2 0b01001111,#3 0b01100110,#4 0b01101101,#5 0b01111101,#6 0b00000111,#7 0b01111111,#8 0b01101111]#9 spi = spidev.SpiDev() spi.open(0,0) spi.max_speed_hz = 1000000 while True: for i in range(10): for j in range(10): spi.xfer([data[i]])#10 spi.xfer([data[j]])#1 time.sleep(0.2)
動作としては、以下のようになります。うまく説明できないので例なのですが・・
- 現在19を表示している状態とします。ここから20に変えようとします。
- まず、ラズパイは7セグ(1の位)に2を表示させるデータを送信します。
- 7セグ(1の位)は7セグ(10の位)に9を表示させるデータを送信し、2を表示します。
- 7セグ(10の位)は9を表示します。
この時点で92となります。(これは目に見えない速さ変わっているのでわからない) - 次に、ラズパイは7セグ(1の位)に0を表示させるデータを送信します。
- 7セグ(1の位)は7セグ(10の位)に2を表示させるデータを送信し、0を表示します。
- 7セグ(10の位)は2を表示します。これで20となります。
最初からここまで一瞬で処理します。 - 0.2秒待ちます。つまり、20という状態を0.2秒間維持することによって、やっと目に20が見えます。
こんな感じで、SDOからは7セグが持っていた数字を出力しています。試しに、time.sleep文を間に噛ませると、この動作がわかりやすいと思います。
5桁にして遊ぶ
回路図
最後に5桁に挑戦してみます。回路は2桁と同じようにSDO→SDIというのだけ注意すれば組めます。
プログラム1
以下を実行すると、00000から99999までのインクリメントをループします。
import spidev import time dot = 0b10000000 data = [0b00111111,#0 0b00000110,#1 0b01011011,#2 0b01001111,#3 0b01100110,#4 0b01101101,#5 0b01111101,#6 0b00000111,#7 0b01111111,#8 0b01101111]#9 spi = spidev.SpiDev() spi.open(0,0) spi.max_speed_hz = 1000000 while True: for num in range(99999): num=(str(num)).zfill(5) spi.xfer([data[int(num[-5])]]) spi.xfer([data[int(num[-4])]]) spi.xfer([data[int(num[-3])]]) spi.xfer([data[int(num[-2])]]) spi.xfer([data[int(num[-1])]]) time.sleep(0.005)
プログラム2
以下を実行すると000.00から999.99までのインクリメントをループします。
import spidev import time dot = 0b10000000 data = [0b00111111,#0 0b00000110,#1 0b01011011,#2 0b01001111,#3 0b01100110,#4 0b01101101,#5 0b01111101,#6 0b00000111,#7 0b01111111,#8 0b01101111]#9 spi = spidev.SpiDev() spi.open(0,0) spi.max_speed_hz = 1000000 while True: for num in range(99999): num=(str(num)).zfill(5) spi.xfer([data[int(num[-5])]]) spi.xfer([data[int(num[-4])]]) spi.xfer([data[int(num[-3])]|dot]) spi.xfer([data[int(num[-2])]]) spi.xfer([data[int(num[-1])]]) time.sleep(0.005)
このプログラムで何をしたいかと言うと、
spi.xfer([data[int(num[-3])]|dot])
の部分で|dotとすれば、ドットを表示できるということを示したかっただけです。
プログラム3
以下のプログラムはユーザーから入力された値を表示します。
0~99999までなら表示します。
入力した値に対する表示例
- 0→00000.
- 0.00000001→0.0000
- 1→00001.
- 1.23456789→1.2345
- 12.3456789→12.345
- 0.12→000.12
- 1234→01234.
- 12345.6→12345.
ちなみに、自分はプログラムは得意という感じでもないので、コードが汚かったり、もう少しスマートなアルゴリズムや良い書き方があると思いますが、とりあえずこれで動いたのでご報告です。
日本語でコメント文ついていますが、実行してエラーになった場合は
「python3 ○○.py」
のようにpython3で実行してみてください。
import spidev dot = 0b10000000 data = [0b00111111,#0 0b00000110,#1 0b01011011,#2 0b01001111,#3 0b01100110,#4 0b01101101,#5 0b01111101,#6 0b00000111,#7 0b01111111,#8 0b01101111]#9 spi = spidev.SpiDev() spi.open(0,0) spi.max_speed_hz = 1000000 while True: number=input("input here-->")#ユーザから入力を待つ if not 0 <= float(number) <= 99999:#不正な値をチェック print("Please enter 0~99999") continue number=number.zfill(6)#6桁に調整。例0.123456789→0.1234 例123→00123 digit=[number[0],number[1],number[2],number[3],number[4],number[5]]#一桁ずつに分解 for i in range(6):#dot+5桁分で6回ループ。小数点のいちを探してdot_placeに格納。 dot_place=6#初期値は1の位の7セグに小数点が来るようにしている。整数12345の場合12345.と表示するため。 if digit[i]==".": dot_place=i break for i in range(6):#表示する部分。万の位から順番に処理。 if i==dot_place-1:#例123.45のとき、小数点の位置は左から4番目だが、3桁目のときに3と小数点を同時に送るためdot_place-1になっている。 spi.xfer([data[int(digit[i])]|dot])#小数点付きで送信 elif i==dot_place:#小数点は上で送信済みなので、ここは通過。 continue else: spi.xfer([data[int(digit[i])]])#普通に送信
動作についてはコメント文を参照してください。
まとめ
秋月電子通商さんで販売されている、SPI通信で扱える7セグは配線量も少なく、プログラムもわかってしまえば、使いやすいのでおすすめです!
ラズパイ初心者です。SPI有効化などトラップされる個所が丁寧に書かれていて、また一桁から順番に書かれていて、分かり易く、漸く理解できそうな気がしてきました。できましたら、pin番号の設定部分のプログラムも公開していただければ、と思います。また、GPIO8番ピンのLatch制御文はどこに書かれているのでしょうか?加えて、Latchピンを他のGPIOピンに割り当てることは可能でしょうか? 74HC595の役割もわかってきましたが、いざ細部になると???です。
これまで4桁のダイナミック接続表示を考えていたのですが、pin数の使用量が半端なく、また表示だけのためにCPUのパワーを消費しプログラムも制限(高速で表示を繰り返さないとチラつく)されそうに思えてうんざりしていました。