半年ほど就活に専念するため、ブログの更新をしていませんでしたが、なんとか就活の方が落ち着いてきたのでまたブログを再開しようと思います。
就活中はブログは一時中断していましたが、電子工作の方は続けていたので、ここ半年間で行ってきた電子工作(主にスマートホーム関連)を今後少しづつ紹介していこうと思います!
今回は電子工作に関する記事です。
SPI通信により8つの7セグLEDを 制御できるモジュールを購入したので、この使い方について紹介します。
8桁 LED 表示管7セグメント74HC595 モジュール
Raspberry Pi4 ModelB 4GB ラズベリーパイ4 技適対応品
もともと7セグLEDの制御を行ってみようと思ていたのですが、 ロジックIC を使用せず直で扱おうとすると1個の7セグLEDに対して7つ配線を引かなければならず、複数の7セグLEDを扱おうとすると配線が複雑になり、とても面倒くさそうだったので避けていました。
そんな時にこのロジックIC( 74HC595 ) 付きの7セグLEDを見つけました。
こちらはSPI通信により、電源とグランドの2線 + 信号線3線の合計5本の線で8個の7セグLEDを制御することができます。
また、このモジュールは複数連結することもできるので、16個、24個、32個・・・と、5本の線で好きなだけ制御することができるんです!
今のところ使用する予定はないのですが衝動買いしてしまいました(笑)
購入していざ実装してみようと思ったのですが、ArduinoやC言語を使用したサンプルコードなどは見つかったのですが、ラズベリーパイを使用した例が見つからなかったので、備忘録として、ラズベリーパイとの接続方法とpythonのサンプルコードをこの記事に記載します。
目次
回路図(接続方法)
回路はこんな感じです。
電源とGNDを含めた合計5つの線をつなぐだけです。
SPI通信をするにはラズベリーパイ上の専用のピンを使用しなければならないので、間違えずに配線してください。
プログラム・動作
まず、ラズベリーパイの設定からSPI通信を有効にします。
下図のように、「MENU(ラズベリーのマーク)」 -> 「設定」-> 「Raspberry Pi の設定」へと進みます。
すると、以下のような設定画面が表示されるので、「インターフェイス」のタブをクリックし、SPIの欄を有効にします。
以上で設定は完了です。続いてプログラムを実行します。
今回サンプルプログラムとして、以下の3つのプログラムを作成しました。
- サンプルプログラム(0~9、A~Zを順に表示していくプログラム)
- 時計プログラム( 現在の時刻を表示するプログラム )
- 3分タイマープログラム(指定時間カウントダウンを行うプログラム)
各プログラムについて記載していきます。
・サンプルプログラム
これは、動作確認用のプログラムです。
1から9の数字が左から右へ順に表示され、一秒暗転した後、AからZのアルファベットが同様に表示されるプログラムです。
ソースコードを以下に記載します。
# coding: UTF-8
import spidev
import time
#///// SPI設定 /////
spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 1000000
#///// 出力データ配列 /////
#数字 0 1 2 3 4 5 6 7 8 9
number_data = [0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90]
#アルファベット a b c d e f g h i j k l m n o p q r s t u v w x y z
alphabet_data = [0xA0,0x83,0xa7,0xa1,0x86,0x8e,0xc2,0x8b,0xe6,0xe1,0x89,0xc7,0xaa,0xc8,0xa3,0x8c,0x98,0xce,0x9b,0x87,0xc1,0xe3,0xd5,0xb6,0x91,0xb8]
#記号等 . ハイフン space 全埋め
symbol_data = [0x7f,0xbf,0xff,0x00]
#///// 出力 /////
#表示リセット
for index in range(8):
spi.xfer([0xff])
time.sleep(1)
#1-9を順に表示
for data in number_data:
spi.xfer([data])
time.sleep(1)
#表示リセット
for index in range(8):
spi.xfer([0xff])
time.sleep(1)
#A-Zを順に表示
for data in alphabet_data:
spi.xfer([data])
time.sleep(1)
・時計プログラム
これは、現在の時間が表示されるプログラムです。
プログラム中の now_date の部分のコメントアウトを外し、出力データの部分を変えるとカレンダーとしても使用できます。
ソースコードを以下に記載します。
# coding: UTF-8
import spidev
import time
import datetime
#///// SPI設定 /////
spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 1000000
#///// 文字を7セグLED用の16進数に変換する関数 /////
def chr_to_7segData(chr):
return_data = ""
if chr == "0":
return_data = 0xc0
elif chr == "1":
return_data = 0xf9
elif chr == "2":
return_data = 0xa4
elif chr == "3":
return_data = 0xb0
elif chr == "4":
return_data = 0x99
elif chr == "5":
return_data = 0x92
elif chr == "6":
return_data = 0x82
elif chr == "7":
return_data = 0xf8
elif chr == "8":
return_data = 0x80
elif chr == "9":
return_data = 0x90
elif chr == "a":
return_data = 0xA0
elif chr == "b":
return_data = 0x83
elif chr == "c":
return_data = 0xa7
elif chr == "d":
return_data = 0xa1
elif chr == "e":
return_data = 0x86
elif chr == "f":
return_data = 0x8e
elif chr == "g":
return_data = 0xc2
elif chr == "h":
return_data = 0x8b
elif chr == "i":
return_data = 0xe6
elif chr == "j":
return_data = 0xe1
elif chr == "k":
return_data = 0x89
elif chr == "l":
return_data = 0xc7
elif chr == "m":
return_data = 0xaa
elif chr == "n":
return_data = 0xc8
elif chr == "o":
return_data = 0xa3
elif chr == "p":
return_data = 0x8c
elif chr == "q":
return_data = 0x98
elif chr == "r":
return_data = 0xce
elif chr == "s":
return_data = 0x9b
elif chr == "t":
return_data = 0x87
elif chr == "u":
return_data = 0xc1
elif chr == "v":
return_data = 0xe3
elif chr == "w":
return_data = 0xd5
elif chr == "x":
return_data = 0xb6
elif chr == "y":
return_data = 0x91
elif chr == "z":
return_data = 0xb8
elif chr == ".":
return_data = 0x7f
elif chr == "-":
return_data = 0xbf
elif chr == " ":
return_data = 0xff
else:
return_data = 0xff
print("error")
return return_data
#データ出力
def send_data(data_chr):
#表示する8文字のデータが入った配列の用意
output_data = []
for x in data_chr:
Converted_data = chr_to_7segData(x)
output_data.append(Converted_data)
#配列を逆順にセット
output_data.reverse()
#出力(SPI通信)
for data in output_data:
spi.xfer([data])
while True:
output_data = []
now = datetime.datetime.today()
#時刻取得
now_time = '{0:%H.%M.%S}'.format(now)
#日付取得
# now_date = '{0:%Y%m%d}'.format(now)
#表示
send_data(now_time)
time.sleep(1)
・3分タイマープログラム
これは指定した時間カウントダウンを行い、最後にENDの文字を表示するプログラムです。
このプログラムでは秒を分や時に単位変換するモジュールを使用したので、実行する前に以下のコマンドで dateutil ライブラリーをインストールする必要があります。
pip install dateutils
ソースコードを以下に記載します。
# coding: UTF-8
import spidev
import time
import datetime
from dateutil.relativedelta import relativedelta
#///// SPI設定 /////
spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 1000000
#///// 文字を7セグLED用の16進数に変換する関数 /////
def chr_to_7segData(chr):
return_data = ""
if chr == "0":
return_data = 0xc0
elif chr == "1":
return_data = 0xf9
elif chr == "2":
return_data = 0xa4
elif chr == "3":
return_data = 0xb0
elif chr == "4":
return_data = 0x99
elif chr == "5":
return_data = 0x92
elif chr == "6":
return_data = 0x82
elif chr == "7":
return_data = 0xf8
elif chr == "8":
return_data = 0x80
elif chr == "9":
return_data = 0x90
elif chr == "a":
return_data = 0xA0
elif chr == "b":
return_data = 0x83
elif chr == "c":
return_data = 0xa7
elif chr == "d":
return_data = 0xa1
elif chr == "e":
return_data = 0x86
elif chr == "f":
return_data = 0x8e
elif chr == "g":
return_data = 0xc2
elif chr == "h":
return_data = 0x8b
elif chr == "i":
return_data = 0xe6
elif chr == "j":
return_data = 0xe1
elif chr == "k":
return_data = 0x89
elif chr == "l":
return_data = 0xc7
elif chr == "m":
return_data = 0xaa
elif chr == "n":
return_data = 0xc8
elif chr == "o":
return_data = 0xa3
elif chr == "p":
return_data = 0x8c
elif chr == "q":
return_data = 0x98
elif chr == "r":
return_data = 0xce
elif chr == "s":
return_data = 0x9b
elif chr == "t":
return_data = 0x87
elif chr == "u":
return_data = 0xc1
elif chr == "v":
return_data = 0xe3
elif chr == "w":
return_data = 0xd5
elif chr == "x":
return_data = 0xb6
elif chr == "y":
return_data = 0x91
elif chr == "z":
return_data = 0xb8
elif chr == ".":
return_data = 0x7f
elif chr == "-":
return_data = 0xbf
elif chr == " ":
return_data = 0xff
else:
return_data = 0xff
print("error")
return return_data
#データ出力
def send_data(data_chr):
#表示する8文字のデータが入った配列の用意
output_data = []
for x in data_chr:
Converted_data = chr_to_7segData(x)
output_data.append(Converted_data)
#配列を逆順にセット
output_data.reverse()
#出力(SPI通信)
for data in output_data:
spi.xfer([data])
set_time = 60 #秒
now_time = set_time
while True:
time_str = "{0.hours:02}.{0.minutes:02}.{0.seconds:02}".format(relativedelta(seconds=now_time))
send_data(time_str)
time.sleep(1)
now_time -= 1
if now_time<=0:
send_data("---end--")
break
解説
まず、サンプルプログラムの 出力データ配列 について解説します。
このモジュールは一文字ずつしかデータを送ることはできず、その送るデータは16進数に変換して送ります。
16進数への変換方法ですが、まず光らせたいセグメントを0とし、光らせたくないセグメントを1として2進数を作ります。
例えば下図のABCDEFだけを光らせて0という文字を作りたい場合は
(HGFEDCBA)
11000000
というようにします。
次にこれを16進数に変換します。これは10進数だと192、16進数だとc0となります。
プログラム上では16進数を表す場合は先頭に0xを付けることになっているので、0xc0 を送れば0が出力されるということになります。
このようにして、16進数を送信することで任意の文字を表示させることができます。
データの送信は
spi.xfer()
により、行うことができます。
次に、時計プログラムとタイマープログラムについてです。
サンプルプログラムでは一文字ずつ送信していましたが、時計やタイマーのように同じフォーマットで表示を行うには、8文字を1セットとして送信することを繰り返すことにより行います。(紛らわしい表現ですが、8文字を同時に送信するということではなく、 8文字を1文字ずつ高速で送信するという意味です。)
送信する際に配列データを反転させている理由についてですが、
このモジュールは、データを送ると下図のように一番左に新しいデータが入り、既に入っていたデータは右隣のLEDへと移動していく、という仕様になっているからです。
よって、例えば12345678というデータを順に送るとすると、全てのデータを送信した後には87654321というようにデータが逆になって表示されてしまいます。
このようにそのまま送信すると反転して表示されてしまうため、データを送信する前にデータ配列をいったん反転させてから送信しています。
まとめ
今回は基礎的な部分の紹介でした。冒頭でも書きましたが、このモジュールは複数連携することができるので、色々と応用できそうです!
せっかくなので、このモジュールと何かしらのAPIを使用して何かしらのデータを表示するプログラムを作ってみようかなと思っているのですが、なかなかアイデアが思い浮かばないため、何か思いついたらまた紹介します(笑)
こうする他ないのでしょうか❓?(笑)
コメントありがとうございます。
どの部分のことでしょうか?