Skip to Content
Lua 自動化I2C 讀寫

I2C 讀寫

先設定要對話的位址:i2c.addr()

跟硬體有關的腳本得先告訴程式要跟哪一顆裝置對話,用 i2c.addr(addr [, slot]) 就能在腳本裡自己設定:

i2c.addr(0x58) -- 把這個分頁接下來要對話的位址設成 0x58

addr 是 7-bit 位址,範圍 0x01~0x7F(0 是保留給「未設定」的哨兵值, 不能拿來當合法位址);省略 slot 時作用在這個分頁預設的掛載,帶 slot 可以 指定同一分頁裡的第幾個掛載,見下一節「認識『掛載』」。模擬後端 mock 預設就有 一顆裝置回應 0x58,不用額外設定就能直接讀寫——下面的範例開頭都會自己呼叫 i2c.addr(0x58),複製下來就能直接跑,不需要再另外下任何指令:

nexus_tui.exe --dongle mock --batch --run i2c_rw.lua

⚠ 這個設定只在這次腳本執行期間有效:腳本結束時(不論成功、失敗、fail()、 發生錯誤或被中止)程式會自動把位址改回腳本開始前的樣子,不會寫進 config.ini, 也不會影響你在腳本外用互動模式或畫面設定的位址。

另一種做法:不想在腳本裡寫死位址,也可以在執行腳本之前先用畫面或指令列 (addr 58,批次模式是 --cmd "addr 58")設定好,腳本裡就不用再呼叫 i2c.addr()——兩種方式效果相同,選你順手的就好。

⚠ 指令列裡的數字跟 Lua 腳本裡的數字,預設進位制不一樣。 addr 58、 rd 16、bank reg F0 FF 這種指令列上的數字,程式一律當十六進位處理,不用加 0x。Lua 腳本裡的數字不是這樣:58 在 Lua 裡就是十進位的 58,要表示跟指令列 addr 58 一樣的位址,得自己寫成 0x58。這也是為什麼 i2c.addr(0x58) 跟下面 i2c.read/i2c.write 的範例裡,數字前面都特意加了 0x。

認識「掛載」

前面 i2c.addr() 設定的位址,設定的對象在程式裡的說法叫掛載:幫某個分頁 設定好要跟哪個位址溝通,之後這個分頁的讀寫都是對著那個位址去的(對應的指令是 mount,見指令參考)。

ic.name() 與 ic.addr()

  • ic.name() 回傳目前分頁掛載的 IC/Plugin 名稱(一個字串);沒有掛載任何東西 時是空字串 "",不是 "none"。
  • ic.addr() 回傳目前的 7-bit 位址(0 到 0x7F 之間的數字)。

這兩個實際印出來的值取決於你自己的掛載設定,範例只驗證它們的型別/範圍對不對, 不會印出實際內容——因為那個值在你的環境跟教學撰寫時的環境不會一樣。

i2c.read 與 i2c.write

i2c.write(offset, value) -- 寫一個位元組 local v = i2c.read(offset) -- 讀一個位元組,回傳一個數字 i2c.write(offset, {1, 2, 3, 4}) -- 用 table 一次連續寫 4 個位元組 local t = i2c.read(offset, 4) -- 給第二個參數 len,一次連續讀 4 個位元組 -- len 存在時 t 回傳的是 table:t[1]、t[2]、t[3]、t[4]

offset 是暫存器的位移,跟其他 Lua 數字一樣預設是十進位——要寫成十六進位得自己 加 0x(例如 0x10),直接寫 16 的話那是十進位的 16,不是 0x16。 i2c.read 省略第二個參數時回傳單一數字;給了 len 就回傳一個 table,跟上一頁 看到的 table 用法一樣,t[1] 是讀到的第一個位元組、t[2] 是第二個,以此類推。

範例:寫入、讀出、讀回比對

-- 先設定這顆 IC 的 slave 位址,之後才能用 i2c.* 存取(見「I2C 讀寫」頁)。
i2c.addr(0x58)

-- I2C 讀取、寫入、讀回比對;ic.name()/ic.addr() 只驗證型別與範圍,不印出
-- 實際值——那個值來自你自己的掛載設定,範例不該假裝知道它是什麼。
check(type(ic.name()) == "string", "ic.name() returns a string")
check(ic.addr() >= 0 and ic.addr() <= 0x7F, "ic.addr() is a 7-bit address")

i2c.write(0x10, 0xA5)
local v = i2c.read(0x10)
check(v == 0xA5, "readback at 0x10 equals 0xA5")

i2c.write(0x20, {1, 2, 3, 4})
local t = i2c.read(0x20, 4)
check(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 4, "4-byte readback matches")

log("info", "i2c_rw done")
預期輸出
CHECK OK: ic.name() returns a string
CHECK OK: ic.addr() is a 7-bit address
CHECK OK: readback at 0x10 equals 0xA5
CHECK OK: 4-byte readback matches
i2c_rw done

接下來

下一頁介紹 bit.* 位元運算,以及只改一個位元組裡幾個位元的 i2c.set()/ i2c.clr()。