在安卓中使用 Modbus
經(jīng)過(guò)上面的介紹,相信大家已經(jīng)對(duì)于 Modbus 有了一個(gè)大致的了解。
那么,如何在安卓中使用 Modbus 呢?如果你理解了 Modbus 的基礎(chǔ),并且前面的兩篇文章也大致理解了,那么這就不是問(wèn)題了。
核心思路就是通過(guò)上篇文章介紹的使用 android-serialport-api 或使用 USB Host 的方法打開(kāi)串口,并獲取到輸入輸出流,然后在發(fā)送和接收數(shù)據(jù)時(shí)按照 Modbus 協(xié)議標(biāo)準(zhǔn)封裝或解析即可。
其中如何打開(kāi)串口以及獲取輸入輸出流已經(jīng)在上篇文章介紹,因此現(xiàn)在需要解決的是如何封裝/解析數(shù)據(jù)。
當(dāng)然,你可以按照 Modbus 標(biāo)準(zhǔn)文檔自己動(dòng)手寫(xiě)一個(gè)。
或者,你也可以不用重復(fù)造輪子,直接使用現(xiàn)成的第三方庫(kù)。
這里我們可以使用 modbus4j,但是,從它的名字就可以看出來(lái),這是一個(gè) java 庫(kù),好在我們只需要使用它的解析和封裝的功能,所以在安卓中依舊可以使用。
modbus4j
老規(guī)矩,使用 modbus4j 前需要先引入依賴:
// 添加倉(cāng)庫(kù)地址
repositories {
...
maven { url 'https://jitpack.io' }
}
……
// 添加依賴
implementation 'com.github.MangoAutomation:modbus4j:3.1.0'
然后在正式使用之前,我們需要新建一個(gè)類(lèi)繼承自 SerialPortWrapper
,用于實(shí)現(xiàn)在安卓上的串口功能:
class AndroidWrapper : SerialPortWrapper {
// 關(guān)閉串口
override fun close() {
TODO("Not yet implemented")
}
// 打開(kāi)串口
override fun open() {
TODO("Not yet implemented")
}
// 獲取輸入流
override fun getInputStream(): InputStream {
TODO("Not yet implemented")
}
// 獲取輸出流
override fun getOutputStream(): OutputStream {
TODO("Not yet implemented")
}
// 獲取波特率
override fun getBaudRate(): Int {
TODO("Not yet implemented")
}
// 獲取數(shù)據(jù)位
override fun getDataBits(): Int {
TODO("Not yet implemented")
}
// 獲取停止位
override fun getStopBits(): Int {
TODO("Not yet implemented")
}
// 獲取校驗(yàn)位
override fun getParity(): Int {
TODO("Not yet implemented")
}
}
在我們新建的這個(gè)類(lèi)中重寫(xiě)上述幾個(gè)方法,用于提供串口通信所需要的幾個(gè)參數(shù)即可。
然后,初始化 modbus4j 并發(fā)送消息:
val modbusFactory = ModbusFactory()
val wrapper: SerialPortWrapper = AndroidWrapper()
// 創(chuàng)建管理對(duì)象
val master = modbusFactory.createRtuMaster(wrapper)
// 發(fā)送消息
val request = ……
val response = master.send(request) // requst 為要發(fā)送的數(shù)據(jù),response 為接收到的響應(yīng)數(shù)據(jù)
上面就是 modbus4j 的簡(jiǎn)單使用方法,如果同學(xué)們甚至都不想自己去完成串口通信的話,還可以用這個(gè)庫(kù) Modbus4Android ,這個(gè)庫(kù)基于 android-serialport-api 和 上面的 modbus4j 封裝了一個(gè)安卓上到手即用的 Modbus 庫(kù)。
不過(guò)它使用的是 android-serialport-api 實(shí)現(xiàn)串口通信,如果需要使用 USB Host 的話可能還是需要自己去封裝一個(gè)庫(kù)了。(等我找到合適的測(cè)試設(shè)備后抽空我也封裝一個(gè))
并且,這個(gè)庫(kù)使用了 RxJava 如果不喜歡 RxJava 的話也得自己封裝一個(gè)了,其實(shí)封裝起來(lái)也不算難,完全可以基于這個(gè)庫(kù)自己改一改就好了。
Modbus4Android
使用這個(gè)庫(kù)的第一步,依舊是導(dǎo)入依賴:
// 添加遠(yuǎn)程倉(cāng)庫(kù)
repositories {
maven { url 'https://jitpack.io' }
}
……
// 添加依賴
dependencies {
implementation 'com.github.licheedev:Modbus4Android:2.0.2'
}
接下來(lái),為了方便使用,同時(shí)為了避免重復(fù)初始化,我們可以創(chuàng)建一個(gè)全局單例實(shí)例 ModbusManager
:
class ModbusManager : ModbusWorker() {
/**
* 釋放整個(gè)ModbusManager,單例會(huì)被置null
*/
@Synchronized
override fun release() {
super.release()
sInstance = null
}
companion object {
@Volatile
private var sInstance: ModbusManager? = null
fun getInstance(): ModbusManager {
var manager = sInstance
if (manager == null) {
synchronized(ModbusManager::class.java) {
manager = sInstance
if (manager == null) {
manager = ModbusManager()
sInstance = manager
}
}
}
return manager!!
}
}
}
復(fù)制代碼
然后初始化串口連接:
private fun initConnect(): Boolean {
Log.i(TAG, "initConnect: 開(kāi)始初始化連接 Modbus\\nconfig=$config")
val param = SerialParam
.create(config.serialPath, config.serialRate) // 串口地址和波特率
.setDataBits(config.serialDataBits) // 數(shù)據(jù)位
.setParity(config.serialParity) // 校驗(yàn)位
.setStopBits(config.serialStopBits) // 停止位
.setTimeout(config.serialTimeout) //超時(shí)時(shí)間
.setRetries(config.serialRetries) // 重試次數(shù)
try {
// 初始化前先關(guān)閉,避免串口已經(jīng)被打開(kāi)過(guò)
ModbusManager.getInstance().closeModbusMaster()
val modbusMaster = ModbusManager.getInstance().syncInit(param)
return true
// 初始化(打開(kāi)串口)成功
} catch (e: ModbusInitException) {
Log.e(TAG, "initConnect: 初始化modbus出錯(cuò)!", e)
} catch (e: InterruptedException) {
Log.e(TAG, "initConnect: 初始化modbus出錯(cuò)!", e)
} catch (e: ExecutionException) {
Log.e(TAG, "initConnect: 初始化modbus出錯(cuò)!", e)
} catch (e: ModbusTransportException) {
Log.e(TAG, "initConnect: 初始化modbus出錯(cuò)!", e)
} catch (e: ModbusRespException) {
Log.e(TAG, "initConnect: 初始化modbus出錯(cuò)!", e)
}
return false
}
完成上述步驟后,我們就可以開(kāi)始發(fā)送請(qǐng)求并接收數(shù)據(jù)了。
這里依舊以讀取線圈數(shù)據(jù)為例,我們可以使用同步請(qǐng)求:
val slaveId = 1 // 從站地址
val start = 00001 // 讀取的起始位置
val len = 1 // 需要讀取的長(zhǎng)度
val response = ModbusManager.getInstance().syncReadCoil(slaveId, start, len)
其中的 response
即為響應(yīng)數(shù)據(jù)信息。
另外,我們也可以使用異步讀取的方式:
ModbusManager.getInstance().readCoil(slaveId, start, len, object : ModbusCallback
該庫(kù)支持的所有讀取方法如下:
所有寫(xiě)數(shù)據(jù)方法如下:
總結(jié)
我們?cè)谶@篇文章中介紹了在安卓中使用串口通信時(shí)大概率會(huì)接觸到的一種應(yīng)用層協(xié)議 -- Modbus,并講解了如何在安卓中使用 Modbus ,另外介紹了幾個(gè)個(gè)人認(rèn)為比較好用的第三方庫(kù)。
-
MODBUS
+關(guān)注
關(guān)注
28文章
1742瀏覽量
76663 -
串口通信
+關(guān)注
關(guān)注
34文章
1604瀏覽量
55324 -
安卓
+關(guān)注
關(guān)注
5文章
2113瀏覽量
56884
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論