2026-08-24 完成!
2026-08-20 書きかけ
7セグメントLED4桁を制御してみようと考えた。BBBに直接つないでやろうとしたんだ…
BBB本体のコネクタにジャンパー飛ばそうとしたんだけど、刺す個数が増えると段々狭くてジャンパー線が刺せなくなっていく……
先の写真に写っている、よく見かけてそうな四角形の部品は 5641AS の名前を持つ7セグメントLED。
1桁が7個+1個のLEDで構成されていて、点灯するLEDの組み合わせで数字や英字の一部を表示できる。
LEDのカソードはすべて共通のPINに纏まっている。※コモンカソード
LEDにはa~gとpの名前が付いていて各LEDのアノードに接続されたPINがある。カソードのPINをLowにして、LEDのアノードPINをHighにするとそのLEDが点灯する。
アノードに接続された各PINには直接信号を入力しない。電流制限抵抗を配置して過電流が流れる事を防ぐ。
この図で “p” と表示している名称は、他の説明だと“DP”や“D.P”、“dp”や“dot”だったりもする。
※AIさんが注記しろというので書いておく
今回のパーツでは4桁分のLED群が付いていて、ピンアサインは以下のようになる。
| PIN | LED/Digit |
|---|---|
| 1 | e |
| 2 | d |
| 3 | p |
| 4 | c |
| 5 | g |
| 6 | Dig4 |
| 7 | b |
| 8 | Dig3 |
| 9 | Dig2 |
| 10 | f |
| 11 | a |
| 12 | Dig1 |
PINの12番・9番・8番・6番はそれぞれ左から1~4桁目のLED群のカソードに接続されているPIN。PINをLowにするとその桁のLED群がPINの1~5番,7番,10番および11番の設定に従って点灯する。
PINの1~5番,7番,10番および11番はLED a~gおよびpの制御用。各桁の各LEDのアノードに接続されていて、各PINのHigh/Lowの組み合わせで数字を点灯する。
そして、結線図から一度に1つの数字の指定しかできないと分かる。例えば12番・9番をLowにすると1桁目と2桁目のLED群に同じ数字が表示される。つまり同時に各桁へ異なる数字を指定できない。
ではどうやって各桁のLEDに個別の数字を表示するかというと……
人間の視覚には残像効果があり、光が消えても像がしばらく消えずに残り続ける。
一般的なLEDの光であれば、個人差はあるが数十ミリ秒間像が残る。
言い換えると、充分に短い間隔で各桁に異なる数字を表示・消灯を繰り返すと、人間の眼には各桁のLED群に異なる数字が連続して表示されているように見えてしまう。
例えば
を十分に短い間隔で繰り返すとあら不思議、“1234”の4桁が表示されているように見える。という力技で実現している。
このように各桁を高速に切り替えて表示する方法を「ダイナミック点灯」と呼ぶ。ダイナミック過ぎ。
コネクタ付きのジャンパーで飛ばせば楽になるんじゃないかな?と素人ながら考えて、ユニバーサル基板とコネクタ付きジャンパー線、半田と半田ごてをAmazonさんでポチり、5641AS専用基板を作る事にした。
ピンヘッダを付ける。桁選択のPIN、LEDのPINをユニバーサル基板上で整理してピンヘッダと繋ぐ。
図を書いてて最後になって「あれそういや電流ナンボ流れるんだ?」と計算させたら… むちゃくちゃデカイやんけ!!!
手持ちの5641ASのデータシートが無いけど、とりあえず1個のLEDに流れる電流を計算する。適当に検索すると1.8Vfと2.0Vfで計算するようなので
(3.3V - 1.8V) ÷ 330Ω ≒ 4.6mA
(3.3V - 2.0V) ÷ 330Ω ≒ 4.0mA
1桁のLEDが全部で7+1個だから8個。1桁のLED全部を光らせたとすると
4.6mA × 8 ≒ 37mA
4.0mA × 8 ≒ 32mA
こんな大電流入れたら物理的に炎上するじゃん……もう駄目だー
ChatGPTさんに相談したところ、トランジスタ S8050 を使ってみようと提案される。ただ、手元のものは別用途で使うので 2SC1815 を利用する事に。
この構成はトランジスタをスイッチ的に使いかつBBBのGPIOに流れる電流を制限するためのもの。LEDへの電流制限用途ではない。
最初の基板だと DigNのPINがLowの時にN桁目のセグメントLEDが点灯する予定だったが、この基板はPINがHighになった時にLEDが点灯する仕様になる。※まぁ分かり易くていいんじゃない?
このトランジスタはNPN接合のバイポーラトランジスタと呼ばれる奴で、ベースに電流を流すとコレクタ‐エミッタ間に電流が流れ出す。
信号の増幅に使うこの動作を、今回はスイッチとして利用している。
エミッタをGND、コレクタをLEDのカソードに接続して、ベースから電流を流すとコレクタはエミッタを通してGNDに繋がった状態になる。つまりLow状態になる。
LED側の電流はコレクタからエミッタを経由してGNDへ流れ、BBBのGPIOにはベースを制御するための電流だけが流れる。BBBのGPIOに先の基板で計算した大電流が流れることも無い。ハズだ…
GPIOのPINに接続されるDigNには1.5kΩの抵抗を接続してある。
(3.3V - 0.6V) ÷ 1.5kΩ ≒ 1.8mA
(3.3V - 0.7V) ÷ 1.5kΩ ≒ 1.7mA
なので、GPIOのPINに過大な電流が流れる事も無い。
0.6V~0.7Vはトランジスタが正常稼働している時にベース‐エミッタ間にかかる電圧。3.3Vからこの電圧を引いたものと流す予定の電流から抵抗を逆算した結果に近いパーツをチョイスしよう。
部品が全部実装された状態。裏面はジャンパー線が飛びまくってる。配線図みたいに配置しようとするとすごい面倒なので手を抜いている配置。
作業途中の写真。ハンダ付け時の都合で基板を固定するためにピンヘッダを仮で付けたりしてある。
1.5kΩの抵抗がどこにも無いので1kΩで再計算。行けそうなのでこちらで代替。
この後テスターでショートの確認を実施。不要になったピンヘッダ取り外しをした。
ショートの確認も終わってBBBに接続した図。この接続は1桁のLED点灯確認用。
Pythonのスクリプトを用意した。BBBのP8_46とP8_42のPINをHighにし続ける。
#!/usr/bin/python import gpiod import time select_chip1 = gpiod.Chip("gpiochip2") line_DigSel = select_chip1.get_line( 7) # P8_46 line_LedOnX = select_chip1.get_line(11) # P8_42 line_DigSel.request( consumer="7SEGTESTD", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnX.request( consumer="7SEGTESTL", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_DigSel.set_value(1) # 1桁目選択 line_LedOnX.set_value(1) # LED点灯 input("ENTERキーで終了.")
sudo ./7SegChk.pyでスクリプト実行後、ブレッドボードの配線を差し替えて点灯箇所を確かめる。
アチャー、しょっぱなから配線間違えてんな… ※Dig1端子がDig2に繋がってる
LEDのa~g、pの点灯を確認すると…端子とPINの接続間違い多数(;・∀・)
ハンダ付けし直す気はもう無いので基板上のピンアサインは以下と決定!
| 基板端子 | 仕様 | 確認結果 |
|---|---|---|
| a | LED a 点灯 | NG ‐ f が点灯した |
| b | LED b 点灯 | OK ‐ b が点灯した |
| c | LED c 点灯 | OK ‐ c が点灯した |
| d | LED d 点灯 | OK ‐ d が点灯した |
| e | LED e 点灯 | NG ‐ p が点灯した |
| f | LED f 点灯 | NG ‐ g が点灯した |
| g | LED g 点灯 | NG ‐ a が点灯した |
| p | LED p 点灯 | NG ‐ e が点灯した |
| Dig1 | 1桁目選択 | NG ‐ 2桁目が選択された |
| Dig2 | 2桁目選択 | NG ‐ 1桁目が選択された |
| Dig3 | 3桁目選択 | OK ‐ 3桁目が選択された |
| Dig4 | 4桁目選択 | OK ‐ 4桁目が選択された |
| GND | GND | OK(でなきゃ点灯しないよ!) |
幸運な事にPINの制御で必要なLEDを点灯できる事は判明したので、これらはソフトウエアで対処する事にする。
Pythonを使う。ちょっとデバッグをChatGPTさんに手伝ってもらった。
表示する文字を渡して対応するパターンのPIN信号を出力する。
このデモは1桁目のLEDに0~9の数字を1秒間隔で表示するデモ。
#!/usr/bin/python import gpiod import time message="0123456789" PIN_Signals = [ ("0" ,(1,1,1,1,1,1,0,0)), ("1" ,(0,1,1,0,0,0,0,0)), ("2" ,(1,1,0,1,1,0,1,0)), ("3" ,(1,1,1,1,0,0,1,0)), ("4" ,(0,1,1,0,0,1,1,0)), ("5" ,(1,0,1,1,0,1,1,0)), ("6" ,(1,0,1,1,1,1,1,0)), ("7" ,(1,1,1,0,0,0,0,0)), ("8" ,(1,1,1,1,1,1,1,0)), ("9" ,(1,1,1,1,0,1,1,0)), ] select_chip0 = gpiod.Chip("gpiochip0") select_chip2 = gpiod.Chip("gpiochip2") line_Dig4 = select_chip2.get_line( 6) # P8_45 line_Dig3 = select_chip2.get_line( 8) # P8_43 line_Dig2 = select_chip2.get_line(12) # P8_39 line_Dig1 = select_chip2.get_line(10) # P8_41 line_LedOna = select_chip2.get_line(11) # P8_42 line_LedOnb = select_chip2.get_line(17) # P8_34 line_LedOnc = select_chip2.get_line(16) # P8_36 line_LedOnd = select_chip2.get_line(15) # P8_38 line_LedOne = select_chip2.get_line(13) # P8_40 line_LedOnf = select_chip0.get_line(11) # P8_32 line_LedOng = select_chip2.get_line( 9) # P8_44 line_LedOnp = select_chip2.get_line( 7) # P8_46 line_Dig4.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig3.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig2.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig1.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnp.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOng.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnf.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOne.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnd.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnc.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnb.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOna.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig1.set_value(1) # 1桁目選択 while True : for ch in message: sigs = [value for key, value in PIN_Signals if key == ch] for sw in sigs: line_LedOna.set_value(sw[0]) line_LedOnb.set_value(sw[1]) line_LedOnc.set_value(sw[2]) line_LedOnd.set_value(sw[3]) line_LedOne.set_value(sw[4]) line_LedOnf.set_value(sw[5]) line_LedOng.set_value(sw[6]) line_LedOnp.set_value(sw[7]) time.sleep(1)
ダイナミック点灯で4桁表示を行うデモ。
ChatGPTさん提示のコードに少し手を入れた。4文字を約1秒間表示後、次の4文字を表示している。動画では少々見辛いが、肉眼でははっきり表示されて見えている。
与えたテキストを4文字毎に表示するデモ。数字以外もいくつか追加してみた。
#!/usr/bin/python import gpiod import time ##表示メッセージ message="HELO20260123456789ABCDEFGHIJLNOPRUVY" PIN_Signals = [ (" " ,(0,0,0,0,0,0,0,0)), ("0" ,(1,1,1,1,1,1,0,0)), ("1" ,(0,1,1,0,0,0,0,0)), ("2" ,(1,1,0,1,1,0,1,0)), ("3" ,(1,1,1,1,0,0,1,0)), ("4" ,(0,1,1,0,0,1,1,0)), ("5" ,(1,0,1,1,0,1,1,0)), ("6" ,(1,0,1,1,1,1,1,0)), ("7" ,(1,1,1,0,0,0,0,0)), ("8" ,(1,1,1,1,1,1,1,0)), ("9" ,(1,1,1,1,0,1,1,0)), ("A" ,(1,1,1,0,1,1,1,0)), ("B" ,(0,0,1,1,1,1,1,0)), ("C" ,(1,0,0,1,1,1,0,0)), ("D" ,(0,1,1,1,1,0,1,0)), ("E" ,(1,0,0,1,1,1,1,0)), ("F" ,(1,0,0,0,1,1,1,0)), ("G" ,(1,0,1,1,1,1,0,0)), ("H" ,(0,1,1,0,1,1,1,0)), ("I" ,(0,0,1,0,0,0,0,0)), ("J" ,(0,1,1,1,1,0,0,0)), ("L" ,(0,0,0,1,1,1,0,0)), ("N" ,(0,0,1,0,1,0,1,0)), ("O" ,(0,0,1,1,1,0,1,0)), ("P" ,(1,1,0,0,1,1,1,0)), ("R" ,(0,0,0,0,1,0,1,0)), ("U" ,(0,1,1,1,1,1,0,0)), ("V" ,(0,0,1,1,1,0,0,0)), ("Y" ,(0,1,1,1,0,1,1,0)) ] SIGNALS = dict(PIN_Signals) select_chip0 = gpiod.Chip("gpiochip0") select_chip2 = gpiod.Chip("gpiochip2") line_Dig4 = select_chip2.get_line( 6) # P8_45 line_Dig3 = select_chip2.get_line( 8) # P8_43 line_Dig2 = select_chip2.get_line(12) # P8_39 line_Dig1 = select_chip2.get_line(10) # P8_41 line_LedOna = select_chip2.get_line(11) # P8_42 line_LedOnb = select_chip2.get_line(17) # P8_34 line_LedOnc = select_chip2.get_line(16) # P8_36 line_LedOnd = select_chip2.get_line(15) # P8_38 line_LedOne = select_chip2.get_line(13) # P8_40 line_LedOnf = select_chip0.get_line(11) # P8_32 line_LedOng = select_chip2.get_line( 9) # P8_44 line_LedOnp = select_chip2.get_line( 7) # P8_46 line_Dig4.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig3.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig2.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig1.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnp.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOng.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnf.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOne.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnd.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnc.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnb.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOna.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) DIG_LINES = ( line_Dig1, line_Dig2, line_Dig3, line_Dig4 ) # a,b,c,d,e,f,g,p の順 LED_LINES = ( line_LedOna, line_LedOnb, line_LedOnc, line_LedOnd, line_LedOne, line_LedOnf, line_LedOng, line_LedOnp ) def DigAllOff(): """全桁を消灯する""" for line in DIG_LINES: line.set_value(0) def DispLED(digit, ch): """ 指定した桁に文字を表示する。 digit : 1~4 ch : PIN_Signalsに登録された文字 """ if digit < 1 or digit > 4: raise ValueError("digitは1~4を指定してください") ch = str(ch).upper() if ch not in SIGNALS: raise ValueError("表示できない文字です: " + ch) sw = SIGNALS[ch] # 文字変更中に別のパターンが見えないよう全桁OFF DigAllOff() # セグメント設定 for line, value in zip(LED_LINES, sw): line.set_value(value) # 指定桁をON DIG_LINES[digit - 1].set_value(1) #### 表示 #### waittime = 0.002 holdtime = 1.0 count = int(holdtime / (waittime * 4)) try: while True : for strpos in range(0, len(message), 4): splitmessage = message[strpos:strpos+4].ljust(4) counter = count while counter > 0 : for dig, ch in enumerate(splitmessage, start=1): DispLED(dig,ch) time.sleep(waittime) counter -= 1 finally: DigAllOff()
アニメーションぽいのも試す。
表示パターンを数字以外のものに置換えてアニメーションぽく。もう少し早く動かすとWindowsの待ち時間中アイコンみたいにぐるぐる回るかも。
#!/usr/bin/python import gpiod import time ##表示メッセージ message= "U U U U R S D P DX D XD XL XK X" PIN_Signals = [ (" " ,(0,0,0,0,0,0,0,0)), ("U" ,(1,0,0,0,0,0,0,0)), ("R" ,(0,1,0,0,0,0,0,0)), ("S" ,(0,0,1,0,0,0,0,0)), ("D" ,(0,0,0,1,0,0,0,0)), ("P" ,(0,0,0,1,0,0,0,1)), ("X" ,(0,0,0,0,0,0,0,1)), ("L" ,(0,0,0,0,1,0,0,0)), ("K" ,(0,0,0,0,0,1,0,0)) ] SIGNALS = dict(PIN_Signals) select_chip0 = gpiod.Chip("gpiochip0") select_chip2 = gpiod.Chip("gpiochip2") line_Dig4 = select_chip2.get_line( 6) # P8_45 line_Dig3 = select_chip2.get_line( 8) # P8_43 line_Dig2 = select_chip2.get_line(12) # P8_39 line_Dig1 = select_chip2.get_line(10) # P8_41 line_LedOna = select_chip2.get_line(11) # P8_42 line_LedOnb = select_chip2.get_line(17) # P8_34 line_LedOnc = select_chip2.get_line(16) # P8_36 line_LedOnd = select_chip2.get_line(15) # P8_38 line_LedOne = select_chip2.get_line(13) # P8_40 line_LedOnf = select_chip0.get_line(11) # P8_32 line_LedOng = select_chip2.get_line( 9) # P8_44 line_LedOnp = select_chip2.get_line( 7) # P8_46 line_Dig4.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig3.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig2.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_Dig1.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnp.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOng.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnf.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOne.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnd.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnc.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOnb.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) line_LedOna.request( consumer="7SEGDEMO", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0] ) DIG_LINES = ( line_Dig1, line_Dig2, line_Dig3, line_Dig4 ) # a,b,c,d,e,f,g,p の順 LED_LINES = ( line_LedOna, line_LedOnb, line_LedOnc, line_LedOnd, line_LedOne, line_LedOnf, line_LedOng, line_LedOnp ) def DigAllOff(): """全桁を消灯する""" for line in DIG_LINES: line.set_value(0) def DispLED(digit, ch): """ 指定した桁に文字を表示する。 digit : 1~4 ch : PIN_Signalsに登録された文字 """ if digit < 1 or digit > 4: raise ValueError("digitは1~4を指定してください") ch = str(ch).upper() if ch not in SIGNALS: raise ValueError("表示できない文字です: " + ch) sw = SIGNALS[ch] # 文字変更中に別のパターンが見えないよう全桁OFF DigAllOff() # セグメント設定 for line, value in zip(LED_LINES, sw): line.set_value(value) # 指定桁をON DIG_LINES[digit - 1].set_value(1) #### 表示 #### waittime = 0.002 holdtime = 0.3 count = int(holdtime / (waittime * 4)) try: while True : for strpos in range(0, len(message), 4): splitmessage = message[strpos:strpos+4].ljust(4) counter = count while counter > 0 : for dig, ch in enumerate(splitmessage, start=1): DispLED(dig,ch) time.sleep(waittime) counter -= 1 finally: DigAllOff()