一般的I 2C裝置, 若是使用原廠提供的NXT-G Block, 只需要對於Input/Output plug的用法瞭解清楚, 通常很快就能夠上手使用.
而使用NXC, 則必須透過NXT的I 2C通訊程序與裝置進行溝通, 實作上多了一些步驟, 不過這些步驟都是標準程序, 不會因不同的裝置而有所差異, 同時如前一篇的說明, 使用NXC可以對於裝置的用法更具彈性, 也更能發揮裝置的功能, 所以即使麻煩一些都是值得的.
NXT Firmware Digital Communication功能
I 2C通訊屬非同步通訊並使用Master/Slave架構, NXT為Master端, 負責啟使I 2C通訊的程序(包含: 初始化及存’ 取請求), 而Slave端裝置則等候接收NXT的請求(request)並回應(Response)對應的動作, 這些請求主要就是進行存取Slave裝置的Register, 至於請求存取的目的則依裝置具備的功能而定, 例如, 可能是NXT要求讀取裝置所偵測到的值 或者 要求裝置執行特定的功能等.
此外, NXT firmware 會維護每個input ports所擁有的Internal Write buffer與Read Buffer, 做為待傳送資料 及 接收資料的暫存空間.
同時, NXT Firmware提供了以下3個Digital I/O Communication Methods能夠讓使用者可以存取Internal Write / Read Buffer, 以進行I 2C通訊的處理過程.
NXT Firmware Digital I/O Communication Methods功能摘要:
l NXTCommLSWrite: 起始I 2C通訊, 將Internal Write buffer資料傳送至裝置, 要求裝置回應指定長度的資料, 讀取資料並存放至Internal Read buffer.
l NXTCommLSCheckStatus: 檢查I 2C通訊的進行狀態以及裝置實際回應的資料長度.
l NXTCommLSRead: 將Internal Read buffer資料複製到使用者的Buffer.
NXT I 2C通訊的步驟與方式
NXT與裝置間的溝通需要按照特定的步驟進行, 這些過程屬於標準的I 2C通訊協定, 與裝置的類型無關, 雖然每個裝置具備的功能不同, 存取的需求可能不同, 然而對於這些差異性, 只需要在I 2C處理的過程中稍微調整就能符合應用上需求. 總之, 只要瞭解標準I 2C通訊的進行步驟, 則任何裝置, 都可以很容易的上手使用, 以下即對於NXT I 2C進行的步驟以及各個階段 NXC API的用法作一個整理與說明:
1. 初始化
要對於input port進行I 2C通訊前首先須將Input port type設成LOWSPEED或LOWSPEED_9V, 差別在於是否需要NXT的9V供電, 而NXC的API: SetSensorLowspeed(port)則會將type設成LOWSPEED_9V.
此外依據文件說明, 在設定input port type時, 須先對port的狀態屬性InvalidData設成TRUE, 再以迴路(loop)等候直到firmware完成對input port的初始化同時更新狀態值為FALSE之後, 才可以繼續後續的處理.
初始化過程NXC的程式碼為:
SetSensor(port, InvalidData, TRUE); //先將port狀態屬性設成TRUE
SetSensorLowspeed(port); //設定port type
while (SensorInvalid(port)); //等候port完成初始化
2. 啟始I 2C通訊
NXT Firmware使用NXTCommLSWrite system call來啟始對裝置的I 2C通訊, 而NXC對應的API為LowspeedWrite(port, returnlen, buffer), 函數使用的3個參數分別為:
l port – 裝置所連接的Input port.
l returnlen – 要求裝置回傳的資料長度(Bytes), 最多為16 Bytes, 若不需要讀取裝置資料則設為0.
l buffer – 為byte型態的陣列, 存放NXT啟始的通訊對象(裝置)位址資訊以及 準備要寫入的資料(若有的話).
在啟始每一次的通訊處理前, 必須先檢查port的狀態, 確定前一次的處理已經執行結束, 而可以接受新的處理請求, 檢查的方式是使用迴路(loop)等候直到LowspeedCheckStatus(port)函數的回傳值不等於32(STAT_COMM_PENDING).
讀取I 2C裝置資料範例
以Hitechnic IRReceiver Sensor為例, 參考它的Register Layout:
Address Type Contents
======= ====== ====================
…
42H byte Motor 1A control
43H byte Motor 1B control
44H byte Motor 2A control
45H byte Motor 2B control
46H byte Motor 3A control
47H byte Motor 3B control
48H byte Motor 4A control
49H byte Motor 4B control
若要讀取裝置所偵測到的所有PFIR信號, 可以透過I 2C通訊, 要求IRReceiver裝置從register 0x42的位址起回傳8 Bytes資料, NXC的程式範例如下:
byte I 2C _request_buf[]; //宣告byte陣列
// 第1個元素: 裝置的Device address(0x02)
// 第2個元素: 本次讀取之裝置register資料的起始位址(0x42)
ArrayBuild(I2C_request_buf, 0x02, 0x42);
// 檢查input port 1的狀態, 等候直到可以啟始下一次的通訊作業
while(LowspeedCheckStatus(IN_1) == STAT_COMM_PENDING);
// 啟始通訊作業, 並要求IRReceiver自register 0x42的位址回傳8 Bytes資料
LowspeedWrite(IN_1, 8, I 2C _request_buf);
寫入I 2C 裝置資料範例
至於寫入資料至I 2C裝置的方式, 可以參考以下的NXTHID使用範例:
NXTHID Register layout:
Address Type Contents
======= ====== ====================
…
41H byte Command,
42H byte Modifier
43H byte Keyboard Data
NXTHID的主要功能在於可以模擬成為鍵盤而將資料輸入到PC, 它提供3種指令作為控制傳送的動作與資料的型態, 以下範例為傳送指令至NXTHID以啟動指令的執行
/* ********************************************************
* 寫入Command到NXTHID的0x41位址以啟動指令的執行
* Command: T-Transmit data to PC
* A-Setup device for Ascii mode
* D-Setup device for Direct data mode
* ******************************************************** */
void NXTHID_RunCmd (byte hid_cmd)
{
byte I 2C _buf[]; //宣告byte陣列
// 第1個元素: NXTHID Device address(0x02)
// 第2個元素: NXTHID command register(0x41)
// 第3個元素: 要寫入NXTHID的command(hid_cmd)
ArrayBuild(I 2C _buf, 0x02, 0x41, hid_cmd);
// 檢查input port 1的狀態, 等候直到可以啟始下一次的通訊作業
while(LowspeedCheckStatus(IN_1) == STAT_COMM_PENDING);
// 啟始通訊作業, 並傳送hid_cmd指令至NXTHID,要求執行該指令
LowspeedWrite(IN_1, 0, I 2C _buf);
}
3. 檢查執行狀態
當使用LowspeedWrite(port, returnlen, buffer)啟始通訊作業之後, 如果是對裝置請求讀取資料, 則資料將會被存入至Internal Read Buffer中, 此時, 可以使用NXTCommLSCheckStatus system call來檢查執行狀態, 一方面確認通訊作業是否正常完成, 同時也可以取得存入Internal Read Buffer中資料的實際長度(Bytes).
如果要進行以上的兩個檢查, 可以使用LowspeedStatus(port, BytesReady) 的NXC API, 其中BytesReady並非作為函數的傳入參數, 而是存放由函數回應Internal Read buffer資料長度的變數, 稍後可參考後面的使用範例.
4. 讀取資料
讀取Internal Read Buffer資料的system call為NXTCommLSRead, NXC API為LowspeedRead(port, buflen, buffer), 3個參數說明如下:
l port – 裝置所連接的Input port.
l buflen – 讀取自Internal Read buffer資料的長度(Bytes), 最多為16 Bytes.
l buffer – 為byte型態的陣列, 存放自Internal Read buffer所讀取的資料.
就如同啟始通訊作業時一樣, 必須先檢查port的狀態, 確定前一次處理已經執行結束, 而可以接受新的處理請求,
檢查的方式是使用迴路(loop)等候直到LowspeedCheckStatus(port) 或 LowspeedStatus(port, BytesReady)函數的回傳值等於32(STAT_COMM_PENDING),而我是比較習慣使用第2個函數做檢查.