位置: IT常识 - 正文

Vue使用Serial连接串口(vue连接webapi)

编辑:rootadmin
Vue使用Serial连接串口

推荐整理分享Vue使用Serial连接串口(vue连接webapi),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:vue serialport,vue绑定接口,vue绑定接口,vue可以直接连接数据库,vue怎么连接后端接口,vue怎么连接数据库,vue serialport,vue连接口,内容如对您有帮助,希望把文章链接给更多的朋友!

本来只是随手记录一下,发现看的人多了,想着还是修复一下bug吧,供各位看官指正

2022-10-24本次更新:

1、修复在不支持Serial的情况下,控制台报错

2022-09-19本次更新:

 1、修复了传输数据接收分隔的情况(增加数据缓存)

 2、修复串口连接没有使用选择的波特率等参数

1、Serial 接口是 Web Serial API的接口,提供了从网页查找和连接串口的属性和方法。

注意:

  只能在部分支持Serial并且网站为安全上下文(HTTPS)中可用,或者是本机访问

一:常用API介绍

requestPort----获取授权串口

open-----打开串口

Vue使用Serial连接串口(vue连接webapi)

close---关闭串口(串口关闭前,需要释放锁住的流)

cancel---立即退出读取的循环,然后去调用releaseLock,最后调用close方法

releaseLock---Reader和.Writer的释放方法

read---port.readable.getReader()的读取字节数组方法

write---port.writable.getWriter()的写入方法

二:代码示例

MySerialPort.js 是封装的一个SerialPort的工具类

export default class MySerialPort { constructor() { this.state = { portIndex: undefined, ports: [], isOpen: false, writeType: 1, readType: 1, isScroll: true, readValue: [], status:false, //port参数 baudRate: "9600", dataBits: "8", stopBits: "1", parity: "none", flowControl: "none", }; this.keepReading=false; this.getPorts = this.getPorts.bind(this); this.handleRequestPort = this.handleRequestPort.bind(this); this.handleChildrenChange = this.handleChildrenChange.bind(this); this.readText = this.readText.bind(this); this.writeText = this.writeText.bind(this); this.handleClear = this.handleClear.bind(this); this.a2hex = this.a2hex.bind(this); this.hex2a = this.hex2a.bind(this); this.hex2atostr=this.hex2atostr.bind(this); this.reader={}; this.closed; } async getPorts() { // 获取已授权的全部串口 let ports = await navigator.serial.getPorts(); this.setState({ ports, }); } async handleRequestPort() { // 请求授权 try { await navigator.serial.requestPort(); await this.getPorts(); } catch (e) { this.$message.error(e.toString()); } } async openPort(portIndex, isOpen,callBack=null) { // 打开串口 let port = this.state.ports[portIndex]; if (!isOpen) { // 关闭串口 this.keepReading = false; this.reader.cancel(); await this.closed; this.handlePortOpen({ portIndex, isOpen, }); } else { await port.open({ baudRate: this.state.baudRate, dataBits: this.state.dataBits, stopBits: this.state.stopBits, parity: this.state.parity, flowControl: this.state.flowControl, }); this.handlePortOpen({ portIndex, isOpen, }); this.keepReading = true; this.closed=this.readUntilClosed(portIndex,callBack); } } async readUntilClosed(portIndex,callBack=null) { let port = this.state.ports[portIndex]; while (port.readable && this.keepReading) { this.reader = port.readable.getReader(); try { let readCache=[] while (true) { const { value, done } = await this.reader.read(); if (done) { break; } readCache.push(...value) setTimeout(() => { if(readCache.length>0){ this.readText(readCache); callBack(readCache) readCache=[] } }, 300);//串口缓存 } } catch (error) { this.$message.error(error.toString()); } finally { this.reader.releaseLock(); } await port.close(); } } handlePortOpen({ portIndex, isOpen }) { // 处理打开串口 this.setState({ portIndex, isOpen, }); } handleChildrenChange(type, value) { this.setState({ [type]: value, }); } portWrite(value) { return new Promise(async (resolve, reject) => { if (!this.state.isOpen) { this.$message.error("串口未打开"); reject(); return; } else { let port = this.state.ports[this.state.portIndex]; const writer = port.writable.getWriter(); await writer.write(new Uint8Array(value)); writer.releaseLock(); resolve(value); } }); } readText(value) { console.log(value, "读取"); let newValue = this.state.readValue.concat({ value, type: 1, }); this.setState({ readValue: newValue, }); } writeText(value) { console.log(value, "写入"); this.portWrite(value).then((res) => { let newValue = this.state.readValue.concat({ value: res, type: 2, }); this.setState({ readValue: newValue, }); }); } handleClear() { this.setState({ readValue: [], }); } componentDidMount() { this.getPorts(); } handleState(status) { this.setState({ status, }); } setState(obj){ Object.keys(this.state).forEach(key => { if(obj[key]!=undefined){ this.state[key]=obj[key] } }); } //字节转字符串 hex2atostr(arr) { return String.fromCharCode.apply(String,arr); } hex2a(hexx) { return String.fromCharCode(hexx); } //字符转16进制 a2hex(str) { return str.charCodeAt(0);}}

 vue代码:

<template> <div> <el-row type="flex" class="row-bg" justify="center" v-show="portsList.length == 0" > <el-col :span="7" ><div style="margin-top: 400px"> <span style="display: block"> 仅支持Chrome 89+或者Edge 89+浏览器(安全上下文(HTTPS)中可用) </span> <el-button type="primary" @click="obtainAuthorization" >授权</el-button > </div></el-col > </el-row> <el-form v-show="portsList.length > 0" ref="form" :model="form" label-width="100px" > <el-row> <el-col :span="6" ><div> <el-form-item label="串口"> <el-select v-model="form.port" filterable placeholder="请选择串口" :disabled="isDisable" > <el-option v-for="item in portsList" :key="item.value" :label="item.label" :value="item.value" > </el-option> </el-select> </el-form-item> <el-form-item label="波特率"> <el-autocomplete popper-class="my-autocomplete" v-model="form.baudRate" :fetch-suggestions="querySearch" placeholder="请输入波特率" :disabled="isDisable" > <i class="el-icon-edit el-input__icon" slot="suffix"> </i> <template slot-scope="{ item }"> <div class="name">{{ item.value }}</div> <span class="addr">{{ item.address }}</span> </template> </el-autocomplete> </el-form-item> <el-form-item label="数据位"> <el-select v-model="form.dataBits" placeholder="请选择数据位" :disabled="isDisable" > <el-option label="7" value="7"></el-option> <el-option label="8" value="8"></el-option> </el-select> </el-form-item> <el-form-item label="停止位"> <el-select v-model="form.stopBits" placeholder="请选择停止位" :disabled="isDisable" > <el-option label="1" value="1"></el-option> <el-option label="2" value="2"></el-option> </el-select> </el-form-item> <el-form-item label="校验位"> <el-select v-model="form.parity" placeholder="请选择校验位" :disabled="isDisable" > <el-option label="None" value="none"></el-option> <el-option label="Even" value="even"></el-option> <el-option label="Odd" value="odd"></el-option> </el-select> </el-form-item> <el-form-item label="流控制"> <el-select v-model="form.flowControl" placeholder="请选择流控制" :disabled="isDisable" > <el-option label="None" value="none"></el-option> <el-option label="HardWare" value="hardware"></el-option> </el-select> </el-form-item> <el-form-item label="显示历史"> <el-switch v-model="form.isShowHistory" @change="loadHistory" ></el-switch> <el-button type="danger" icon="el-icon-delete" circle title="清空历史" @click="clearHistory" ></el-button> </el-form-item> <el-form-item label="发送区设置" v-show="isShowSendArea"> <el-form-item label="发送格式"> <el-radio-group v-model="form.type"> <el-radio label="1">ASCII</el-radio> <el-radio label="2">HEX</el-radio> </el-radio-group> </el-form-item> <el-form-item label="发送信息"> <el-input type="textarea" v-model="form.sendMsg"></el-input> </el-form-item> <el-button type="primary" @click="sendCommon">发送</el-button> </el-form-item> <el-form-item> <el-button :type="btnType" @click="connectBtn">{{ btnText }}</el-button> <el-button type="info" @click="obtainAuthorization" >新增授权</el-button > </el-form-item> </div> </el-col> <el-col :span="10" ><div> <el-form-item label="电子秤信息"> <el-input type="textarea" v-model="form.desc" disabled :autosize="{ minRows: 21, maxRows: 25 }" ></el-input> </el-form-item></div ></el-col> </el-row> </el-form> </div></template><script>import MySerialPort from "./MySerialPort";import USBDevice from "./usb.json";export default { data() { return { input: "", keepReading: true, form: { baudRate: "9600", dataBits: "8", stopBits: "1", parity: "none", flowControl: "none", desc: "", type: "1", isShowHistory: false, }, btnType: "primary", btnText: "连接串口", restaurants: [], portsList: [], isShowSendArea: false, readType: 1, }; }, mounted() { if ("serial" in navigator) { this.myserialport = new MySerialPort(); this.getPorts(); navigator.serial.addEventListener("connect", (e) => { this.$message.success("设备已连接"); this.getPorts(); }); navigator.serial.addEventListener("disconnect", (e) => { this.$message.error("设备已断开"); }); this.restaurants = this.loadAll(); } else { this.$message.error( "当前为HTTP模式或者浏览器版本过低,不支持网页连接串口" ); } }, computed: { isDisable() { return this.btnType == "danger"; }, }, methods: { //接受数据的回调 callBack(value) { if (this.form.isShowHistory) this.form.desc = this.readLi().join(""); else { if (value.length > 0) this.form.desc = this.myserialport.hex2atostr(value); } }, clearHistory() { this.form.desc = ""; this.myserialport.state.readValue = []; }, loadHistory() { if (this.form.isShowHistory) this.form.desc = this.readLi().join(""); else { let temp = this.readLi(); if (temp.length > 0) this.form.desc = temp[temp.length - 1].join(""); } }, readLi() { let readType = this.readType; return this.myserialport.state.readValue.map((items, index) => { const item = items.value; const type = items.type; // 1接收,2发送 let body = []; if (item !== undefined) { let strArr = []; for (let hex of Array.from(item)) { strArr.push(hex.toString(16).toLocaleUpperCase()); } if (strArr.includes("D") && strArr.includes("A")) { if (strArr.indexOf("A") - strArr.indexOf("D") === 1) { strArr.splice(strArr.indexOf("D"), 1); strArr.splice(strArr.indexOf("A"), 1, <br key={0} />); } } strArr = strArr.map((item) => { if (typeof item === "string") { if (readType === 1) { return this.myserialport.hex2a(parseInt(item, 16)); } else if (readType === 2) { return item + " "; } } return item; }); if (typeof strArr[strArr.length - 1] === "string") { strArr.push("\r\n"); } body.push(strArr.join("")); } return body; }); }, //连接 async connectBtn() { if (this.btnType == "primary") { try { this.myserialport.state.baudRate = this.form.baudRate; this.myserialport.state.dataBits = this.form.dataBits; this.myserialport.state.stopBits = this.form.stopBits; this.myserialport.state.parity = this.form.parity; this.myserialport.state.flowControl = this.form.flowControl; await this.myserialport.openPort(this.form.port, true, this.callBack); } catch (error) { this.$message.error("串口连接失败!请检查串口是否已被占用"); } if (this.myserialport.state.isOpen) { this.$message.success("串口连接成功"); this.btnType = "danger"; this.btnText = "关闭串口"; } } else { this.myserialport.openPort(this.form.port, false, this.callBack); this.$message.success("串口关闭成功"); this.btnType = "primary"; this.btnText = "连接串口"; } }, //授权 async obtainAuthorization() { if ("serial" in navigator) { console.log("The Web Serial API is supported."); if (!this.myserialport) this.myserialport = new MySerialPort(); try { await this.myserialport.handleRequestPort(); this.$message.success("串口授权成功"); this.getPortInfo(this.myserialport.state.ports); } catch (error) { this.$message.warning("未选择新串口授权!"); } } else { this.$message.error( "当前为HTTP模式或者浏览器版本过低,不支持网页连接串口" ); } }, //串口列表初始化 getPortInfo(portList) { this.portsList = []; portList.map((port, index) => { const { usbProductId, usbVendorId } = port.getInfo(); if (usbProductId === undefined || usbVendorId === undefined) { this.portsList.push({ label: "未知设备" + index, value: index }); } else { const usbVendor = USBDevice.filter( (item) => parseInt(item.vendor, 16) === usbVendorId ); let usbProduct = []; if (usbVendor.length === 1) { usbProduct = usbVendor[0].devices.filter( (item) => parseInt(item.devid, 16) === usbProductId ); } this.portsList.push({ label: usbProduct[0].devname, value: index }); } }); }, // 发送 async sendCommon() { if (this.myserialport.state.isOpen) { if (this.form.sendMsg.length !== 0) { const writeType = this.form.type; let value = this.form.sendMsg; let arr = []; if (writeType == 1) { // ASCII for (let i = 0; i < value.length; i++) { arr.push(this.myserialport.a2hex(value[i])); } } else if (writeType == 2) { // HEX if (/^[0-9A-Fa-f]+$/.test(value) && value.length % 2 === 0) { for (let i = 0; i < value.length; i = i + 2) { arr.push(parseInt(value.substring(i, i + 2), 16)); } } else { this.$message.error("格式错误"); return; } } this.myserialport.writeText(arr); } else { this.$message.warning("请输入发送的信息"); } } else { this.$message.warning("串口处于关闭状态,请连接串口"); } }, async getPorts() { await this.myserialport.getPorts(); this.getPortInfo(this.myserialport.state.ports); }, querySearch(queryString, cb) { var restaurants = this.restaurants; var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants; // 调用 callback 返回建议列表的数据 cb(results); }, createFilter(queryString) { return (restaurant) => { return ( restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === ); }; }, loadAll() { return [ { value: "110" }, { value: "300" }, { value: "600" }, { value: "1200" }, { value: "2400" }, { value: "4800" }, { value: "7200" }, { value: "9600" }, { value: "14400" }, { value: "19200" }, { value: "28800" }, { value: "38400" }, { value: "56000" }, { value: "57600" }, { value: "76800" }, { value: "115200" }, { value: "230400" }, { value: "460800" }, ]; }, },};</script><style scoped>/* ::v-deep .el-textarea__inner { height: 320px !important; width: 80% !important;} */</style>三:示例截图

授权界面:

授权成功后:

使用串口工具调试发送和接收: 

1、使用vspd创建一个对虚拟串口,com1和com2

2、网页的连接com1,sscom连接com2就可以进行通信了

本文链接地址:https://www.jiuchutong.com/zhishi/311774.html 转载请保留说明!

上一篇:dedecms调用当前文章所属栏目名(dedecms进入数据库)

下一篇:机器学习——果蔬分类

  • 浏览器历史记录设置(浏览器历史记录查询)

    浏览器历史记录设置(浏览器历史记录查询)

  • 腾讯课堂怎么确定自己关麦(腾讯课堂怎么确认签到)

    腾讯课堂怎么确定自己关麦(腾讯课堂怎么确认签到)

  • 怎么暂停微信步数(怎么暂停微信步数增长不让对方发现你已设置)

    怎么暂停微信步数(怎么暂停微信步数增长不让对方发现你已设置)

  • qq我的音乐盒干嘛的(qq中我的音乐盒)

    qq我的音乐盒干嘛的(qq中我的音乐盒)

  • 苹果手表充电显示绿色闪电和一条线(苹果手表充电显示红色闪电)

    苹果手表充电显示绿色闪电和一条线(苹果手表充电显示红色闪电)

  • 三星s10黑屏了什么情况(三星s10手机黑屏打不开)

    三星s10黑屏了什么情况(三星s10手机黑屏打不开)

  • QQ位置怎么发(qq位置怎么发不出去了)

    QQ位置怎么发(qq位置怎么发不出去了)

  • 苹果手机电池不行会有哪些反应(苹果手机电池不掉电是怎么回事)

    苹果手机电池不行会有哪些反应(苹果手机电池不掉电是怎么回事)

  • 回收站中的文件可以改名吗(如何还原回收站中的文件)

    回收站中的文件可以改名吗(如何还原回收站中的文件)

  • 主板有问题会出现什么现象(主板有问题会出现什么)

    主板有问题会出现什么现象(主板有问题会出现什么)

  • vivitek是什么牌子的投影仪(vicomtea属于什么档次)

    vivitek是什么牌子的投影仪(vicomtea属于什么档次)

  • 10086说发什么恢复网速(10086回复ye)

    10086说发什么恢复网速(10086回复ye)

  • 局域网通常采用的传输方式是(局域网通常采用什么编码)

    局域网通常采用的传输方式是(局域网通常采用什么编码)

  • 拼多多投诉卖家以后卖家会受到什么惩罚(拼多多投诉卖家买家会怎样)

    拼多多投诉卖家以后卖家会受到什么惩罚(拼多多投诉卖家买家会怎样)

  • 王卡激活为什么显示没有查询到(王卡激活就要扣钱了吗)

    王卡激活为什么显示没有查询到(王卡激活就要扣钱了吗)

  • qq怎么设置充电中(扣扣手机充电中怎么设置)

    qq怎么设置充电中(扣扣手机充电中怎么设置)

  • 怎么开通花呗付款方式(怎么开通花呗付款二维码功能)

    怎么开通花呗付款方式(怎么开通花呗付款二维码功能)

  • 华为nova4屏幕材料(华为nova4屏幕什么材质)

    华为nova4屏幕材料(华为nova4屏幕什么材质)

  • ios13设备管理在哪里(ios13设备管理在哪找)

    ios13设备管理在哪里(ios13设备管理在哪找)

  • 淘宝津贴怎么算的(淘宝津贴怎么算出来的)

    淘宝津贴怎么算的(淘宝津贴怎么算出来的)

  • 电脑显示器能用机顶盒吗(电脑显示器能用电视代替吗)

    电脑显示器能用机顶盒吗(电脑显示器能用电视代替吗)

  • 苹果11自带无线耳机吗(苹果自带无线充电动画)

    苹果11自带无线耳机吗(苹果自带无线充电动画)

  • 神州联保怎么加入的(神州联保收费标准怎么样)

    神州联保怎么加入的(神州联保收费标准怎么样)

  • vivox27定时开关机在哪里(vivo手机定时开关机在哪里设置)

    vivox27定时开关机在哪里(vivo手机定时开关机在哪里设置)

  • 天猫劵怎么领(天猫劵怎么领取使用)

    天猫劵怎么领(天猫劵怎么领取使用)

  • cat命令  在终端设备上显示文件内容(终止cat命令)

    cat命令 在终端设备上显示文件内容(终止cat命令)

  • 减免所得税如何申报
  • 税收分类方法表格
  • 金蝶软件可以实现一键报税吗
  • 小规模纳税人所得税怎么征收
  • 盈利能力也可以反映短期偿债能力
  • 取得交易性金融资产投资收益为什么在借方
  • 金蝶财务系统录入发票
  • 劳务费发票是个人开还是公司开
  • 通行费发票怎么合并一张发票
  • 所得税申报更正申报怎么报?
  • 个人所得税专项扣除子女教育标准
  • 定额发票遗失情况说明怎么写
  • 公益机构可以收费吗
  • 厂房面积测绘收费标准
  • 支付技术转让费能加计扣除
  • 材料核销发票未开具
  • 未报税会怎么样
  • 营改增后租金如何交税
  • 销项税额转出税额怎么做账?
  • 管家婆怎样查历史记录
  • 免征的教育费附加如何账务处理
  • 固定资产合并抵扣增值税
  • 代扣职工社保
  • 失控发票进项税转出申报怎么填
  • 应发工资包含罚款吗
  • 商品进价销售要上税吗
  • 实收资本不到位后果
  • 施工预想内容
  • 非限定性净资产相当于哪个科目
  • 程序员编程代码大全
  • Mail.app增强插件:Universal Mailer介绍
  • 公司入股的钱叫什么
  • 消耗性生物资产减值准备一经计提不得转回
  • 上市公司股东股份轮候冻结是什么意思
  • 医院个人缴费什么意思
  • centos下file_put_contents()无法写入文件的原因及解决方法
  • 年报中投资总额怎么填
  • 小公司不交社保违法吗
  • 应收账款属于会计要素中的什么科目
  • node js 安装
  • 学生个人网站制作html代码
  • 增值税纳税申报表在哪里查询
  • 出口退税退运费的税吗
  • 销售边角料的会计分录
  • 微信收款怎么记录怎么删除
  • 差旅费包干是什么意思
  • 增值税发票名称可以写个人吗
  • 租车发票可以抵扣吗
  • 歌咏比赛服装费用规定标准最新
  • 股权转让 开票
  • 以前年度损益调整属于哪类科目
  • 销售返利冲抵货款怎么做账
  • 公司返聘退休人员的员工比例有没有规定
  • 收到股东投入材料怎么做账
  • 代收开票收入怎么做账
  • 预付账款为什么不是金融资产
  • 购买设备的运费增值税计入成本吗
  • 收付实现制下主营业务成本怎么算
  • 银行存款实际余额不足
  • 留抵的进项税可以用多少年
  • MySQL利用命令行工具启动和关闭的命令是什么
  • 苹果Mac系统怎么用光盘安装
  • win8网络连接受限怎么处理
  • linux源码安装软件的方法介绍
  • 关于我和鬼变成家人的那件事
  • android环境搭建教程
  • javascript闭包函数
  • Vue-Access-Control 前端用户权限控制解决方案
  • threejs入门教程
  • android 按键
  • node.js web开发
  • jquery获取自定义标签的值
  • eclipse出现an error has occurred
  • 轮廓模式
  • jquery遍历json对象
  • centos python2.7升级到3.7
  • 河北税务总局发票怎么开
  • 税务核查主要核算内容
  • 上海税务机关代码查询
  • 供电企业向电厂收取的并网服务费
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设