Raspberry Pi – ブザー

概要

Raspberry Pi用キットのアクティブ・ブザー、パッシブ・ブザーの実験。

アクティブ・ブザー

単純接続

アクティブ・ブザーは振動源を内蔵していて、電流が流すだけで音が出る。まず、単純に3.3Vの電源に繋いでみた。

抵抗なしで直接GNDに繋ぐと、「ピュー」という音が鳴る。抵抗値が10Ωで音はかなり小さくなり、100Ωにするとかすかに聞こえるくらいの音になった。

回路図

ブザーを電源に直接GPIOに繋いでもRasberry Piで制御できるが、キットの回路図はPNP型のトランジスターを介して接続していた。GPIOから流れる電流をより少なくするためと思われる。

この回路の場合、GPIOをHIGHにすると音はならず、LOWにするとC-E間にも電流が流れて音が出る。音量は直接3.3Vに繋いだ時と同じ。

コード

以下のコードでは単純にGPIOのHIGH/LOWを切り替えて、一定間隔でブザーを鳴らす。周期を短くすると「ピュピュピュピュ・・・」と連続して鳴動する。

パッシブ・ブザー

ソフトウェアによる音

パッシブブザーは入力の1パルスに対して1回だけクリック音が出る。アクティブ・ブザーと同じ回路図でブザーをパッシブブザーに取り換えて同じコードで実行すると”click, click, …”と単調な音が続く。

ここで入力をある周波数にすると、その周波数に対応した音程のビープ音になる。

以下のコードは440Hzの音を鳴らすもので、設定した周波数の周期で矩形パルスを発生させてAの音を出す。ソフトウェア制御なので、ときどき音が途切れたりする。

PWMによる音

上と同様のことを、ハードウェアのPWMで実装したのが下記のコード。

ハードウェアPWMのGPIO13にピンを変えて、周波数やデューティー・サイクルを指定してAの音を2秒間出している。

音階

PWMを使ってスケールを鳴らしてみた。

辞書定数で各音階に対応する周波数をセットして、ある周波数の1音を鳴らすクラスを定義。Cのスケールで音階を鳴らしている。

音楽

改めて音符・給付を並べて音楽を演奏するクラスを定義。ついでにテンポも指定できるようにした。

このクラスを使って、D-durの音階を鳴らしている。

 

Raspberry Pi – I2C~LCD1602

概要

ここではI2C接続によるLCD1602の制御について整理する。

Raspberry Pi用のキットにはI2CがセットされたLCD1602が同梱されていたが、Pythonのモジュールが見つからなかった。ゼロから組み立てようかとCのコードを読んでみたが、いま一つわからない。そこでネット上をいろいろと探して、自分なりに理解してみた。

LCD1602

LCD1602のピン配置

LCD1602のピン配置は以下の様になっているらしい。上から順番に1~16。

各ピンの意味は以下の通り。

GND Ground
+5V Vcc(電源)
CNT L→H→LでDB0~DB7ピンと信号伝送
RS Register Select -> H: Data, L: Command
R/W H: Read, L: Write
E L→H→LでDB0~DB7ピンと信号伝送
DB0~DB7 8ビットデータ
A LEDのアノード
K LEDのカソード

表示領域~DDRAM

2行表示の場合のDDRAMアドレスの割り当ては以下の様になっている。

LCD1602のコマンド

LCD1602のコマンドは以下の通り。H→1、L→0で表している。

  • RS=0のときはコマンド、RS=1のときはデータを表す
  • R/W=1で読み出し、R/W=0で書き込みで、コマンドは常にR/W=0
  • コマンドの場合は8ビットのDB7~0で最初に1が現れたビットによってコマンドが変わる
  • 書き込み/読み出しは、EをL→H→Lと変化させて実行

8ビット/4ビットモードの設定

LCD1602起動時、確実に8ビット/4ビットモードをセットする手順は以下の通り。

起動直後の初期設定では、適切な待機時間を挟んで4ビットで0x3を3回書き込んだ後に0x2を書き込むことで4ビットモードに設定される。

I2CによるLCD1602の制御

接続

キットのLCD1602にはあらかじめI2C接続のためのボードが接続されていた。チップはHLF8574Tと書かれていたが、これは中国製らしくフィリップス製のPCF8574と同じ機能らしい。PCF8574はI2C I/Oエクスパンダ―というチップで、I2Cに準拠しSDAを介したシリアルの通信と、P0~P7の8ビットパラレルの通信を変換する。

PCF8574のP0~P7が8ビットのレジスターの各ビットに相当し、それらはLCD1602の各ピンと以下のように接続されている(他のピンは省略している)。

参考サイト:

PCF8574 LCD1602 LCD1602の機能
P7 DB7 4ビットデータのbit3
P6 DB6 4ビットデータのbit2
P5 DB5 4ビットデータのbit1
P4 DB4 4ビットデータのbit0
P3 K バックライトのカソード
P2 E L→H→LでDB0~DB7ピンと信号伝送
P1 R/W H: Read, L: Write
P0 RS Register Select -> H: Data, L: Command

DB0~DB3は接続されていないことから、このモジュールは常に4ビットモードで使用する必要がある。

P2に接続されたKピンはバックライトのカソードにあたり、トランジスターのC~Bを介してGNDに接続されている。

LCDとRaspiの接続

Rasberey PiのGPIO2と3(3番ピンと5番ピン)がSDAとSCLに対応しており、電源・GNDとともにこれらをLCDの端子(正確にはLCDに接続されたエキスパンダーの端子)に接続する。

SDAとSCLに対するプルアップ抵抗がないが、LCD/I2C内部でプルアップされているらしい。

初期手順

Raspberry Piの手順に従ってI2Cを有効化した後、デバイスアドレスを確認(I2Cを参照)。ここでは、LCD1602のデバイスアドレスは0x27。

コード

動作テスト

LCDモジュールを4ビットモードにセット後、画面をクリアしてカーソルをブリンクさせる。

冒頭で定数を定義している。TWはEを1にしてからLに戻すまでの待機時間で、データシートでは最小230nsという値もあったが、Pythonのtime.sleepの分解能もあり、1ms(以上)としている。

次に、4ビットのデータを書き込む関数を定義している。

  1. 引数のデータの下位4ビットを取り出し、4ビットシフトして上位4ビットへ
  2. 下位4ビットにコマンドセット
    • バックライトON、転送Enable、Writeモード、コマンドレジスターに書き込み指示
  3. 書き込みウェイト
  4. EnableをLowにして書き込み

もう1つの関数は、1バイトのコマンドをLCDに書き込む。4ビットモードなので上位・下位の4ビットに分けて書き込んでいる。

コマンド送信の場合の手順は、上位4ビットの場合は0xF0でマスク、下位4ビットの場合は0xFでマスクして4ビット分シフトした後、以下の通り。

  1. 下位4ビットはコマンド書き込みイネーブルで、KE(RW)(RS)=0b1100=0xC
  2. TWの間ウェイト
  3. その後Eのみ0とするため0b11111011=0xFBでマスクして書き込み

実行部分の先頭で、8ビットモードを確定してから4ビットモードを設定。

いろいろなサンプルコードで0x33→0x32とバイト単位で書き込む例が多いが、4ビットごとの待機時間を意識するならこの方がデータシートの説明とも合っている。

最後にコマンド送信。

まず001で始まるFunction setで0b00101000=0x28とする。

  • DL=0で4ビットモード
  • N=1で2行表示
  • F=0で5×8フォントを使用

次に00001で始まるDisplay ONで0b00001111=0x0Fとする。

  • D=1でディスプレイ表示
  • C=1でカーソル表示
  • B=1でブリンクさせる

最後に0b00000001=0x01でディスプレイをクリア。

文字表示

先のコードに変更・追加を加えて、LCDに文字を表示してみる。

まず、write_command関数をwrite_byte関数に変更し、引数is_commandTrue/Falseに応じてRSの0/1を切替え、コマンド・データの両方を取り扱えるようにした。

データ送信の場合イネーブル時にRS=0となるため、下位4ビットはKE(RW)(RS)=0b1101=0xDとなる

また、新たに文字を表示する関数write_charを定義した。アドレスが与えられた場合はDDRAMのそのアドレスに、アドレスを指定しない場合は現在のアドレスに文字を書き込む。1文字書き込むとアドレスはインクリメントされるため、続けて文字を書き込む場合にはアドレス指定はしなくてよい。

実行の前半では、カーソルOFF、ブリンクOFFとしている。

文字表示の部分は以下の通りで、1行目に”ABC”、2行目に半角カナで”アイウ”と表示している。

LCD1602クラス

LCD1602を扱うクラスを作成。これまで作った関数をクラスのメソッドにしただけ。インスタンス生成時にLCDのアドレスを与える。

 

Raspberry Pi – シフトレジスター~ドットマトリックスLED

概要

Raspberry Piで8×8のドットマトリックスLEDを表示させてみた。

  • 2つのシフトレジスターを使って、任意のパターンを表示させるようにした
  • パターンを周期的に流れるように表示させた

ドットマトリックスLEDの仕様

キットに同梱されていたドットマトリックスLEDはピン配置や極性の手掛かりになる表示などがなかったので、1つずつ通電しながらピン配置と点灯の確認を行った。

内部の接続は以下のようになっている。RmをHIGHに、CnをLOWにすると、m行目n列目のLEDが点灯する。

回路図

キットのマニュアルの回路は2つのシフトレジスター74HC595を使っていたが、それらをカスケードに接続しているため、行と列のパターンを同時にしか設定できない。

そこで、2つのシフトレジスターを切り離して独立して制御するようにした。1行ずつスキャンしながら行ごとの点灯パターンを設定し、8×8の64個のLEDを任意のパターンで点灯させることができる。

ブレッドボードで回路を組んだら、かなり配線がごちゃごちゃになった。LEDのRとCから8本ずつのケーブルが出て、保護抵抗も8本使っているので仕方がないか。LEDのサイズがそれなりに大きいので、ブレッドボードの穴が覆われてしまう。

表示は平仮名の「お」で、後述のサイネージコードで「おはよう」と流して表示しているときの一部。

コード例

試験点灯

まず、8×8のドットパターンを2秒間だけ表示させてみる。

ドットパターンはサブディレクトリーlibの下にled_dotmatrix_data.pyとして以下のモジュールを準備した。

パターンをスペースとスペース以外の文字(ここでは*)を使って準備し、get_bit_pattern関数で8ビット×8行のリストとする。

最初のコードで、まずGPIOピンなどの定数を定義している。ROWSはドットマトリックスの各行を単独で指定する際に、シフトレジスターに与えるビットパターン。

shift関数は、SERとSRCLK、HIGH/LOWのレベルを指定してシフトレジスターを1回シフトする。

read関数は、RCLKをHIGHにしてストレージレジスタ―の出力を取り出し、LOWに戻す。

clear関数はドットマトリックスのR1~R8をLOWにしてLEDを消灯させる。念のためC1~C8もLOWにしている。

display関数は、8ビット×8行のビットパターンを与えてsleepの秒数だけLEDを点灯させる。

DisplayThreadはビットパターンを与えて生成し、startメソッドを呼ぶと内部でrunメソッドが実行される。stopメソッドによりスレッドが停止する。

試験点灯用のコードは以下の通りで、表示パターンを与えてスレッドを生成し、2秒間点灯させた後にスレッドを停止させている。

ここで、stopメソッドの後に僅かな時間の間をおかないと、「setmodeが必要」というランタイムエラーが出る。destroyメソッドでcleanupを実行するタイミングがstopで表示が停止するよりも早いからかもしれない。

CTRL-Cでの表示停止

次に、実行後表示を続けてCTRL-Cのキーボード入力で停止するようにした。

このとき、キーボード割込を待ち受けるwhileループの内容を単にpassとすると目に見えるくらいのちらつきが生じたため、sleepを入れている。

アニメーション表示

2つのパターンを準備して、一定時間で交互に表示を切り替えてみた。

まず、led_dotmatrix_dataモジュールで準備した表示パターンは以下の通り。

2つのパターンを交互に切り替える実行部分は以下の通り。

流れる表示

8×8のパターンを横に流れるように表示してみた。led_dotmatrix_dataモジュールに以下を追加。

get_cycle_pattern関数は、8×8のパターンの表示開始位置を与えてサイクリックに表示をずらすためのパターンを返す関数。

以下は、この関数を使って流れる表示をさせるコード。データのリストの最後まで来たら、表示させる桁数を先頭に戻している。この結果、正弦波のような波が流れて表示される。

サイネージ

複数の文字が横に流れるように表示させるようにしてみた。まず、led_dotmatrix_dataモジュールに以下の関数とパターンを追加。

combine_patterns関数は複数のパターンを引数にとり、それらを横に連ねた2次元リストを返す。

実行部分は以下の通りで、複数の文字パターンを関数で1つの2次元リストにまとめ、それを上の流れる表示と同じように処理している。

 

Raspberry Pi – シフトレジスタ―~4桁7セグメントLED

概要

  • Raspberry Piでシフトレジスターを介して4桁7セグメントLEDをコントロール
  • 各桁を短時間で明滅させて、視覚的に全桁が同時発光しているように見せる
  • おまけでカウントダウンタイマーにしてみた

4桁7セグメントLEDのピン配置と回路

キットに同梱されていたLEDのピン配置は下図の通り。

D1~D4のピンは左から順に各桁の7セグメントLEDに対応している。これらのピンがHIGHのLEDにa~dpのピンへの入力が反映されて表示される。LOWの時にはLEDは消灯する。

a~dpは7セグメントLEDのピン配置に対応している。

内部の回路は以下の通りで、カソードコモンとなっている。たとえば左から2桁目のLEDを点灯させたいときは、D2をHIGHにしてa~dpのうち点灯させたいセグメントのピンをLOWに、消灯させたいセグメントのピンをHIGHにする。

4桁の同時発光

セグメントの明滅を制御するa~dpのピンが1組しかないので、ある桁を特定のパターンで点灯させたいときは、他の桁は消灯させる(でなければ、DnがHIGHになっている桁の全てが同じパターンで点灯する)。

そこで、ある桁を短い時間点灯させたあと消灯するという動作を各桁入れ替えながら実行していく。点灯・入れ替えの時間が十分短いと、残像減少によって人の目には全桁が同時発光しているように見える。

Raspberry Piによる制御回路

全体の考え方は以下の通り。

  • D1~D4の桁選択ピンは4つのGPIOピンでコントロールする
  • a~dpのセグメント選択ピンはシフトレジスター74HC595を介してコントロールする
  • 7セグメントLEDの保護抵抗はD1~D4に1つずつ繋ぎ、1つの7セグメントあたり1つとする

試験点灯

ソフトウェアによる制御の考え方は以下の通り。

  1. 初期設定ではD1~D4をLOWにする
  2. DnをD1~D4と順番に入れ替えて以下を繰り返す
    1. DnをHIGHにして選択する
    2. 選択したLEDに対してシフトレジスターを介して表示パターンを送る
      • 表示パターンはa→dpの順の8ビットで定義して、LSBから順にシフトレジスターに送り込む
    3. 一定時間sleepさせる
    4. HIGHにしたDnをLOWにする
  3. CTRL-Cが押されたらD1~D4をLOWにして終了処理を行う。

以下のPythonコードでは、いくつかの関数を定義している。

initialize
LEDとシフトレジスターの初期化を行う。
destroy
終了処理を行う。
display_a_digit
指定した桁のLEDを指定したパターンで一定時間点灯させる。桁の指定は左から0~3、パターンは0~9の数字に対応したビットパターン、点灯時間はミリ秒で与える。
display_digits
表示させる4桁の数値を文字列で与えて、一定時間点灯させる。ミリ秒で与えた点灯時間はdisplay_a_digit関数にそのまま渡される。

カウントダウンタイマー

time.perf_counter

4桁7セグメントLEDでカウントダウンタイマーを作ってみた。

  • 左2桁が分、右2桁が秒に対応する
  • 動作中は秒数でコントロールし、LED表示のために分と秒を分解する
  • 点灯時間をtime.perf_count関数で計り、約1秒ごとにカウントダウンする
  • カウントダウンを終えたら’0000’を表示して割り込みを待つ

なお、整数値の分・秒を2桁表示の文字列にする関数get_two_digits関数を定義している。

69-72行で分と秒をセットし、それを総秒数に計算。

77-93行がカウントダウン部分。

  • tartとendをtime.perf_counterで取得して経過秒数を計算
  • 表示秒数が1秒たつとカウントダウン
  • カウントダウン後と残りゼロ秒になったときに内側のループを抜ける

95-98行目では、残りゼロ秒になったときにオールゼロを表示して待機。

スレッド

実行部分をシンプルにするためにスレッドを使ってみた。

66-83行目で、4桁の内容を表示し続けるスレッドクラスを準備。

95-108行目で、1秒ごとにスレッドを発生させて現在の残り時間を表示。

回路の写真

74HC595の向きを逆にしてしまったのでコードがごちゃごちゃ。

Raspberry Pi – シフトレジスタ―~7セグメントLED

 

シフトレジスターには74HC595を使う。

ここでは、別々のGPIOから7セグメントLEDを点灯させたときと逆に、a→dpのビット順にしていて、コードではLSBから順に読みだしてシフトレジスターに送ることにした。

表示 a b c d e f g dp Hex
0 11111100 0xfc
1 01100000 0x60
2 11011010 0xda
3 11110010 0xf2
4 01100110 0x66
5 10110110 0xb6
6 10111110 0xbe
7 11100000 0xe0
8 11111110 0xfe
9 11110110 0xf6
A 11101110 0xee
B 00111110 0x3e
C 10011100 0x9c
D 01111010 0x7a
E 10011110 0x9e
F 10001110 0x8e

以下はRaspberry Piで7セグメントLEDを点灯させるコード。リストのpatternsに0~Fまでのセグメント点灯パターンを入れ、対応する桁数分シフトしてシフトレジスターに送っている。そして、各パターンを0.5秒ずつ表示させてカウントアップさせている。

キットのテキストのコードでは、time.sleep()を入れていたり入れていなかったりするが、特にこれがなくても問題なく動作する。

 

Raspberry Pi – シフトレジスター~LEDバーグラフ

LEDバーグラフ

LEDバーグラフの例はこちらで示したが、点滅させるLEDの数だけGPIOポートを使った。シフトレジスターを使えば、データに関してはシリアル信号1本だけで済む。以下はシフトレジスター74HC595を使った回路例。

各LEDの点滅の制御は以下の流れ。

  1. LEDの個数分以下を処理
    1. SERに点灯ならHIGH、消灯ならLOWを入力
    2. SRCLKにHIGHを入力してシフト後、LOWに
  2. RCLKをHIGHにして、QA~QHの出力をLEDに流す
  3. 全消灯するときはSRCLKをLOWにしてからHIGHに戻す

以下はこの回路をRuspberry PiのMicro Pythonで制御するコード例。

SRCLK/RCLKでHIGH/LOWに変化させた後、それぞれLOW/HIGH戻すまでに0.001秒待たせているが、これがなくても動作はする。

 

LEDの保護抵抗

対象とする回路

以下のような回路を考える。

ここで各記号の意味は以下の通り。

  • E:電源電圧
  • Vf:LEDにかかる順電圧
  • If:LEDを流れる順電圧
  • Vr:保護抵抗による電圧降下
  • R:保護抵抗値
  • I:回路を流れる電流(I = If

Vf(順電圧)やIf(順電流)は、それらを用いる人や場合によってLEDが発光し始める閾値や典型値など定義が異なっているが、ここではその時点の回路での値とする。

保護抵抗による電圧降下

保護抵抗による電圧降下、抵抗値、回路電流の間では、以下のようにオームの法則が成立する。VrIの線形関数となっている。

(1)    \begin{equation*} V_r = R I \end{equation*}

LEDの特性

一方LEDの順電圧Vfも電流の関数だが、それは一般的な固定抵抗のものと異なり、電圧によって非線形的に電流が変化する。以下は赤色LEDの特性曲線を概ねのイメージで描いた例。

LEDの電流~電圧特性の特徴は以下の通り。

  • LEDにかかる順電圧がある閾値を越えるまでは電流は流れず発光しない
  • 順電圧が閾値を越えると、電圧値に対して急に電流が増加する
  • 順電圧の僅かな変動に対して、順電流の変動が大きい

LEDの内部抵抗で考えると以下のように表現できる。

  • 閾値以下ではLEDの内部抵抗は∞と考えてもよいくらい大きい
  • 閾値を越えると、順電圧の増加に対して内部抵抗が急激に減少していく

回路に関する計算

基礎式

LEDの順電流・順電圧に関する特性曲線をI = If(Vf)という関数で表し、電源とLEDの内部抵抗をゼロとして考えると、回路全体の電圧のバランスは以下のようになる。

(2)    \begin{equation*} E = V_f + RI = V_f + R I_f(V_f) \end{equation*}

これをIfについて解くと以下のようになる。

(3)    \begin{equation*} R = \dfrac{E - V_f}{I_f(V_f)} \end{equation*}

IfVfの関数になっているのでややこしいが、一般にはデータシートの典型値などをそのまま用いて計算する例が多い。たとえば電源電圧が3.3Vで赤色LEDを発光させる場合、典型値としてIfTYP=20mAの時にVfTYP=2Vという値が示されているとすると保護抵抗値は以下のようになる。

(4)    \begin{equation*} R = \dfrac{3.3 - 2}{0.02} = 65 \Omega \end{equation*}

よく見かける保護抵抗値は100Ωとか330Ωといった値だが、こういう場合のVfIfがどのようになるか、また順電流を10mAや30mAにしたい場合抵抗値をどうするかといったことを知りたい場合は非線形な方程式を解かなければならない。

特性曲線にの読み取りによる計算

LEDの特性が先に示したような特性曲線のように与えられている場合、電源電圧3.3Vに対して順電流をIf = 10mAとしたい場合は、グラフからVf =2.4V程度となるので、保護抵抗値は以下のように求められる。

(5)    \begin{equation*} R = \dfrac{3.3 - 2.4}{0.01} = 90 \Omega \end{equation*}

順電流の絶対最大定格値が30mAの場合、これを越えないようにするための最低の保護抵抗値はどうなるか。先の特性曲線からIf = 30mAに対してVf = 2.6V程度と読み取れるので、以下のように計算される。

(6)    \begin{equation*} R = \dfrac{3.3 - 2.6}{0.03} \fallingdotseq 23.33 \Omega \end{equation*}

市販のLEDのデータ

市販のLEDのデータシートの値の例は以下のようになっていた。なおA社のデータシートによると、より長期間使用するために順電流値を10~30mAの間で使用することが推奨されている。

これらのLEDを典型値で用いる場合の保護抵抗値を計算してみる。A社の赤、青・緑のLEDを5Vで使う場合、

(7)    \begin{equation*} \left\{ \begin{align} \dfrac{5 - 2.1}{0.02} &= 145 \Omega \\ \dfrac{5 - 3.4}{0.02} &= 80 \Omega \end{align} \end{equation*}

またB社の赤、緑のLEDを3.3Vで使う場合、

(8)    \begin{equation*} \left\{ \begin{align} \dfrac{3.3 - 1.9}{0.01} &= 140 \Omega \\ \dfrac{3.3 - 2}{0.01} &=  130 \Omega \end{align} \end{equation*}

なお各LEDのIfVfの関係をデータシートの特性曲線から典型値で読み取ってみると以下のようになり、概ね表の値に一致する。

  • A社の赤LED→20mAに対して約2.13V
  • A社の緑・青LED→20mAに対して約3.4V
  • B社の赤LED→10mAに対して1.9V

不明LEDの特性曲線

Raspberry Pi用のキットにはパーツのデータシートや型番などがなく、LEDの特性も分からない。そこで、抵抗値を取り換えながらVfVrを計測し、Ifの計算値をプロットしてみた。
データシートで見られるカーブの形をしており、赤・緑・黄色の特性が近く、青と白はより大きなVfを必要としている。

特性曲線は指数関数で近似できるので、片対数軸で表示してみる。若干指数関数よりもVfに対するIfの増加率が緩やかな傾向がある。

Excelの分析ツールでも指数関数近似をしてくれるが、ここで以下の式形で回帰をしてみた。まず以下の式で回帰する。

(9)    \begin{equation*} I_f = a e^{b V_f} \end{equation*}

一般にはa(exp(b Vf) – 1)の形で示されているが、回帰計算のしやすさのために形を少し変えている。両辺の対数をとって線形回帰する。

(10)    \begin{equation*} \ln I_f  =  \ln a + b V_f \end{equation*}

結果は分析ツールのグラフと同じ形で以下のようになる。

片対数で表すと以下のようになる。

対数軸で線形性が良好な緑と黄は元の関数形でもよく一致しているが、赤と青・白についてはVfが大きいところでの乖離が大きくなる。ただしVfに対してIfが小さく推定されるため、たまたまとはいえ安全側になっている。

各色のLEDに対する推定式の定数は以下のようになった。

対数化した線形式での相関係数は0.978~0.999程度であり、かなり高い。土質・地質工学や水理学のように自然現象を扱う場合とは異なる。

なお、Ifを希望する値にするための抵抗値は以下のように計算できる。

(11)    \begin{equation*} I_f = a \exp{b V_f} = a \exp{b (E - R I_f)} \end{equation*}

この式をRについて解いて、

(12)    \begin{equation*} R = \dfrac{E - \dfrac{1}{b} \ln \dfrac{I_f}{a}}{I_f} \end{equation*}

Ifを変化させた場合、各色のLEDに使う保護抵抗値は以下のように計算される。

キットのテキストでは220Ωの抵抗をよく用いているが、その場合は赤・緑・黄色が7~8mA程度、青と白では4mA程度ということになる。実際、青と白のLEDは少し暗めかなというくらいの明るさなので、これらの計算結果は腹落ちできる。

 

7セグメントLED

配置図

7セグメントLEDのピン配置は以下の通り(コモンカソードの場合)。

セグメントコード

各セグメントを0で消灯、1で点灯するとして、a~g及びDPを逆順にして0~Fを表示させるビット配列は以下のようになる。

表示 dp g f e d c b a Hex
0 00111111 0x3f
1 00000110 0x06
2 01011011 0x5b
3 01001111 0x4f
4 01100110 0x66
5 01101101 0x6d
6 01111101 0x7d
7 00000111 0x07
8 01111111 0x7f
9 01101111 0x6f
A 01110111 0x77
B 01111100 0x7c
C 00111001 0x39
D 01011110 0x5e
E 01111001 0x79
F 01110001 0x71

GPIOに直接接続

7セグメントLEDの動作を確認するため、以下の様にRaspberry Pi 4BのGPIOに接続した。

点灯テストは以下のコードで行った。

  • LEDの各ピンにGPIOのピンを割り当て
  • 0~9, A~Fの表示に対応するビットパターンを定義
    • ビット配列はdp, g, f, e, d, c, b, aの逆順
  • 16個のパターンを0.5秒ずつ表示
  • パターン表示はビット配列を必要分だけシフトして、ピンに対応するビットが1の場合にセグメントを点灯、0の場合に消灯
  • 終了時に全セグメントを消灯

このような接続の場合、LEDの8つのピンに対応してGPIOのピンも8つ消費される。

より少ないピンの数で7セグメントLEDを接続するためには、シフトレジスターを用いるのが一般的。

 

Raspberry Pi – LEDバーグラフ

概要

LEDバーグラフの実験例。DavinciキットのLEDはピン配置がわからなかったので、まず3.3VとGNDで確認した。

回路図

以下の通り、アレイになっている10個のLEDを3.3Vに抵抗を介して繋ぎ、各ポートに接続。ポートのレベルをHIGHにするとLED消灯、LOWにするとLED点灯になる。

コード

今回はピン番号を物理番号(GPIO.BOARD)で定義している。接続数は多いが独立したLEDを扱うのと同じで、以下の例では短い間隔でLEDを順次点灯・消灯させて、流れるように表示させている。

 

Raspberry Pi – RGB LED


概要

DavinciキットのRGB LEDを試してみる。オリジナルのコードを少し変えて、3色をまとめて扱うするクラスを作ってみた。また、徐々に明るさを変化させてみた。

回路

RGB LEDのピン配置は以下のようになっており、最も長いピンがGNDでRed-GND-Green-Blueの順に配置されている。

回路図は以下の通り。

コマンドラインで以下を実行して、接続を確認。

基本コード

辞書でR/G/Bのピン番号を設定し、周波数を100HzにしてLEDの発色を確認。

クラス化と色変化

3色のLEDをまとめて扱うクラスを定義。

  • コンストラクターでピン番号と周波数を指定してインスタンスを生成
  • startメソッドでPWMの作動開始
  • changeDutyCycleメソッドでデューティー比を変更設定
  • stopメソッドでPWM停止とGPIOのリソース解放

定数COLORSで定義した色を順次発色させている。カラーコードからデューティー比への変換は1つの関数で一括して行っている。

色と輝度の変化

R/G/Bを順に徐々に明滅させる例。カラーコードや変換関数は使わず、直接各色のデューティー比を0~100~0に変化させている。