注册
web

electron+node-serialport串口通信

electron+node-serialport串口通信



公司项目需求给客户开发一个能与电子秤硬件通信的Win7客户端,提供数据读取、处理和显示功能。项目为了兼容win7使用了electron 22.0.0版本,串口通信使用了serialport 12.0.0版本



serialport文档 electron文档


 //serialport的基本使用方法
 //安装 npm i serialport
 import { SerialPort } from 'serialport'
 SerialPort.list()//获取串口列表
 /** 创建一个串口连接
path(必需):串口设备的路径。例如,'/dev/robot' 或 'COM1'。
baudRate(必需):波特率,即每秒传输的比特数。常见值有 9600、19200、38400、57600、115200 等。
autoOpen(可选):是否在创建对象时自动打开串口。默认为 true。如果设置为 false,你需要手动调用 port.open() 来打开串口。
dataBits(可选):每字节的数据位数。可以是 5、6、7、8。默认值是 8。
stopBits(可选):停止位的位数。可以是 1 或 2。默认值是 1。
parity(可选):校验位类型。可以是 'none'、'even'、'odd'、'mark'、'space'。默认值是 'none'。
rtscts(可选):是否启用硬件流控制(RTS/CTS)。布尔值,默认值是 false。
xon(可选):是否启用软件流控制(XON)。布尔值,默认值是 false。
xoff(可选):是否启用软件流控制(XOFF)。布尔值,默认值是 false。
xany(可选):是否启用软件流控制(XANY)。布尔值,默认值是 false。
highWaterMark(可选):用于流控制的高水位标记。默认值是 16384(16KB)。
lock(可选):是否锁定设备文件,防止其他进程访问。布尔值,默认值是 true。
 **/

 const serialport = new SerialPort({ path: '/dev/example', baudRate: 9600 })

 serialport.open()//打开串口
 serialport.write('ROBOT POWER ON')//向串口发送数据
 serialport.on('data', (data) => {//接收数据
    //data为串口接收到的数据
 })

获取串口列表


 //主进程main.ts
 import { SerialPort, SerialPortOpenOptions } from 'serialport'
 //初始化先获取串口列表,提供给页面选择
 ipcMain.on('initData', async () => {
   const portList = await SerialPort.list()
   mainWindow.webContents.send('initData', {portList})
 })

 //渲染进程
 window.electron.ipcRenderer.once('initData', (_,{portList}) => {
   //获取串口列表后存入本地,登录页直接做弹窗给客户选择串口,配置波特率
   window.localStorage.setItem('portList', JSON.stringify(portList))
 })

串口选择


1720148892968.jpg


波特率配置


1720148971517.jpg


读取数据



公司秤和客户的秤串口配置不一样,所以做了model1和model2区分



 //主进程main.ts
 let P: SerialPort | undefined
 ipcMain.on('beginSerialPort', (_, { path, baudRate }) => {
   //区分配置
   const portConfig: SerialPortOpenOptions<AutoDetectTypes> =
     import.meta.env.VITE_MODE == 'model1'
       ? {
           path: path || 'COM1',
           baudRate: +baudRate || 9600, //波特率
           autoOpen: true,
           dataBits: 8
        }
      : {
           path: path || 'COM1',
           baudRate: +baudRate || 115200, //波特率
           autoOpen: true,
           dataBits: 8,
           stopBits: 1,
           parity: undefined
        }
   if (P) {
     P.close((error) => {
       if (error) {
         console.log('关闭失败:', error)
      } else {
         P = new SerialPort(portConfig)
         P?.write('SIR\r\n', 'ascii')//告诉秤端开始发送信息,具体看每个秤的配置,有的不需要
         P.on('data', (data) => {
           //接收到的data为Buffer类型,直接转为字符串就可以使用了
           mainWindow.webContents.send('readingData', data.toString())
        })
      }
    })
  } else {
     P = new SerialPort(portConfig)
     P?.write('SIR\r\n', 'ascii')
     P.on('data', (data) => {
       mainWindow.webContents.send('readingData', data.toString())
    })
  }
 })

解析数据


 <!--渲染进程解析数据-->
 <template>
   <div class="weight-con">
     <div class="weight-con-main">
       <div>
         <el-text class="wei-title" type="primary"><br /></el-text>
       </div>
       <div class="weight-panel">
         <el-text id="wei-num">{{ weightNum!.toFixed(2) }}</el-text>
         <div class="weight-con-footer">当前最大称重:600公斤</div>
       </div>
       <div>
         <el-text class="wei-title" type="primary"><br /></el-text>
       </div>
     </div>
   </div>
 </template>
 ​
 <script setup lang="ts">
 import { weightModel } from '@/utils/WeightReader'
 const emits = defineEmits(['zeroChange'])
 const weightNum = defineModel<number>()
 window.electron.ipcRenderer.on('readingData', (_, data: string) => {
   //渲染进程接收到主进程数据,根据环境变量解析数据
   weightNum.value = weightModel[import.meta.env.VITE_MODE](data)
   if (weightNum.value == 0) {
     emits('zeroChange')
  }
 })
 
</script>

 //weightReader.ts 解析配置
 export type Mode = 'model1' | 'model2'
 let str = ''
 export const weightModel = {
   model1: (weightStr: string) => {
     const rev = weightStr.split('').reverse().join('')
     return +rev.replace('=', '')
  },
   module2: (weightStr: string) => {
     str += weightStr
     if (str.match(/S\s+[A-Za-z]\s*(-?\d*.?\d+)\s*kg/g)) {
       const num = str.match(/S\s+[A-Za-z]\s*(-?\d*.?\d+)\s*kg/m)![1]
       str = ''
       return Number(num)
    } else {
       return 0
    }
  }
 }

67cd365b0ec45d2ca47e4eb0b597c33f.gif



完活~下班!



作者:彷徨的耗子
来源:juejin.cn/post/7387701265796562980

0 个评论

要回复文章请先登录注册