第3回 ラズパイを使用したBLE通信 ~ A/D変換・D/A変換を用いた入出力編 ~
公開日:2023.02.24 更新日:2023.02.24
こんにちは、GTです。
よろしくお願いします。
第3回の今回は、ラズパイの入出力についてご紹介します。
ラズパイには、現時点(Raspberry Pi 4)ではアナログ信号を入力する機能はありません。
そのため、アナログ信号をラズパイに入力することができるデジタル信号に変換(A/D変換)して入力を行います。
また、出力を行う際はデジタル信号をアナログ信号に変換(D/A変換)します。
A/D変換やD/A変換を行うために、下記のA/Dコンバータ(ADC)やD/Aコンバータ(DAC)を使用します。
機器名 | メーカー | 備考 |
---|---|---|
Raspberry Pi用高精度 AD/DAボード | seeed studio | A/D変換に使用 |
DC2197A-A | Analog Devices | D/A変換に使用 |
出力信号のD/A変換は、A/D変換と同様にRaspberry Pi用高精度 AD/DAボードでも行うことができます。
ただし、出力端子は2つしかありません。
今回は3つ以上の出力が必要であるため、より端子の数が多いDC2197A-Aを使用しました。
DC2197A-AによってD/A変換を行う際、ラズパイからの入力はPWM信号(一定周期(PWM周波数)当たりのON状態の時間が占める割合(デューティ比)によって平均電圧を制御する変調方式)によって行います。
最終的には以下のような通信経路となります。

ラズパイの設定については過去の記事を参考にしてください。
第1回 ラズパイを使用したBLE通信 ~ ディスプレイ、キーボード、マウスを接続しないで設定 前編 ~
第2回 ラズパイを使用したBLE通信 ~ ディスプレイ、キーボード、マウスを接続しないで設定 後編 ~
入力
BLE通信の送信側で使用するラズパイに対して操作を行います。
機器から送られたアナログ信号をRaspberry Pi用高精度 AD/DAボードにてA/D変換し、デジタル信号をラズパイに入力します。
A/D変換を行う際、第2回で行ったSPI通信の有効化の設定が必要となります。
Raspberry Pi用高精度 AD/DAボードについては下記のWebサイトを参考にしました(英語)。
https://www.waveshare.com/wiki/High-Precision_AD/DA_Board
■接続
ラズパイの電源がOFFの状態で下記の接続を行います。
- Raspberry Pi用高精度 AD/DAボードをラズパイの上に被せるようにしてGPIOに接続します。
- Raspberry Pi用高精度 AD/DAボードの端子を付属のジャンパピンによって下記に従って接続します。
接続箇所 | 端子1 | 端子2 | 備考 |
---|---|---|---|
VCC | VCC | 3V3または5V | 入力に使用する機器の電源電圧が3.3[V]の場合は「3V3」、5[V]の場合は「5V」に接続。 |
VREF | VREF | 3V3または5V | リファレンス電圧(基準電圧)が3.3[V]の場合は「3V3」、5[V]の場合は「5V」に接続。 |
JMP_AGND | AGND | AINCOM | シングルエンド伝送(※1)の場合に接続。 差動伝送(※2)の場合は接続する必要なし。 |
- 入力に用いる配線をRaspberry Pi用高精度 AD/DAボードのAD0~AD7に接続します。
ただし、AD0はポテンショメータ、AD1はフォトレジスタと連動させることができるため、これらの抵抗による入力信号の調整が必要ない場合はAD0~AD1の使用を避けたほうが無難です。
(AD0~AD1とポテンショメータ、フォトレジスタの連動はジャンパピンの接続状態によって有効/無効を切り替えることができます。)
今回はAD2~AD4を使用しました。 - 入力に使用する機器の電力供給をRaspberry Pi用高精度 AD/DAボードの「VCC」に、グランドを「AGND」に接続します。
■信号取得
下記のWebサイトのサンプルを使用することで入力信号をA/D変換した値が確認できます。
https://github.com/waveshare/High-Precision-AD-DA-Board/tree/master/RaspberryPI/ADS1256/python3
上記のサンプルをもとに、今回の例に合わせた場合は下記のようなPythonスクリプトとなります。
停止させる場合はCtrl + C キーを押下します。
import time
import RPi.GPIO as GPIO
import ADS1256
TARGET_CHANNELS = (2, 3, 4) # 取得対象のチャンネル
VOLTAGE_MAX = 5.0 # 最大電圧([V]単位)
AD_VAL_MAX = 0x7FFFFF # 最大入力値
WAIT_INTERVAL = 0.1 # 更新間隔([s]単位)
try:
# ADCの初期設定
adc = ADS1256.ADS1256()
adc.ADS1256_init()
while True:
for channel in TARGET_CHANNELS:
# A/D変換した値を取得
val = adc.ADS1256_GetChannalValue(channel)
# [V]単位で表示
print("\033[2KAD%d = %lf" % (channel, val * VOLTAGE_MAX / AD_VAL_MAX)) # 「\033[2K」 → 行クリア
print("\033[%dA" % (len(TARGET_CHANNELS)), end="") # カーソル位置を上に戻す
time.sleep(WAIT_INTERVAL)
except KeyboardInterrupt:
print("Detect KeyboardInterrupt")
finally:
GPIO.cleanup()
出力
BLE通信の受信側で使用するラズパイに対して操作を行います。
BLE通信によって受信したデジタル信号をラズパイがPWM信号に変換してDC2197A-Aへ入力し、DC2197A-AがD/A変換を行って出力します。
DC2197A-Aについては下記の資料を参考にしました(英語)。
https://www.analog.com/media/en/technical-documentation/user-guides/dc2197afa.pdf
■接続
ラズパイの電源がOFFの状態で下記の接続を行います。
- DC2197A-Aの端子を付属のジャンパピンで下記のように接続します。
接続箇所 | 端子1 | 端子2 | 備考 |
---|---|---|---|
IOVCC | JP1 | VCC | IOVCCをVCCに直接接続する(デフォルト)。 |
REFSEL | JP2 | EXT | 外部リファレンス電圧を供給。 |
IDLSEL | JP3 | ZS#-FS | PWM入力がローレベルの場合はDAC出力をゼロスケール、ハイレベルの場合はフルスケールに設定。 |
PD | JP4 | ON | 通常動作(非シャットダウン・モード、デフォルト)。 |
- ラズパイのGPIOとDC2197A-Aの端子を接続します。
今回は下記のように接続しました。
ラズパイ | DC2197A-A | 備考 | |
---|---|---|---|
ピン番号 | GPIO番号 | 端子 | |
2 | 5V power | VCC、REF | 電源、外部リファレンス。 2.7V~5.5V。 |
14 | Ground | GND | グランド。 |
31 | GPIO6 | INA | PWM入力1。 D/A変換されてVOUTAから出力される。 |
33 | GPIO13 | INB | PWM入力2。 D/A変換されてVOUTBから出力される。 |
35 | GPIO19 | INC | PWM入力3。 D/A変換されてVOUTCから出力される。 |
■信号出力
ラズパイからDC2197A-Aに入力したPWM信号をVOUTA~VOUTCから出力するには下記のPythonスクリプトを実行します。
停止させる場合はCtrl + C キーを押下します。
import time
import array
import RPi.GPIO as GPIO
PWM_OUTPUT_PINS = (6, 13, 19) # PWM出力用GPIO(BCM)
PWM_FREQ = 1000 # PWM周波数(Hz)
AD_VAL_MAX = 0x7FFFFF # A/D変換した値の最大値
AD_VAL_BYTES_NUM = 3 # A/D変換した値1データ辺りのバイト数
WAIT_INTERVAL = 0.005 # 更新間隔([s]単位)
pwm_output_list = [] # PWM出力用インスタンスリスト
written_data_array = array.array('B', [0x00] * (AD_VAL_BYTES_NUM * len(PWM_OUTPUT_PINS))) # BLE通信によって書き込まれたデータを格納
# A/D変換した値の取得
def get_ad_data(data_no: int) -> int:
data = 0
top_idx = data_no * AD_VAL_BYTES_NUM
# バイトごとのデータを結合
for i in range(top_idx, top_idx + AD_VAL_BYTES_NUM):
if i < len(written_data_array):
data += written_data_array[i] << ((AD_VAL_BYTES_NUM - (i - top_idx) - 1) * 8)
else:
return -1
return data
# デューティ比(%)を取得
def get_pwm_duty(val: int) -> float:
return max(min(val * 100.0 / AD_VAL_MAX, 100.0), 0.0)
def main():
try:
# ピン番号の指定方法を設定
GPIO.setmode(GPIO.BCM)
# PWM出力用GPIO設定
for pin in PWM_OUTPUT_PINS:
GPIO.setup(pin, GPIO.OUT) # 出力設定
pwm_output = GPIO.PWM(pin, PWM_FREQ) # ピン番号と周波数を指定
pwm_output.start(0) # デューティ比(%)を指定して出力開始
pwm_output_list.append(pwm_output)
while True:
# PWM出力処理
for i in range(len(pwm_output_list)):
# A/D変換した値を取得
data = get_ad_data(i)
# 値が不正な場合は読み飛ばす
if data < 0:
continue
# A/D変換した値からデューティ比を取得
duty = get_pwm_duty(data)
# デューティ比を設定
pwm_output_list[i].ChangeDutyCycle(duty)
time.sleep(WAIT_INTERVAL)
except KeyboardInterrupt:
print("Detect KeyboardInterrupt")
finally:
# PWM出力停止
for pwm_output in pwm_output_list:
pwm_output.stop()
GPIO.cleanup()
if __name__ == "__main__":
main()
グローバル変数「written_data_array」には、BLE通信により非同期で3Byteのデータ(0x000000~0x7FFFFF、ビッグエンディアン)が3つ分連続して格納されることを想定しています。
(詳細については次回記載する予定です。)
PWM周波数は1kHzとしました。
次回
次回はBLE通信の処理についてご紹介したいと思います!!
関連記事
-
-
第1回 Visual C++で作成したDLL内のクラスをC#で利用する方法
こんにちは、ILCです。 Visual C++ (以下 VC++)で作成されたDynamic...
公開日:2024.01.19 更新日:2024.01.19
tag : Windows
-
第1回 ラズパイを使用したBLE通信 ~ ディスプレイ、キーボード、マウスを接続しないで設定 前編 ~
こんにちは、GTです。よろしくお願いします。 最近業務でラズパイのBluetooth機能を使...
公開日:2021.12.24 更新日:2021.12.24
tag : Bluetooth Raspberry Pi
-
-
【新機能探訪】Android 13から導入された『アプリごとの言語設定』
こんにちは、KNSKです。よろしくお願いします。 今回は Android13の新機能である『...
公開日:2022.12.09 更新日:2022.12.09
tag : スマートデバイス
-
第3回 ラズパイを使用したBLE通信 ~ A/D変換・D/A変換を用いた入出力編 ~
こんにちは、GTです。よろしくお願いします。 第3回の今回は、ラズパイの入出力についてご紹介...
公開日:2023.02.24 更新日:2023.02.24
tag : Bluetooth BLE Raspberry Pi