デモ用の地震計を作りたい
PGAの調整によってノイズ問題が解決した結果は下記参照
ゲインアンプ付きA/Dコンバータ(SX8725C)を用いた簡易地震計の製作 2(ノイズ対策)
はじめに
手元に4.5Hzっぽい昔のジオフォンがあり、デモンストレーション用に利用しようと思った。しかしデモのために本格的なロガーを用意する金銭的なアテがなく、またあっても持ち歩きが面倒。
小型のデバイスを自作できないかと考えたものの、アンプ部分の製作が目的の日時に間に合わせられる自信がない。何か安くて楽な方法は無いかと部品屋で検索していると、下記のモジュールを見つけた。
SX8725C
SX8725Cは内部に可変ゲインアンプを搭載したA/Dコンバータで、出力が微小電圧のセンサーをそのまま接続して計測可能なモジュール。
差動入力が可能なアンプを製作する手間が省けるので、手軽に使えることがメリット。マルツからMSX8725CというDIP化モジュールが販売されているため利用した。
https://www.marutsu.co.jp/pc/i/243036/
https://www.marutsu.co.jp/select/list/detail.php?id=491
製作
今度は SX8725C の利用例をネットで探し始め、下記の記事を参照した。
5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (34) A-Dコンバータの利用9 SX8725C
ネットで見つかるほぼ唯一の日本語の記事だが、初心者が利用するに十分な内容でまとめられている。
マイコンには RaspberryPi-Pico を採用し、MSX8725C に付属の説明書を参考に回路を接続した。デモではPCに接続して波形表示することになるため、電圧をシリアルで受信できれば十分。できるだけ小型かつSDカードのトラブルの心配も無いことが大きなメリット。おそらくArduinoでも問題ないだろう。
-
ジオフォンのダンピング係数が不明であるため、シャント抵抗を変えられるようにソケットで対応することにした。
-
一部のノイズ源が特定できずセンサー側にコモンモードチョークコイルを入れた状態の写真だが、あまり効果はなかった。地震計の特性に影響が出る可能性があるため、外した方が良いかもしれない。
-
基板の差動入力用の配線は平行だと周辺のノイズを拾ったため、ツイストに変更した。こちらは効果あり。
レジスタの設定は 16bit, 差動入力, ゲインアンプ使用(Pga:x1, Pga3:127/12), 5[V]給電, 電源電圧リファレンス といったものを選択した。
動作にはMicroPythonを使い、記事末尾のコードを走らせている。ほとんど紹介記事のプログラムそのまま。
# Define values
ValACCfg0 = b'\x1E' #30 #0b00011110
ValACCfg1 = b'\xFF' #255 #0b11111111
ValACCfg2 = b'\x00' #0 #0b00000000
ValACCfg3 = b'\x7F' #127 #0b01111111 #127/12
ValACCfg4 = b'\x00' #0 #0b00000000
ValACCfg5 = b'\x02' #2 #0b00000010 #diff, VBATT
ValMode = b'\x88' #132 #0b10000100 #pump off
実験
縦軸:[mV]
横軸:10 [msec]
計測は概ねうまくできているようだが、気になる点がいくつか。
-
開放時の発振。地震計を接続しても若干残っている。1Hzくらいって何だろうか。
-
致命的に問題なのがスパイクノイズである。
目下スパイクのノイズ源を探しているが、Raspberry Pi pico の昇降圧コンバータが悪さをしているのであれば電源供給から見直さないといけない。最悪、Arduinoに乗り換えも検討することになるかも。
MicroPython コード
観測の現場で良く使われてきたサンプリング100Hzを目指して割り込み処理を行うことにした。
ただし、A/Dが間に合っているのかまだ未確認。シリアルには一応100サンプル/秒来ていることが確認できた。
import utime
import machine
led = machine.Pin(25, machine.Pin.OUT)
timer = machine.Timer()
i2c_bus_number = 0
i2c_sda=machine.Pin(0)
i2c_scl=machine.Pin(1)
i2c=machine.I2C(i2c_bus_number,sda=i2c_sda, scl=i2c_scl, freq=100000)
#if we use only one i2c device, this code is useful to find the address.
addrlist = i2c.scan()
print( "address is :" + str(hex(addrlist[0])) )
addr = addrlist[0]
#addr = 0x48 # Default address of SX8725C
i2c_address = addr
#Vref = 1.22 # for internal refernce
Vref = 5.00 # for Vbatt reference
conversion_factor = Vref / (65535)
zero_shift = -98
# Define registers
RegACOutLsb = 0x50
RegACOutMsb = 0x51
RegACCfg0 = 0x52
RegACCfg1 = 0x53
RegACCfg2 = 0x54
RegACCfg3 = 0x55
RegACCfg4 = 0x56
RegACCfg5 = 0x57
RegMode = 0x70
# Define values
ValACCfg0 = b'\x1E' #30 #0b00011110
ValACCfg1 = b'\xFF' #255 #0b11111111
ValACCfg2 = b'\x00' #0 #0b00000000
ValACCfg3 = b'\x7F' #127 #0b01111111 #127/12
ValACCfg4 = b'\x00' #0 #0b00000000
ValACCfg5 = b'\x02' #2 #0b00000010 #diff, VBATT
ValMode = b'\x88' #132 #0b10000100 #pump off
reglist = []
reglist = list(range(0x50, 0x50+8))
reglist.append(0x70)
# --- Check default values (not required) ---
data=[]
for reg in reglist:
readdata = i2c.readfrom_mem(addr,reg,1)
data.append(int.from_bytes(readdata,'big'))
print(data)
#--------------------------------------------
#init
i2c.writeto_mem(addr,RegACCfg0,ValACCfg0)
i2c.writeto_mem(addr,RegACCfg1,ValACCfg1)
i2c.writeto_mem(addr,RegACCfg2,ValACCfg2)
i2c.writeto_mem(addr,RegACCfg3,ValACCfg3)
i2c.writeto_mem(addr,RegACCfg4,ValACCfg4)
i2c.writeto_mem(addr,RegACCfg5,ValACCfg5)
i2c.writeto_mem(addr,RegMode,ValMode)
# --- Check current values (not required) ---
data=[]
for reg in reglist:
readdata = i2c.readfrom_mem(addr,reg,1)
data.append(int.from_bytes(readdata,'big'))
print(data)
#--------------------------------------------
def sign16(x):
return ( -(x & 32768) | (x & 32767) );
#main
def readdata(timer):
data = []
for reg in (RegACOutLsb, RegACOutMsb):
readdata = i2c.readfrom_mem(addr,reg,1)
data.append(int.from_bytes(readdata,'big'))
data16 = (data[1]<<8 | data[0])
dataDiff = sign16(int(hex(data16),16))
mVol = 1000 * dataDiff * conversion_factor
var = "{:0=+12.4f}".format(mVol + zero_shift)
print (var)
led.value(1)
timer.init(freq=100, mode=machine.Timer.PERIODIC, callback=readdata)