Learning Objectives
- 說明為什麼 write() 返回了,儀器卻還沒做完
- 用 *OPC? 等待自動設定、長時間量測這類要花時間的動作,並依量測時間設定 timeout
- 分辨 *OPC?、*WAI、*OPC 的用途
- 維持一問一答的順序,看懂 -410 Query INTERRUPTED 的原因
指令送出了,不代表儀器做完了
write() 的工作只是把一行文字送到儀器,送完就返回,通常不到幾毫秒。但有些指令,儀器收到之後要花很久才做完:
- 示波器的自動設定(
:AUT):要找訊號、調時基、調垂直刻度,常要數百毫秒到數秒; - 電錶的長時間量測(10 PLC × 很多筆,上一課學過的
INIT); - 電源供應器打開輸出後,電壓要一段時間才穩定。
如果程式在儀器還沒做完時就去量測或讀設定,就可能拿到舊的設定或錯的數字。這一課要回答:
- 程式怎麼知道儀器「做完了」?
- 要等的時候,timeout 要設多長?
- 為什麼查詢的回答一定要讀走,否則會出現 -410?
本課的儀器是模擬的教學儀器(Uedu Sim);各儀器哪些指令需要等待、等多久,以手冊為準。
循序指令、重疊指令與 *OPC?
IEEE 488.2 把儀器的指令分成兩種:
- 循序指令(sequential):做完才處理下一個指令。大部分設定指令都是。
- 重疊指令(overlapped):開始做之後,儀器就先去處理後面的指令,原本的動作在背景繼續。示波器的自動設定、電錶的
INIT常是這一種。
對重疊指令,程式要主動確認它做完了。最簡單的方法是 *OPC?(Operation Complete query):
儀器等到前面所有的動作都做完,才回答 1。因為 query() 會等回答,程式自然就停在這一行,直到儀器做完。
scope.write(":AUT") # 送出就返回
scope.query("*OPC?") # 等到自動設定做完,回答 1
逐步看:自動設定要等多久
比較第 11 行與第 14 行印出的時間:write(":AUT") 只花了約 1 ms,*OPC? 卻等了約 800 ms,那才是示波器真正做自動設定的時間。畫面上的示波器時基與刻度都被自動調整了(本頁的模擬示波器一收到 :AUT 就換上新設定,真實的示波器要等自動設定做完)。
等待要多久:timeout 跟著量測時間調整
*OPC? 會讓 query() 一直等。上一課學過:等太久,PyVISA 會丟出 VI_ERROR_TMO。
所以在真實儀器上,如果量測要 3 秒、timeout 卻是 2 秒,*OPC? 就會逾時,即使儀器一切正常。
做法是先估算要等多久,再設定 timeout:
need = 10 * 0.02 * 5 # NPLC × 每個電源週期(秒)× 筆數
dmm.timeout = int(need * 1000) * 2 + 1000 # 毫秒,留兩倍再多 1 秒
本頁的模擬儀器也會這樣逾時:timeout 比量測時間短,read() 會丟出 VI_ERROR_TMO;回答留在儀器裡,量完之後還讀得到。
*OPC? 之外,還有兩個相關的共同指令:
| 指令 | 程式會停嗎 | 用途 |
|---|---|---|
*OPC? |
會,等到回答 1 | 最常用:確定做完再往下 |
*WAI |
不會 | 讓同一台儀器的下一個指令等前面做完;程式可以先去控制別台儀器 |
*OPC |
不會 | 做完時在狀態暫存器(*ESR? 的第 0 位元)做記號,程式可以定期去問,等待時做別的事 |
*STB?(狀態位元組)是儀器狀態的摘要,例如有一個位元表示錯誤佇列裡有東西。進階的程式會用狀態暫存器搭配「服務請求」(SRQ)讓儀器主動通知電腦,細節以手冊為準。
本課的模擬儀器也支援這種寫法:送出 *OPC 之後程式照常往下走,做完之後再問 *ESR?,回答的第 0 位元會是 1。
逐步看:等電錶量完
電錶設定成 10 PLC、5 筆,大約要 1 秒。看第 12、13 行先估算時間、設定 timeout;第 16 行的 *OPC? 等到量完;第 20 行把 INIT、*WAI、FETC? 用分號寫在同一行。
一問一答:-410 Query INTERRUPTED
儀器的回答會先放在輸出緩衝區,等電腦來讀。如果電腦還沒讀走,就又送出新的指令,
SCPI 儀器會把舊的回答丟掉,並在錯誤佇列記一筆 -410,"Query INTERRUPTED"。
這常發生在把 write() 與 read() 分開寫的時候:
dmm.write("MEAS:VOLT:DC?") # 問了
dmm.write("*IDN?") # 還沒讀,又問:上一個回答被丟掉
dmm.read() # 讀到的是 *IDN? 的回答,不是電壓
最後讀到的資料「對不上問題」,而且程式不會出錯,只會算出錯的結果。避免的方法很簡單:查詢一律用 query(),它保證一問一答。
另一種相反的錯誤是「沒問就讀」:沒有任何回答可以讀時呼叫 read(),等到 timeout 之後逾時。
逐步看:問答順序亂掉
看通訊紀錄:第 8 行送出的電壓查詢沒有被讀走,第 9 行又送出 *IDN?;第 10 行讀到的是儀器身分,不是電壓。錯誤佇列裡留下 -410。
小測驗:等待
scope.write(":AUT") 返回了,代表什麼?
你要同時控制兩台儀器:電錶量 2 秒的同時設定函數產生器。對電錶來說,哪一個寫法讓程式不必停下來等?
電錶設 VOLT:NPLC 10、SAMP:COUN 20,1 PLC 以 20 ms 計。依本課的估算方式,*OPC? 前 timeout 至少要比幾毫秒長?
小測驗:一問一答
下面是一個極簡的儀器模型:回答放在 out,送新指令時若 out 還沒被讀,就丟掉並記錯誤。程式會印出什麼?
out = None
errors = []
def write(cmd):
global out
if out is not None:
errors.append(-410)
out = None
if cmd.endswith("?"):
out = "ans:" + cmd
def read():
global out
r, out = out, None
return r
write("MEAS:VOLT?")
write("*IDN?")
print(read(), errors)
哪一個寫法最不容易出現 -410?
重點整理
write()送出就返回;自動設定、INIT這類重疊指令在儀器背景繼續做。*OPC?:等前面的動作全部做完才回答1,最簡單的同步方式。- 要等的時候先估算時間,把
timeout設得比它長;否則真實儀器上會VI_ERROR_TMO。 *WAI讓同一台儀器的下一個指令等待,程式本身不停;*OPC搭配*ESR?可以輪詢。- 查詢的回答沒讀走又送新指令 →
-410 Query INTERRUPTED;查詢一律用query(),一問一答。
下一課認識函數產生器:波形、頻率、振幅、偏移,以及示波器上看到的電壓為什麼可能和設定值不一樣。