ラズベリーパイは基板上に「GPIO」と呼ばれる、ラズベリーパイで作成したプログラムから信号の入力・信号の出力が行えるピンが存在します。
信号の入力とは「スイッチのON/OFF」「温度計で室温の計測」といった、ラズベリーパイの外の情報を入力(インプット)してプログラム上で使用することです。
対して、信号の出力とは「LEDを点灯させる」「モータを回す」といった、ラズベリーパイで制御した結果を外に出力(アウトプット)することです。
この記事では、ラズベリーパイのプログラム(Python)からADコンバータに接続された半固定ボリュームの値をSPI通信で読み取り、赤色バーLEDを制御する方法を解説します。
SPI(Serial Peripheral Interface)とは、ICなどの電子部品と通信するために使用される通信方法の一種です。ADコンバータに接続された半固定ボリュームの値をSPI通信を用いて読み取る方法は以下のページで解説しておりますので、宜しければご覧ください。
SPI通信を用いてLEDの明るさを調整する方法は以下のページで解説しておりますので、宜しければご覧ください。
目次
1. 完成イメージ(赤色バーLEDを制御する)
この記事で完成するものは以下のようになります。

半固定ボリュームの回した加減により、赤色バーLEDの点灯する数を調整します。
- ボリュームの状態をADコンバータで読み取る
- ADコンバータの値をSPI通信を用いてラズパイに取込む
- 読み取った値を元に赤色バーLEDを点灯する
2. 使用する部品
今回使用する部品は以下の通りです。

『Raspberry Pi 3 Model B+』を使用します。※2020年6月時点で最新はRaspberry Pi 4になります。

LEDや抵抗といった各種部品や(後述する)ジャンパ線などを穴に差し込み、部品間を電気的に接続する板(ボード)です。
電子工作をする上で必須の部品です。

ブレッドボートに差し込み、電子部品の間を電気的に接続します。
↑の写真では両側が「ピン」になっており、ブレッドボートの穴に差し込んで使用します。

今回は「バーLED」であるOXS10201-Rを使用します。赤色のLEDが10ヶ横一列に配列され、各LEDのアノード・カソードは独立しています。(コモンラインは無し)
外形図、内部配線は以下のようになります。


LEDなどの電子部品は適した電圧と電流値が決められており、既定の範囲を超えると壊れてしまう恐れがあります。
抵抗器は電流の流れを妨げ、電子部品に流れる電流を抑える役割を担います。
今回は220Ω(オーム)の抵抗器を使用します。

(小さくてすいません…)
今回はSPI通信に対応したADコンバータであるMCP3002を使用します。各ピンの機能は以下のようになります。

| 1 | :CS/SHDN | :チップセレクト |
| 2 | :CH0 | :チャンネル0 アナログ入力 |
| 3 | :CH1 | :チャンネル1 アナログ入力 |
| 4 | :Vss | :GND |
| 5 | :Din | :シリアルデータ入力 |
| 6 | :Dout | :シリアルデータ出力 |
| 7 | :CLK | :シリアルクロック |
| 8 | :Vdd/Vref | :電源(+2.7V~5.5V) |

半固定ボリューム(半固定抵抗器)は、ツマミを回すと抵抗値が変化する部品です。今回は0~10kΩ範囲の抵抗値を可変できる半固定ボリュームを使用します。
電子工作をするため、これまで解説した部品の他にもスイッチやセンサなど、色々な部品が必要になってきます。個々で購入するには手間がかかるため、最初はセット品を購入することをおススメします。

私は以下のセット品を購入しました!
また、これからラズベリーパイを購入する場合、ラズベリーパイ本体を含めたセット品を購入することをおススメします。
ラズベリーパイ本体を収めるケースや、OSをインストールするためmicroSDカードなど必要なものを個々に購入する手間を省くことができます。
3. 回路図・配線の様子
ラズベリーパイのプログラム(Python)からADコンバータに接続された半固定ボリュームの値をSPI通信で読み取り、赤色バーLEDを制御する回路を解説します。
回路図は以下のようになります。

赤色バーLEDの各アノード(プラス側)にGPIOを個別に配線します。各LEDを右からA~Jとすると、各LEDとGPIOの関係は以下のように配線します。
| LED区別 | GPIO | ジャンパ線色 |
|---|---|---|
| LED_A(一番左側) | GPIO 27番ポート | 白色 |
| LED_B | GPIO 22番ポート | 青色 |
| LED_C | GPIO 5番ポート | 黄色 |
| LED_D | GPIO 13番ポート | オレンジ色 |
| LED_E | GPIO 26番ポート | 白色 |
| LED_F | GPIO 18番ポート | 青色 |
| LED_G | GPIO 23番ポート | 黄色 |
| LED_H | GPIO 24番ポート | オレンジ色 |
| LED_I | GPIO 16番ポート | 白色 |
| LED_J(一番右側) | GPIO 21番ポート | 青色 |
各LEDのカソード(マイナス側)には抵抗器(220Ω)を介してGNDに接続します。(黒色のジャンパ線)
ラズベリーパイをADコンバータ(MCP3002)とSPI通信するため、以下のように接続します。
| ラズベリーパイのピン | MCP3002のピン | ジャンパ線 |
|---|---|---|
| SPICS0 | CS/SHDN(1番ピン) | 白色 |
| SPIMOSI | Din(5番ピン) | 黄色 |
| SPIMISO | Dout(6番ピン) | 青色 |
| SPISCLK | CLK(7番ピン) | 白色 |
MCP3002と半固定ボリュームを接続する必要があります。今回はMCP3002のCH0(2番ピン)に接続します。(青色のジャンパ線)
3.3VとGNDをMCP3002と半固定ボリュームに各々接続します。(オレンジ色と黒色のジャンパ線)
配線の様子です。こんな感じになりました。

配線量が多く、予想以上に汚くなってしまいました…
↑では、フラットケーブルでGPIOの全ピンをブレッドボードに接続しています。回路図と実際の配線は異なる部分がありますがご了承ください。
※電気的には「回路図」と同じ意味です。
4. プログラム(Python)
ADコンバータに接続された半固定ボリュームの値をSPI通信で読み取り、赤色バーLEDを制御するプログラム(Python)は以下のようになります。
#必要なモジュールをインポート
import RPi.GPIO as GPIO #GPIO用のモジュールをインポート
import spidev #SPI通信用のモジュールをインポート
import time #時間制御用のモジュールをインポート
import sys #sysモジュールをインポート
#ポート番号の定義
Bar_led = [
27, 22, 5, 13, 26, 18, 23, 24, 16, 21] #変数"Bar_led"にリストを代入
#GPIOの設定
GPIO.setmode(GPIO.BCM) #GPIOのモードを"GPIO.BCM"に設定
GPIO.setup(Bar_led, GPIO.OUT) #GPIO(10ヶ)を出力モードに設定
#SPI通信を行うための準備
spi = spidev.SpiDev() #インスタンスを生成
spi.open(0, 0) #CE0(24番ピン)を指定
spi.max_speed_hz = 1000000 #転送速度 1MHz
#数値からバーLEDを点灯させる関数
def barled_lighting(level):
for i in range(0, level): #点灯させるGPIO(左側)
GPIO.output(Bar_led[i], GPIO.HIGH) #GPIO点灯
for i in range(level, 9): #消灯させるGPIO(右側)
j = i + 1
GPIO.output(Bar_led[j], GPIO.LOW) #GPIO消灯
#連続して値を読み込む
while True:
try:
resp = spi.xfer2([0x68, 0x00]) #SPI通信で値を読み込む
volume = ((resp[0] << 8) + resp[1]) & 0x3FF #読み込んだ値を10ビットの数値に変換
bright = volume / 1023 * 10 #0~1023を0~10に変換
print(int(bright)) #変換した数値を表示
barled_lighting(int(bright)) #変換した数値を元にLEDを点灯
time.sleep(0.1) #0.1秒間待つ
except KeyboardInterrupt:
#Ctrl+Cキーが押された
GPIO.cleanup() #GPIOをクリーンアップ
spi.close() #SPI通信を終了
sys.exit() #プログラム終了SPI通信でADコンバータMCP3002の値を読み取り、赤色バーLEDに割り付けたGPIOを制御します。
#必要なモジュールをインポート
import RPi.GPIO as GPIO #GPIO用のモジュールをインポート
import spidev #SPI通信用のモジュールをインポート
import time #時間制御用のモジュールをインポート
import sys #sysモジュールをインポート2~5行目で今回必要な「モジュール」を宣言します。
#ポート番号の定義
Bar_led = [
27, 22, 5, 13, 26, 18, 23, 24, 16, 21] #変数"Bar_led"にリストを代入変数”Bar_led”に27,22,5,13,26,18,23,24,16,21を代入します。この数値はGPIOのポート番号として扱い、後からポート番号を変更する場合はこの数値を変更します。
#GPIOの設定
GPIO.setmode(GPIO.BCM) #GPIOのモードを"GPIO.BCM"に設定
GPIO.setup(Led_pin, GPIO.OUT) #GPIO18を出力モードに設定GPIOの設定を行います。
GPIO.setmode(GPIO.BCM)は、GPIOをポート番号で扱う方法に設定します。
GPIO.setup(Led_pin, GPIO.OUT)は、GPIO 18番ポートを出力モードに設定します。
#SPI通信を行うための準備
spi = spidev.SpiDev() #インスタンスを生成
spi.open(0, 0) #CE0(24番ピン)を指定
spi.max_speed_hz = 1000000 #転送速度 1MHzSPI通信をする準備をします。SpiDev()メソッドはspiという名称でSPI通信をできるようにします。
spi.open(0, 0)は、CE0(24番ピン)に接続したデバイスと通信を開始します。仮にCE1(26番ピン)に接続したデバイスと通信する場合はspi.open(0, 1)と記述します。※今回はCE0(24番ピン)に接続します。
#数値からバーLEDを点灯させる関数
def barled_lighting(level):
for i in range(0, level): #点灯させるGPIO(左側)
GPIO.output(Bar_led[i], GPIO.HIGH) #GPIO点灯
for i in range(level, 9): #消灯させるGPIO(右側)
j = i + 1
GPIO.output(Bar_led[j], GPIO.LOW) #GPIO消灯関数barled_lighting(level)は、引数levelの数値を元に赤色バーLEDの点灯する数を制御します。
例えば、変数levelの値が4の場合、for文を用いてリストBar_ledの添え字(インデックス)が0~4となります。
リストBar_ledの0~4の要素は27,22,5,13,26のため、GPIO.output(Bar_led[i], GPIO.HIGH)にてGPIO 27,22,5,13,26番ポートの電圧をHigh(3.3V)にします。これらのGPIOは赤色バーLEDの左側から接続されており、High(3.3V)になったLEDはここで点灯します。
GPIO.output(Bar_led[j], GPIO.LOW)は、赤色バーLEDの残り(右側)のGPIOの電圧をLow(0V)にします。
#連続して値を読み込む
while True:
try:
resp = spi.xfer2([0x68, 0x00]) #SPI通信で値を読み込む
volume = ((resp[0] << 8) + resp[1]) & 0x3FF #読み込んだ値を10ビットの数値に変換
bright = volume / 1023 * 10 #0~1023を0~10に変換
print(int(bright)) #変換した数値を表示
barled_lighting(int(bright)) #変換した数値を元にLEDを点灯
time.sleep(0.1) #0.1秒間待つ
except KeyboardInterrupt:
#Ctrl+Cキーが押された
GPIO.cleanup() #GPIOをクリーンアップ
spi.close() #SPI通信を終了
sys.exit() #プログラム終了「while文」は条件を指定して、その条件が真の時に繰り返し処理を行うものです。
while 条件式:
繰り返し処理を行うコード↑の「条件式」にTrueを指定することにより、条件式は常に真となりwhile文は無限に繰り返します。
ただし、このままではプログラム実行中に無限ループから抜け出す方法がありません。そこでwhile文の中にある「try文」と「except文」を使用します。
このtry-except文を用いることにより、while文の処理は以下のようになります。
while True:
try:
繰り返し処理を行うコード
except KeyboardInterrupt: #Ctrl+cキーが押された
GPIO.cleanup() #GPIOをクリーンアップ
spi.close() #SPI通信を終了
sys.exit() #プログラム終了except KeyboardInterrupt:は、キーボードのCtrl + cキーが押された時にwhile文の繰り返し処理から抜けて上記のプログラム終了の処理を行います。
Ctrl + cキーが押されていないとき、try:文の中の処理を繰り返し行います。(以下で解説)
while文の中の「繰り返し処理を行うコード」は以下の通りです。つまり、Ctrl + cキーが押されるまで以下の処理を繰り返します。
resp = spi.xfer2([0x68, 0x00]) #SPI通信で値を読み込む
volume = ((resp[0] << 8) + resp[1]) & 0x3FF #読み込んだ値を10ビットの数値に変換
bright = volume / 1023 * 10 #0~1023を0~10に変換
print(int(bright)) #変換した数値を表示
barled_lighting(int(bright)) #変換した数値を元にLEDを点灯
time.sleep(0.1) #0.1秒間待つspi.xfer2([0x68, 0x00])は、ADコンバータMCP3002のCH0(チャンネル0 アナログ入力)のアナログ値を取得します。
MCP3002から取得したデータはresp[0]とresp[1]の2バイトに分かれるため、シフト演算子を用いて変数”volume”にまとめます。
変数”volume”には0~1023の数値が格納されます。今回、赤色バーLEDの数は10ヶのため、bright = volume / 1023 * 10で0~10に変換します。
barled_lighting(int(bright))は、変数”bright”を整数型に変換して21~26行目の関数に渡します。
time.sleep(0.1)は何もせずに0.1秒間待ちます。
5. おわりに
ラズベリーパイのプログラム(Python)からADコンバータに接続された半固定ボリュームの値をSPI通信で読み取り、赤色バーLEDを制御する方法を解説しました。
まだまだラズベリーパイ初心者の私ですが、以下の参考書が大変参考にさせて頂いております。
2冊とも初学者にも易しい内容になっており、ゼロからラズベリーパイを始める方にもオススメできる参考書です。

