使用Electron开发串口通信应用详解
在当今的物联网和嵌入式系统开发中,串口通信作为一种经典的通信方式,依然扮演着重要的角色。Electron作为一种跨平台桌面应用开发框架,结合Node.js的能力,使得开发串口通信应用变得异常便捷。本文将深入探讨如何使用Electron开发串口通信的核心交互代码,并提供一个完整的示例。
初始化全局变量和依赖
首先,我们需要定义一些全局变量和引入必要的模块:
globalThis.mainWindow = null
const { SerialPort } = require('serialport')
const config = require('./config.js')
const hexMapTool = require('./tools/hex-map.js')
在这里,mainWindow
用于存储Electron的主窗口对象,SerialPort
是serialport
模块提供的串口操作类,config
包含了串口配置信息,hexMapTool
则用于十六进制与文本之间的映射转换。
创建串口连接
接下来,我们定义一些变量用于管理串口连接:
let port = null
let autoOpenPortInterval = null
const autoOpenPortIntervalTime = config.autoScanPortIntervalTime
port
用于存储串口连接对象,autoOpenPortInterval
用于自动重连的定时器,autoOpenPortIntervalTime
则是重连间隔时间。
打开串口
onOpenPort
函数负责打开串口连接:
function onOpenPort() {
if(port) {
try {
if(port.isOpen) {
port.close()
} else {
port.open()
}
} catch(err) {
console.log('关闭现有端口时出错,忽略并继续')
}
} else {
port = new SerialPort({
path: config.serialPort,
baudRate: config.baudRate,
// 其他配置参数...
})
}
}
如果已经存在一个串口连接,尝试关闭它;否则,创建一个新的串口连接。
监听串口事件
我们需要监听串口的打开、数据接收、关闭和错误事件:
port.on('open', () => {
console.log('串口已打开')
onSendData({ data: 'A' })
autoOpenPortInterval && clearInterval(autoOpenPortInterval)
})
port.on('data', (data) => {
onReceiveData({ data })
})
port.on('close', () => {
console.log('串口异常,已关闭')
if(!autoOpenPortInterval) {
autoOpenPortInterval = setInterval(onOpenPort, autoOpenPortIntervalTime)
console.log(`将在 ${autoOpenPortIntervalTime / 1000} 秒后尝试重新连接...`)
}
})
port.on('error', (err) => {
console.error('串口错误:', err)
if(err.message && err.message.includes('Access denied')) {
console.log('串口访问被拒绝,可能被其他程序占用或需要管理员权限')
}
try {
if(port && port.isOpen) {
port.close()
}
} catch(closeErr) {
console.log('尝试关闭错误的端口失败,继续...')
}
if(!autoOpenPortInterval) {
autoOpenPortInterval = setInterval(onOpenPort, autoOpenPortIntervalTime)
console.log(`将在 ${autoOpenPortIntervalTime / 1000} 秒后尝试重新连接...`)
}
})
应用关闭时的处理
在应用关闭时,我们需要正确关闭串口和清除定时器:
process.on('exit', () => {
if(autoOpenPortInterval) {
clearInterval(autoOpenPortInterval)
autoOpenPortInterval = null
}
if(port.isOpen) {
port.close()
console.log('关闭串口')
}
})
数据发送与接收
onSendData
函数负责发送数据到串口:
function onSendData({ data: text }) {
if(!port || !port.isOpen) {
console.error('串口未打开,无法发送数据')
return
}
const hexString = hexMapTool.onMapTextToHex(text)
if(!hexString) {
console.error('无法发送数据:未找到字符对应的十六进制映射')
return
}
try {
const buffer = Buffer.from(hexString, 'hex')
port.write(buffer, (err) => {
if(err) {
console.error('写入错误:', err)
} else {
console.log('数据发送到串口:', hexString)
}
})
} catch(error) {
console.error('转换十六进制字符串到Buffer失败:', error.message)
}
}
onReceiveData
函数处理从串口接收到的数据:
function onReceiveData({ data }) {
const hexString = Buffer.from(data).toString('hex').toUpperCase()
console.log('数据从串口接收:', data)
console.log('转换为十六进制:', hexString)
const text = hexMapTool.onMapHexToText(hexString)
mainWindow.webContents.send('receive-data', {
data: text,
hexString: hexString
})
}
注入窗口和更新映射
最后,我们提供两个函数用于注入主窗口对象和更新十六进制映射:
function onInjectWindow(win) {
mainWindow = win
}
function onUpdateHexMapping(newMapping) {
hexMapTool.onUpdateHexMapping(newMapping)
}
module.exports = {
onSendData,
onInjectWindow,
onUpdateHexMapping
}
总结
通过上述代码,我们实现了一个基于Electron的串口通信核心交互模块。该模块能够自动重连串口,发送和接收数据,并通过十六进制映射工具进行数据转换。在实际应用中,可以根据具体需求进一步扩展和优化该模块,以适应不同的串口通信场景。
希望本文能为你使用Electron开发串口通信应用提供有价值的参考。如果你有任何问题或建议,欢迎在评论区留言交流。