1. はじめに
この記事はオシロスコープをExcelで制御して測定値とスクリーンショットを取得するの続編です。オシロスコープに :WAVeform:DATA? コマンドを発行して波形データを取得できるよう改修しました。
2. 波形データの取得
以下のコマンドを使用します。コマンドの説明はRIGOL DS1104Zシリーズのものを参照しているため機種によって異なる可能性があります。
- :WAVeform:SOURce
- :WAVeform:MODE
- :WAVeform:FORMat
- :WAVeform:STARt
- :WAVeform:STOP
- :WAVeform:DATA?
2.1 :WAVeform:SOURce
読み出す波形データのデータソースを指定します。
例):WAVeform:SOURce CHAN1
?を付けて発行すると設定されているデータソースを返却します。
例):WAVeform:SOURce? → CHAN1
2.2 :WAVeform:MODE
NORMal、MAXimun、RAWのいずれかを指定します。
例):WAVeform:MODE NORMal
- NORMal:ディスプレイに表示されている波形データを読み出します。
- RAW:オシロのメモリ内のデータを読み出します。
- MAXimum:実行状態ではディスプレイに表示されている波形データを、停止状態ではメモリ内のデータを読み出します。
- データソースがMATHの場合はNORMalのみ有効。
- RAWは停止状態のときのみ有効。
- 後述の:WAVeform:DATAコマンドは取得できるデータ量に制限があるため一回で読み出せない場合は:WAVeform:STARt、:WAVeform:STOPで読み出す区間を指定しながら繰り返しデータを取得します。
本稿ではNORMalを指定します。
2.3 :WAVeform:FORMat
WORD、BYTE、ASCiiを指定します。
例):WAVeform:MODE ASCii
- WORD:1個の波形データをWORD(16bit)で読み取ります。Lowerの8bitが有効で、Upperの8bitは0です。
- BYTE:1個の波形データをBYTE(8bit)で読み取ります。
- ASCii:1個の波形の実際の電圧を読み取ります。波形データ同士はカンマで区切られます。
本稿ではASCiiを指定します。
2.4 :WAVeform:STARt
読み出す波形データの起点を指定します。初期値は1です。
例):WAVeform:STARt 1
- NORMal:1~1200の値
- MAX:1~現在の画面上の有効ポイント数
- RAW:1〜現在の最大記憶容量
本稿では1を指定します。
2.5 :WAVeform:STOP
読み出す波形データの終点を指定します。初期値は1200です。
例):WAVeform:STOP 1200
- NORMal:1~1200の値
- MAX:1~現在の画面上の有効ポイント数
- RAW:1〜現在の最大記憶容量
本稿では1200を指定します。
2.6 :WAVeform:DATA?
SOURceで指定されたデータソースの波形データを、指定されたモード、区間、フォーマットで読み出します。
波形データはTMC1データ記述子ヘッダと波形データの2つの部分で構成されます。
- TMCデータ記述子ヘッダ
- #Nxxxxxxxxxの形式
- #:識別子
- N:Length Blockのバイト数(9)
- xxxxxxxxx:Length Block(波形データのバイト数を格納するブロック)
- 波形データ
- 波形の各ポイントの電圧を","で区切って羅列(FORMatがASCiiの場合)
例)#9000015895-3.874302e-07,3.999961e-02,3.999961e-02,-3.874302e-07, ... ,2.919997e+00
※TMCデータ記述子ヘッダより、波形データは15895バイトと分かる。
本稿ではCHAN1の波形データをNORMalモード、1~1200の区間、ASCii形式で読み出します。
3. 動作
あらかじめオシロスコープのCH1にプローブ補償信号(1kHzの矩形波信号)を入力して動作させたときの例を以下に示します。
- 15行目でデータソースを指定しています。
- 16行目でスクリーンショットを取得しています。
- 17行目で波形データを読み出しています。TMCデータ記述子ヘッダの情報をC列に格納しています。波形データは「ファイル名-シート名-受信データセル座標.csv」というファイルに保存します。
3.1 スクリーンショットと読み出したデータに基づくグラフ
スクリーンショットと読み出したデータに基づくグラフを以下に示します。
- 波形データのファイルの一行目にデータソースとタイムベースのスケールを自動で付加しています。
- グラフは保存されたcsvファイルをExcelで開いて散布図で描画したものです。グラフのタイトルは1行目のデータがそのまま反映されています。
4. ソースコード(波形データ読み出し部分)
ソースコード全文は付録をご覧ください。
- モード、フォーマット、区間を設定します。
- データソース、タイムベーススケールを取得します。
- 波形データを読み出し、TMCデータ記述子ヘッダの情報をExcelのセルへ、波形データをファイルへ保存します。
Function ReadWaveformData(Line As Long, StrTxd As String, ColRxd As Long, DSO As VisaComLib.FormattedIO488)
DSO.WriteString (":WAVeform:MODE NORMal")
DSO.WriteString (":WAVeform:FORMat ASCii")
DSO.WriteString (":WAVeform:STARt 1")
DSO.WriteString (":WAVeform:STOP 1200")
Dim Channel As String
DSO.WriteString (":WAVeform:SOURce?")
Channel = DSO.ReadString()
Channel = Left(Channel, Len(Channel) - 1) '末尾の改行コードを捨てる
Dim TimebaseScale As String
DSO.WriteString (":TIMebase:SCALe?")
TimebaseScale = DSO.ReadString()
'WaveformDataはTMCデータ記述子ヘッダ(TMC data description header)と波形データの2つのパートで構成される。
'TMCデータ記述子ヘッダ:
' #Nxxxxxxxxxの形式
' #:識別子
' N:Length Blockのバイト数(9)
' xxxxxxxxx:Length Block(波形データのバイト数を格納するブロック)
'波形データ
' 波形の各ポイントの電圧を、","で区切って羅列
Dim WaveformData As String
DSO.WriteString (":WAVeform:DATA?")
WaveformData = DSO.ReadString()
'TMCデータ記述子ヘッダ部分
Dim TMCDataDescriptionHeader As String
TMCDataDescriptionHeader = Left(WaveformData, 11)
ActiveSheet.Cells(Line, ColRxd) = TMCDataDescriptionHeader
'波形データ部分
WaveformData = Replace(Mid(WaveformData, 12), ",", vbCr)
'save Waveform Data to file
Dim DataFileName As String
DataFileName = GenerateDataFileName(Line, ColRxd) + ".csv"
Dim DataString As String
DataString = Channel + "/" + TimebaseScale + WaveformData
Dim FreeFileNum As Long
FreeFileNum = FreeFile
Open DataFileName For Binary As #FreeFileNum
Put #FreeFileNum, , DataString
Close #FreeFileNum
End Function
5. おわりに
ひとまず波形データを自動で取得できるようになりました。シートを指定してそこに波形データを出力するように改修すると使い勝手が向上するものと思います。
付録A.参考資料
付録B.動作確認環境
- Windows 10 64bit 21H1
- Microsoft® Excel® 2016 MSO (バージョン 2204 ビルド 16.0.15128.20240) 32 ビット
- VISA-COM 5.9 Type Library
- Keysight IO Libraries Suite 2018 Update 0.2に同梱されているもの
- RIGOL DS1104Z
付録C.ソースコード一式
10行目のLINE_PARSER_LOOPの値を変えると繰り返し実行の開始行を変えることができます。
Option Explicit
Private Declare Sub Sleep Lib "KERNEL32.dll" (ByVal dwMilliseconds As Long)
Const COL_PARSER_CMD = 1 'A列:パーサ用コマンドカラム
Const COL_PARSER_TXD = 2 'B列:パーサ用送信データカラム
Const COL_PARSER_RXD = 3 'C列:パーサ用受信データカラム
Const LINE_PARSER_START = 10 'パーサ用コマンド開始行
Const LINE_PARSER_LOOP = 20 'パーサ用ループ処理開始行
Const LINE_TABLE_START = 10 '測定テーブル用コマンド開始行
Const VISA_ADDR_DSO = "C6" 'DSO : Digital Storage Oscilloscope
Const VISA_ADDR_TB = "C7" 'TB : Target Board
'「テスト開始」ボタン押下で呼出すマクロ
Sub Parser()
Dim i As Long
Dim LoopNum As Long
Dim LoopNumMax As Long
LoopNumMax = 1 'いったん1で設定(LOOPコマンドで上書き可)
Dim StrCmd As String
Dim StrTxd As String
LoopNum = 0
Do While LoopNum < LoopNumMax
i = LINE_PARSER_START
Do While ActiveSheet.Cells(i, COL_PARSER_CMD) <> ""
If LoopNum >= 1 And i < LINE_PARSER_LOOP Then
'処理をスキップする
Else
ActiveSheet.Cells(i, COL_PARSER_CMD).Select
StrCmd = ActiveSheet.Cells(i, COL_PARSER_CMD)
StrTxd = ActiveSheet.Cells(i, COL_PARSER_TXD)
If InStr(StrCmd, "//") > 0 Then
'何もしない
ElseIf StrCmd = "DSO" Then
Call ControlDSO(i, StrTxd, COL_PARSER_RXD)
ElseIf StrCmd = "TB" Then
Call ControlTB(i, StrTxd, COL_PARSER_RXD)
ElseIf StrCmd = "WAITMS" Then
Call SysWaitMs(StrTxd)
ElseIf StrCmd = "MSGBOX" Then
MsgBox (StrTxd)
ElseIf StrCmd = "LOOP" Then
If IsNumeric(StrTxd) = True Then
LoopNumMax = CInt(StrTxd)
Else
MsgBox ("unknown value")
End If
ElseIf StrCmd = "TABLE" Then
Call SysTable(LoopNum, StrTxd)
Else
MsgBox ("unknown command")
End If
End If
i = i + 1
Loop
LoopNum = LoopNum + 1
Loop
End Sub
Function SysTable(LoopNum As Long, ColTable As String)
Dim i As Long
Dim Column As Long
Dim StrCmd As String
Dim StrTxd As String
i = LoopNum + LINE_TABLE_START
Column = Range(ColTable + "1").Column
ActiveSheet.Cells(i, Column).Select
StrCmd = ActiveSheet.Cells(i, Column)
StrTxd = ActiveSheet.Cells(i, Column + 1)
If StrCmd = "DSO" Then
Call ControlDSO(i, StrTxd, Column + 2)
ElseIf StrCmd = "TB" Then
Call ControlTB(i, StrTxd, Column + 2)
End If
i = i + 1
End Function
'Line:送信データが記述されているセルの行番号
'StrTxd:送信データ
'ColRxd:受信データの格納先セルの列番号
Function ControlDSO(Line As Long, StrTxd As String, ColRxd As Long)
Dim VisaAddr As String
VisaAddr = ActiveSheet.Range(VISA_ADDR_DSO)
Dim RM As New VisaComLib.ResourceManager
Dim DSO As New VisaComLib.FormattedIO488
Set DSO.IO = RM.Open(VisaAddr)
If InStr(StrTxd, ":DISPlay:DATA?") > 0 Then
Call ReadDisplayData(Line, StrTxd, ColRxd, DSO)
ElseIf InStr(StrTxd, ":WAVeform:DATA?") > 0 Then
Call ReadWaveformData(Line, StrTxd, ColRxd, DSO)
ElseIf InStr(StrTxd, "?") > 0 Then
DSO.WriteString StrTxd
ActiveSheet.Cells(Line, ColRxd) = Replace(DSO.ReadString(), vbLf, "")
Else
'MsgBox (StrTxd)
DSO.WriteString StrTxd
End If
DSO.IO.Close
Set DSO = Nothing
Set RM = Nothing
End Function
'拡張子は呼び出し元で付けること
Function GenerateDataFileName(Line As Long, ColRxd As Long) As String
Dim FilePath As String
FilePath = ThisWorkbook.Path
Dim FileName As String
FileName = Left(ThisWorkbook.Name, Len(ThisWorkbook.Name) - 5)
Dim SheetName As String
SheetName = ActiveSheet.Name
Dim DataFileName As String
DataFileName = FilePath + "\" + FileName + "-" + SheetName + "-" + CStr(Line) + "-" + CStr(ColRxd)
GenerateDataFileName = DataFileName
End Function
Function ReadDisplayData(Line As Long, StrTxd As String, ColRxd As Long, DSO As VisaComLib.FormattedIO488)
DSO.WriteString StrTxd
Dim ReadIEEEBlockData() As Byte
ReadIEEEBlockData = DSO.ReadIEEEBlock(BinaryType_UI1)
Dim DataFileName As String
DataFileName = GenerateDataFileName(Line, ColRxd) + ".png"
Dim FreeFileNum As Long
FreeFileNum = FreeFile
Open DataFileName For Binary As #FreeFileNum
Put #FreeFileNum, , ReadIEEEBlockData
Close #FreeFileNum
With ActiveSheet.Pictures.Insert(DataFileName)
.Top = Cells(Line, ColRxd).Top
.Left = Cells(Line, ColRxd).Left
.Height = Cells(Line, ColRxd).Height
End With
End Function
Function ReadWaveformData(Line As Long, StrTxd As String, ColRxd As Long, DSO As VisaComLib.FormattedIO488)
DSO.WriteString (":WAVeform:MODE NORMal")
DSO.WriteString (":WAVeform:FORMat ASCii")
DSO.WriteString (":WAVeform:STARt 1")
DSO.WriteString (":WAVeform:STOP 1200")
Dim Channel As String
DSO.WriteString (":WAVeform:SOURce?")
Channel = DSO.ReadString()
Channel = Left(Channel, Len(Channel) - 1) '末尾の改行コードを捨てる
Dim TimebaseScale As String
DSO.WriteString (":TIMebase:SCALe?")
TimebaseScale = DSO.ReadString()
'WaveformDataはTMCデータ記述子ヘッダ(TMC data description header)と波形データの2つのパートで構成される。
'TMCデータ記述子ヘッダ:
' #Nxxxxxxxxxの形式
' #:識別子
' N:Length Blockのバイト数(9)
' xxxxxxxxx:Length Block(波形データのバイト数を格納するブロック)
'波形データ
' 波形の各ポイントの電圧を、","で区切って羅列
Dim WaveformData As String
DSO.WriteString (":WAVeform:DATA?")
WaveformData = DSO.ReadString()
'TMCデータ記述子ヘッダ部分
Dim TMCDataDescriptionHeader As String
TMCDataDescriptionHeader = Left(WaveformData, 11)
ActiveSheet.Cells(Line, ColRxd) = TMCDataDescriptionHeader
'波形データ部分
WaveformData = Replace(Mid(WaveformData, 12), ",", vbCr)
'save Waveform Data to file
Dim DataFileName As String
DataFileName = GenerateDataFileName(Line, ColRxd) + ".csv"
Dim DataString As String
DataString = Channel + "/" + TimebaseScale + WaveformData
Dim FreeFileNum As Long
FreeFileNum = FreeFile
Open DataFileName For Binary As #FreeFileNum
Put #FreeFileNum, , DataString
Close #FreeFileNum
End Function
Function ControlTB(Line As Long, StrTxd As String, ColRxd As Long)
Dim i As Long
Dim j As Long
Dim StrVal As String
Dim StrArray() As String
' Dim DbgStr As String
Dim VisaAddr As String
VisaAddr = ActiveSheet.Range(VISA_ADDR_TB)
Dim RM As New VisaComLib.ResourceManager
Dim TB As New VisaComLib.FormattedIO488 'TB : Target Board
Set TB.IO = RM.Open(VisaAddr)
Dim Sfc As VisaComLib.ISerial 'RS232C通信設定
Set Sfc = TB.IO
Sfc.BaudRate = 115200
Sfc.DataBits = 8
Sfc.Parity = ASRL_PAR_NONE
Sfc.StopBits = ASRL_STOP_ONE
Sfc.FlowControl = ASRL_FLOW_NONE
TB.IO.TerminationCharacter = 10
TB.IO.TerminationCharacterEnabled = True
TB.WriteString StrTxd
StrVal = ""
For i = 1 To 3 'Write→ReadのあいだにSleepを入れる
Sleep (10)
DoEvents
StrVal = StrVal + TB.ReadString()
ReDim StrArray(1 To Len(StrVal))
For j = 1 To UBound(StrArray) '制御文字を削除する
StrArray(j) = Mid(StrVal, j, 1)
If Asc(StrArray(j)) <= 31 Or 127 <= Asc(StrArray(j)) Then
' DbgStr = CStr(i) + "," + CStr(j) + "," + CStr(Asc(StrArray(j)))
' MsgBox (DbgStr)
StrArray(j) = ""
End If
Next j
StrVal = Join(StrArray, "")
If i <= 2 Then
StrVal = StrVal + "/"
End If
If StrVal <> "" Then
ActiveSheet.Cells(Line, ColRxd).Value = StrVal
'Exit For
End If
Next
TB.IO.Close
Set TB = Nothing
Set RM = Nothing
End Function
Function SysWaitMs(WaitMs As String)
Dim i As Long
Dim LoopNum As Long
If IsNumeric(WaitMs) = True Then
LoopNum = CInt(WaitMs) / 100
For i = 1 To LoopNum
Sleep (100)
DoEvents
Next
Else
MsgBox ("unknown value")
End If
End Function
-
USB TMC(Universal Serial Bus Test & Measurement Class) ↩