'# Vue中使用Web Serial API连接串口,实现通信交互
一、背景与问题
在物联网开发和嵌入式系统调试中,串口通信是常见需求。传统开发模式需要通过USB转串口线连接设备,再通过串口调试工具(如Arduino IDE)进行数据交互。这种模式存在以下痛点:
- 需要切换多个工具进行数据查看和发送
- 前端开发人员难以直接调试串口设备
- 无法实现实时数据可视化和交互
Web Serial API作为W3C标准,允许网页直接访问USB串口设备,为前后端开发提供了新的可能性。本文将深入解析其技术原理,结合Vue框架实现完整的串口通信系统。
二、基本原理
Web Serial API通过浏览器将USB设备识别为串口设备,其核心机制包含三个步骤:
- 设备发现:浏览器通过
navigator.serial.requestPort()获取可用串口设备列表 - 通信建立:通过
SerialPort对象建立通信通道,设置波特率、数据位等参数 - 数据传输:通过
readable和writable流进行双向通信
关键特性:
- 基于流式传输的异步通信
- 支持自定义波特率配置(推荐9600-115200)
- 与标准WebSocket API兼容
- 支持二进制数据传输
三、环境准备
开发环境要求:
- 浏览器支持:Chrome 88+(需启用
chrome://flags/#enable-serial-api) - 串口设备:Arduino Uno/ESP32等USB转串口设备
- 开发框架:Vue 3 + Vite
设备连接建议:
- 将串口设备的TX/RX引脚与电脑USB口连接
- 使用USB转串口线(如FT232RL模块)
- 确认设备驱动已安装(Windows需安装CH340驱动)
四、核心实现
1. 基础通信组件
<template>
<div class="serial-terminal">
<button @click="connect">连接串口</button>
<textarea v-model="inputData" @keyup.enter="sendData"></textarea>
<pre>{{ log }}</pre>
</div>
</template>
<script>
export default {
data() {
return {
serialPort: null,
reader: null,
writer: null,
log: '',
inputData: ''
}
},
methods: {
async connect() {
try {
// 1. 请求串口设备
const port = await navigator.serial.requestPort({
baudRate: 9600,
timeout: 1000
});
// 2. 打开串口连接
await port.open({ baudRate: 9600 });
// 3. 创建流读取器和写入器
this.reader = port.readable.getReader();
this.writer = port.writable.getWriter();
// 4. 启动数据读取循环
this.startReading();
this.log = '已连接串口设备';
} catch (err) {
this.log = `连接失败: ${err.message}`;
}
},
async startReading() {
try {
while (true) {
const { value, done } = await this.reader.read();
if (done) break;
// 5. 解析接收到的数据
const decoded = new TextDecoder().decode(value);
this.log += `收到数据: ${decoded}`;
// 6. 自动滚动显示
this.$nextTick(() => {
const pre = this.$el.querySelector('pre');
pre.scrollTop = pre.scrollHeight;
});
}
} catch (err) {
this.log = `读取失败: ${err.message}`;
} finally {
await this.reader.release();
this.reader = null;
}
},
async sendData() {
if (!this.writer) return;
try {
// 7. 发送数据
await this.writer.write(new TextEncoder().encode(this.inputData));
this.log += `发送数据: ${this.inputData}`;
this.inputData = '';
} catch (err) {
this.log = `发送失败: ${err.message}`;
}
}
}
}
</script>关键点解析:
- 使用
TextEncoder/Decoder处理字符串与字节的转换 - 通过
getReader()获取流式读取器 - 设置
timeout参数防止死锁 - 使用
$nextTick实现自动滚动显示
2. 数据解析与转换
// 解析接收到的十六进制数据
function parseHexData(hexString) {
const bytes = [];
for (let i = 0; i < hexString.length; i += 2) {
const hex = hexString.substring(i, i + 2);
bytes.push(parseInt(hex, 16));
}
return bytes;
}
// 将字节数组转换为十六进制字符串
function bytesToHex(bytes) {
return bytes.map(b => b.toString(16).padStart(2, '0')).join(' ');
}3. 错误处理与重连机制
// 重连函数
async function reconnect() {
try {
await navigator.serial.requestPort({ baudRate: 9600 });
await port.open({ baudRate: 9600 });
this.reader = port.readable.getReader();
this.writer = port.writable.getWriter();
this.startReading();
} catch (err) {
console.error('重连失败:', err);
this.log = '连接中断,请尝试重新连接';
}
}五、完整案例:Arduino温度传感器监控系统
1. 硬件连接
- Arduino Uno连接DHT11温湿度传感器
- TX引脚连接到电脑USB口(需使用USB转串口线)
- 电源连接5V/3.3V电源
2. Arduino代码
#include <DHT.h>
#define DHTPIN 4
DHT dht(DHTPIN, DHT11);
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println("传感器错误");
} else {
String data = String(t, 1) + "," + String(h) + "\n";
Serial.write(data.c_str(), data.length());
delay(1000);
}
}3. Vue前端实现
<template>
<div class="temperature-monitor">
<h2>温度监控系统</h2>
<div class="data-display">
<p>温度: <span>{{ temperature }}℃</span></p>
<p>湿度: <span>{{ humidity }}%</span></p>
</div>
<div class="log">
<pre>{{ log }}</pre>
</div>
</div>
</template>
<script>
export default {
data() {
return {
temperature: 0,
humidity: 0,
log: ''
}
},
methods: {
async parseData(data) {
const values = data.split(',');
this.temperature = parseFloat(values[0]);
this.humidity = parseFloat(values[1]);
}
}
}
</script>六、源码解析
1. 流式读取机制
async function startReading() {
try {
while (true) {
const { value, done } = await this.reader.read();
if (done) break;
const decoder = new TextDecoder();
const text = decoder.decode(value);
this.log += `收到数据: ${text}`;
// 解析并更新UI
this.parseData(text);
}
} catch (err) {
console.error('读取错误:', err);
this.log = '连接中断,请尝试重新连接';
}
}2. 数据解析逻辑
parseData(data) {
const [temp, humidity] = data.split(',').map(Number);
this.temperature = temp;
this.humidity = humidity;
}七、进阶使用
1. 数据可视化
<template>
<div class="graph">
<canvas ref="canvas" width="600" height="400"></canvas>
</div>
</template>
<script>
export default {
data() {
return {
chart: null,
dataPoints: []
}
},
mounted() {
this.initChart();
},
methods: {
initChart() {
const ctx = this.$refs.canvas.getContext('2d');
this.chart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: '温度',
data: [],
borderColor: 'red',
fill: false
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
});
},
updateChart(temp) {
this.dataPoints.push(temp);
this.chart.data.datasets[0].data.push(temp);
this.chart.options.scales.y.max = Math.max(
this.chart.options.scales.y.max,
temp
);
this.chart.update();
}
}
}
</script>2. 数据持久化
async function saveData(data) {
try {
const response = await fetch('/api/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data })
});
if (!response.ok) throw new Error('保存失败');
return await response.json();
} catch (err) {
console.error('数据保存失败:', err);
}
}八、性能与工程实践
1. 性能优化方案
| 优化策略 | 说明 |
|---|---|
| 使用二进制传输 | 减少文本编码/解码开销 |
| 批量发送数据 | 减少频繁的IO操作 |
| 使用Web Workers | 避免阻塞主线程 |
| 设置合理的缓冲区 | 防止数据丢失 |
2. 异常处理策略
- 连接中断:自动重连机制
- 数据异常:校验和校验
- 流量控制:设置最大缓冲区
3. 安全考虑
- 用户权限控制:限制串口访问权限
- 数据加密:使用TLS传输敏感数据
- 输入过滤:防止注入攻击
- 身份验证:设备指纹识别
九、常见问题与踩坑
1. 常见错误及解决办法
| 错误类型 | 现象 | 解决方案 |
|---|---|---|
| 设备未识别 | 无法获取设备列表 | 确认设备驱动安装 |
| 连接失败 | 端口未正确打开 | 检查波特率配置 |
| 数据丢失 | 读取数据不完整 | 增加缓冲区大小 |
| 内存泄漏 | 页面刷新后未关闭 | 在beforeUnmount钩子中释放资源 |
2. 常见问题分析
- 浏览器兼容性:部分浏览器尚未支持Web Serial API
- 数据格式混乱:未进行正确的编码/解码处理
- 设备驱动问题:未安装正确的USB驱动
- 波特率不匹配:发送端和接收端波特率配置不一致
十、最佳实践
- 设备连接:使用
requestPort()时明确指定波特率 - 数据处理:采用流式处理避免内存溢出
- 错误重连:实现自动重连机制提高系统健壮性
- 安全防护:对敏感数据进行加密处理
- 性能优化:使用Web Workers处理大量数据
- 文档记录:详细记录设备参数配置
十一、总结
Web Serial API为前端开发提供了直接访问串口设备的能力,为物联网应用开发带来了新的可能性。在Vue项目中实现串口通信需要:
- 理解浏览器与设备的通信机制
- 掌握流式处理的编程模式
- 处理各种异常和兼容性问题
- 实现健壮的错误处理和重连机制
该技术适用于需要实时数据采集、设备调试等场景,但不建议用于高实时性要求或复杂协议传输。通过合理的设计和优化,可以构建稳定可靠的串口通信系统,为物联网应用提供强有力的支持。