新しいテスターが欲しいなと思っていたらFNIRSI DMC-100を見つけて、中身がSDICのSD7502とAT32F415CBT7で制御していて分解画像を見たらUARTで通信してそうだったので解析してみた。
FNIRSIのハンディーオシロスコープが話題になっていたような気がする。
ちなみにUSBはファームウェアアップデート専用っぽくて、PCとつなぐと充電中は使わないでねという警告が表示される。データ保存はできるけどUSBで取得できるわけではなさそう。メモ程度かな…
ネジ6個で止まっているので分解するとクランプメータのところがフレキシブルケーブルなのでちょっと注意。
左側の小さいICがLCDとかを制御しているAT32F415CBT7で、大きいICがADCSD7502側の22Ωの下側(どっちでも良さそうだけど)からSD7502の出力が取れそうだったのでそこにジャンパケーブルを繋いで、GNDはUSB端子あたりから取って解析してみた。
CoolTermでBaudrateを9600で受信してみるとHEXモードで"5A A5 06 E0 FB 0B 0A 00 01 00 00 00 00"のようなデータが流れてきた。周期はだいたい6Hzぐらい。
5A A5がヘッダのUART通信はよくありがちな気がするのでボーレートはあってそう。
いろんなモードに変更してみて、電圧モードだと入力の値が変更しやすそうだったので電圧モードで電圧を変更していくとどうやら電圧に応じたデータというよりもこのテスターICが出力している4桁のセグメントディスプレイ用の出力がそのままUARTで出ているのではないかという疑惑がでてきた。
0.000V、0.100V、0.200Vみたいな感じでデータを入れていって解析してみると規則性が出てきたのでまずは4桁の数字を解析してみることに。
import serial
import time
PORT = "COM4"
BAUDRATE = 9600
FRAME_LENGTH = 13
HEADER = b'\x5A\xA5'
DECODE_TABLE = {
0x7B: "0", 0x0A: "1", 0x5D: "2", 0x4F: "3", 0x2E: "4",
0x67: "5", 0x77: "6", 0x4A: "7", 0x7F: "8", 0x6F: "9",
0x31: "L", 0x00: " "
}
UNIT_V = 0x02
UNIT_A = 0x01
def parse_seven_segment(frame):
digits = []
for i in range(2, 6):
hi, lo = frame[i], frame[i+1]
raw7 = ((hi >> 1) & 0x70) | (lo & 0x0F)
digits.append(DECODE_TABLE.get(raw7, "0"))
return digits
def get_decimal_info(frame):
dots = [(frame[i] & 0x10) != 0 for i in range(3, 7)]
dot_bin = "".join(["1" if d else "0" for d in dots])
pos = None
if True in dots:
pos = dots.index(True) + 1
return pos, dot_bin
def get_secondary_value(frame):
val = (frame[11] << 8 | frame[12]) * 0.01
is_neg = (frame[10] & 0x40) != 0
return -val if is_neg else val
def process_frame(frame):
digits = parse_seven_segment(frame)
dec_pos, dot_bin = get_decimal_info(frame)
is_neg = (frame[2] & 0x10) != 0
unit = ""
if frame[8] == UNIT_V: unit = "V"
elif frame[8] == UNIT_A: unit = "A"
value_str = "".join(digits)
if dec_pos:
value_str = value_str[:dec_pos] + "." + value_str[dec_pos:]
if is_neg:
value_str = "-" + value_str
dual_a = get_secondary_value(frame)
print(f"[{frame.hex(' ')}] | Dots:{dot_bin} | {value_str:>9}{unit} | Sub:{dual_a:6.2f}")
def main():
try:
ser = serial.Serial(PORT, BAUDRATE, timeout=0.1)
print(f"Listening on {PORT}...")
buffer = bytearray()
while True:
if ser.in_waiting:
buffer.extend(ser.read(ser.in_waiting))
while len(buffer) >= FRAME_LENGTH:
if buffer.startswith(HEADER):
frame = bytes(buffer[:FRAME_LENGTH])
process_frame(frame)
del buffer[:FRAME_LENGTH]
else:
del buffer[0]
time.sleep(0.01)
except KeyboardInterrupt:
print("\nStopped.")
finally:
if 'ser' in locals(): ser.close()
if __name__ == "__main__":
main()やはり7セグのデータが来ているようなんだけど、1バイトに全部収まってるわけではなくて3bit+4bitで分かれて入ってる上に1bit分は小数点なので少し面倒。でも4桁とも規則性があったので7bit分で取り出してテーブルから読み込む形にしてみた。小数点は場所に応じて計算であとから追加する形に。
あとV-Aボタンを長押しすると電圧と電流を同時に取得してWが出せるモードがあるんだけど、そのときは4桁の数字が電圧になって、12バイト目と13バイト目がuint16_tで100培値の電流データが出てくることがわかった。電流値がマイナスの場合は11バイト目の0x40が1になる。
他にも色々ありそうだけどとりあえず4桁の7セグデータと符号が分かればだいたいデータが取れそうなのでPythonツールでのテストはこのぐらいかな。とりあえず電流か電圧かの判別は単位のところでできそう。(9バイト目)
BLEとか仕込んでスマホでデータ取れるようにしたら便利かも。OpenLogとか仕込んでログ変換ツールをPythonで作っても便利かもしれない。
ADC付きのマイコンでアナログ出力しても面白いかも。DCが測れるタイプのクランプ式電流プローブとは意外と高いのでこれは破格かも。





