前回の記事では、Raspberry Pi で脈拍計(心拍計)の作り方を分かりやすく紹介しました。脈拍計に使用したA/DコンバータMCP3002に関して詳細に解説せず接続の方法を記載しただけでした。
今回はMCP3002の各ピンの役割、データ送受信の仕組みとSPI通信するためのプログラムの書き方に関して詳しく紹介します。A/Dコンバータの知識が深まると思いますので、参考にしてみてください。
前回紹介したRaspberry Pi で脈拍計(心拍計)の作り方を先に読まれると、今回の記事が分かりやすいと思いますので参考にしてください。
Raspberrypiとセンサとの接続方法
まず、MCP3002の接続先と各ピンの役割を説明します。
今回、Raspberry Pi と MCP3002間のデータ伝送方法は、SPI通信を用いています。
Raspberry Pi(指令を送る側)をマスタと呼び、A /Dコンバータ(指令を受け取る側)をスレーブと呼びます。スレーブは指令によって得た情報をマスタに返送します。
1つのマスタに複数のスレーブを繋げることが可能です。CS/SHDNをマスタのGPIO8(24番)に繋ぎ、ON・OFF信号を送ることで、どのスレーブに指令を送るか指定できます。GPIO7(26番)に繋げても可能ですが、プログラムのコードも変わるので注意してください。
脈拍センサからのアナログ信号をCH0またはCH1で受け取ります。脈拍センサの右端のコードをCH0またはCH1のどちらかに繋げます。
CLKでマスタからのクロック信号を受け取ります。
DOUTをラズパイのSPI_MISO端子(21番)に繋ぐことで、センサが得たデータをマスタへ送ります。
DIN をラズパイの SPI_MOSI端子(19番)に繋ぐことで、マスタからの指令を受けとります。
VSS は GNDに、VDD/VREF は5V電源に繋げます。
MCP3002でのデータ送受信の仕組み
A/DコンバータMCP3002を動かすために、必要な入力データと出力されるデータの仕組みを説明します。
データを送る方式には、先頭から送るMSBと最後尾から送るLSBの2つの方式があります。
今回はMSB方式を採用しています。下図のMCP3002でのMSB方式におけるフォーマットを見ることで、スレーブへ送る入力コマンド(Din)の設定と、AD変換したデータの出力(Dout)の読み取りの方法が分かります。
クロックの周波数に合わせて、Din 、Dout のビットデータは送られています。
Din の各ビットデータの中身は、まずStartは”1”とします。SGL/DIFFは”1”でシングルエンド入力となり”0”で擬似作動入力を選択でき、今回はシングルエンド入力の”0”を選択します。ODD/SIGNは”0”でCh0を選択し、”1”でCh1を選択できます。今回はCh1にしています。MSBFではMSB方式を採用しているので”1”とします。
Dout の各ビットにおいて、B0からB9が脈拍センサが読み取った値をAD変換したデータになります。B0からB9は”1”にし、その他は”0”にします。
マスタとスレーブ間のSPI通信では8ビット単位でデータをやり取りしています。ここで、Din とDout のデータは共にB0から逆に数えて16ビット目からB0までのデータを使用し、8ビットずつに区切ります。
Din の灰色部分は「Don’t Care=0でも1でも良い」という意味を指します。よって、今回の8ビット単位に分けたDin のデータは”01011000” “00000000“となります。
Dout は読み取りたいB0からB9のみをを1にするので、”00000011” ”11111111”となります。
以上がRaspberryPi と MCP3002 間のデータやり取り方法になります。次にプログラムの解説します。
プログラム
import spidev
import time
import matplotlib.pyplot as plt
import numpy as np
spi = spidev.SpiDev()
spi.open(0,0) #CS/SHDNを24番ピンに繋げば(0,0)、26番ピンに繋げば(0,1)とする。
spi.max_speed_hz = 1000000 #転送速度設定:1MHz
sleeptime = 0.001 #ここでサンプリング周波数を調整
x = []
y = []
start_time = time.perf_counter()
while True:
try:
Dout = spi.xfer2([0x68, 0x00]) #Din入力
amp = ((Dout[0] << 8) + Dout[1]) & 0x3FF #Doutのデータを10進数に変換
elapsed_time = time.perf_counter() - start_time #測定経過時間を算出
y.append(amp)
x.append(elapsed_time)
time.sleep(sleeptime)
print(elapsed_time)
except KeyboardInterrupt:
spi.close() #spi通信終了
break
np.savetxt('data.txt',y) #脈拍波形データ保存後にグラフ表示
plt.plot(x,y)
plt.show()
測定終了後、脈拍波形を表示するプログラム全体は上記のようになります。簡単な解説はコメントアウトで表していますが16行、17行目だけ補足説明します。
16行目のspi.xfer2( )内にDin の16ビットデータを2要素に分けて入力すると、Doutの16ビットデータが2要素に分かれて出力されます。
プログラムコード上のデータは16進数で表現されていますが、2進数でも10進数でも実行できます。16進数で表現が一般的のようです。
2進数で表現すると、spi.xfer2([0b1101000, 0b0])となります。
マスタとスレーブ間のSPI通信では8ビット単位でのデータのやり取りのため、16ビットを2つに分けています。
17行目では、8ビットずつに分けられたDout のデータを16ビットデータに直します。得られた16ビットデータを”0000001111111111”で&処理することで、B0からB9までのデータだけが残るようにしています。ビット演算を参考に見てみてください。
まとめ
はじめはただ脈拍波形を取ろうと思っただけでしたが、Raspberry Piで脈拍測定するためにはA/Dコンバータの接続が必要でした。マスタとスレーブ間でのデータのやり取りの仕組みやSPI通信するためのプログラムの書き方など新たに参考になることがたくさんありました。今後は取得した脈拍波形から、実際に脈拍数やストレス度の測定も行っていきたいと思います。
ぜひ、前回記事も参考にしてみてください!!
コメント