Vue中使用Web Serial API连接串口,实现通信交互

Vue中使用Web Serial API连接串口,实现通信交互

一、背景与问题

在物联网开发和嵌入式系统调试中,串口通信是常见需求。传统开发模式需要通过USB转串口线连接设备,再通过串口调试工具(如Arduino IDE)进行数据交互。这种模式存在以下痛点:

  1. 需要切换多个工具进行数据查看和发送
  2. 前端开发人员难以直接调试串口设备
  3. 无法实现实时数据可视化和交互

Web Serial API作为W3C标准,允许网页直接访问USB串口设备,为前后端开发提供了新的可能性。本文将深入解析其技术原理,结合Vue框架实现完整的串口通信系统。

二、基本原理

Web Serial API通过浏览器将USB设备识别为串口设备,其核心机制包含三个步骤:

  1. 设备发现:浏览器通过navigator.serial.requestPort()获取可用串口设备列表
  2. 通信建立:通过SerialPort对象建立通信通道,设置波特率、数据位等参数
  3. 数据传输:通过readable和writable流进行双向通信

关键特性:

  • 基于流式传输的异步通信
  • 支持自定义波特率配置(推荐9600-115200)
  • 与标准WebSocket API兼容
  • 支持二进制数据传输

三、环境准备

开发环境要求:

  • 浏览器支持:Chrome 88+(需启用chrome://flags/#enable-serial-api)
  • 串口设备:Arduino Uno/ESP32等USB转串口设备
  • 开发框架:Vue 3 + Vite

设备连接建议:

  1. 将串口设备的TX/RX引脚与电脑USB口连接
  2. 使用USB转串口线(如FT232RL模块)
  3. 确认设备驱动已安装(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驱动
  • 波特率不匹配:发送端和接收端波特率配置不一致

十、最佳实践

  1. 设备连接:使用requestPort()时明确指定波特率
  2. 数据处理:采用流式处理避免内存溢出
  3. 错误重连:实现自动重连机制提高系统健壮性
  4. 安全防护:对敏感数据进行加密处理
  5. 性能优化:使用Web Workers处理大量数据
  6. 文档记录:详细记录设备参数配置

十一、总结

Web Serial API为前端开发提供了直接访问串口设备的能力,为物联网应用开发带来了新的可能性。在Vue项目中实现串口通信需要:

  1. 理解浏览器与设备的通信机制
  2. 掌握流式处理的编程模式
  3. 处理各种异常和兼容性问题
  4. 实现健壮的错误处理和重连机制

该技术适用于需要实时数据采集、设备调试等场景,但不建议用于高实时性要求或复杂协议传输。通过合理的设计和优化,可以构建稳定可靠的串口通信系统,为物联网应用提供强有力的支持。

VUE
最后修改于:2026年09月15日 20:14

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日