如何用WebUSB API与Arduino等微控制器通信?

WebUSB API使浏览器能直接与Arduino通信,用户需授权连接,通过指定vendorId请求设备,打开并配置CDC接口,利用transferOut和transferIn实现数据收发,简化了Web与物理设备交互流程。

如何用webusb api与arduino等微控制器通信?

WebUSB API提供了一种在浏览器中直接与Arduino等微控制器进行通信的强大方式,它让网页能够发现、连接并交换数据,无需安装额外驱动或桌面应用,极大地简化了设备交互的门槛,为Web应用打开了通往物理世界的大门。

解决方案

要让WebUSB与Arduino对话,这可不是点一下按钮那么简单,它涉及硬件固件和Web应用两端的协作,并且需要一套清晰的步骤。

首先,你的Arduino微控制器得准备好。大多数Arduino板子默认通过USB暴露一个CDC(Communication Device Class)串行接口。你只需要在Arduino草图中像往常一样使用

Serial.begin()

Serial.print()

Serial.read()

函数即可。如果用的是非标准板或自定义固件,确保它能正确地作为USB串行设备被识别。

接着,我们来看Web端的实现,这通常是一个异步操作序列:

请求设备:出于安全考量,浏览器不会让你随意连接任何USB设备。用户必须通过一个弹窗明确授权。你用

navigator.usb.requestDevice()

来发起这个请求,并提供

filters

来指定你想要连接的设备类型,比如通过

vendorId

(厂商ID)和

productId

(产品ID)。Arduino Uno的厂商ID通常是

0x2341

async function connectDevice() {    try {        const device = await navigator.usb.requestDevice({            filters: [{ vendorId: 0x2341 }] // 示例:Arduino的VID        });        console.log("已连接设备:", device.productName);        // 接下来就可以打开并配置设备了        return device;    } catch (error) {        console.error("连接失败:", error);    }}

打开并配置设备:拿到

device

对象后,你需要打开它,选择一个配置,然后声明(claim)它提供串行通信的接口。USB设备可能有多个配置和接口,你需要找到那个用于CDC(通常是串行通信)的接口。

async function setupArduinoConnection(device) {    await device.open(); // 打开设备    if (device.configuration === null) {        await device.selectConfiguration(1); // 选择一个配置,通常是1    }    // 寻找CDC数据接口,interfaceClass 0x0A 通常代表CDC数据    const cdcInterface = device.configuration.interfaces.find(i =>        i.alternates.some(alt => alt.interfaceClass === 0x0A)    );    if (!cdcInterface) {        throw new Error("未找到CDC接口。");    }    await device.claimInterface(cdcInterface.interfaceNumber); // 声明接口    // 找到输入和输出端点    const alternate = cdcInterface.alternates[0]; // 假设使用第一个备用设置    const endpointIn = alternate.endpoints.find(e => e.direction === 'in');    const endpointOut = alternate.endpoints.find(e => e.direction === 'out');    if (!endpointIn || !endpointOut) {        throw new Error("未找到输入或输出端点。");    }    console.log("设备接口已声明,端点已识别。");    return { device, endpointIn, endpointOut, interfaceNumber: cdcInterface.interfaceNumber };}

数据传输:现在可以进行数据读写了。发送数据用

device.transferOut()

,接收数据用

device.transferIn()

。记住,WebUSB处理的是

ArrayBuffer

DataView

格式的二进制数据,所以你需要进行字符串和二进制数据的转换。

写入数据:

async function writeToArduino(device, endpointOut, dataString) {    const encoder = new TextEncoder(); // 默认UTF-8编码    const dataBuffer = encoder.encode(dataString);    await device.transferOut(endpointOut.endpointNumber, dataBuffer);    console.log("数据已发送:", dataString);}

读取数据:读取通常需要一个循环来持续监听。

let isReading = false;async function readFromArduino(device, endpointIn, callback) {    isReading = true;    const decoder = new TextDecoder(); // 默认UTF-8解码    while (device.opened && isReading) {        try {            const result = await device.transferIn(endpointIn.endpointNumber, 64); // 读取最多64字节            if (result.data && result.data.byteLength > 0) {                const receivedData = decoder.decode(result.data);                callback(receivedData);            }        } catch (error) {            if (error.message.includes("The device was disconnected")) {                console.log("设备在读取时断开。");

以上就是如何用WebUSB API与Arduino等微控制器通信?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1521330.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 14:04:52
下一篇 2025年12月20日 14:05:10

相关推荐

  • 如何构建一个零依赖的现代化JavaScript路由器?

    答案:利用History API和URLPattern实现轻量级前端路由,支持动态与嵌套路由。通过监听popstate和拦截锚点点击实现无刷新导航,结合动态导入按需加载组件,并在切换前执行钩子逻辑。初始化时匹配当前路径并绑定全局监听,确保单页应用体验,整个系统零依赖且易于扩展。 构建一个零依赖的现代…

    好文分享 2025年12月20日
    000
  • 使用 Mongoose 在复合索引文档中按索引的部分内容进行搜索

    本文档介绍了在使用 Mongoose 和 MongoDB 时,如何在复合索引文档中,仅使用索引的部分内容进行查询。重点讲解了使用点符号进行查询,以及避免全文档匹配时可能遇到的问题,并提供了相应的代码示例和注意事项,帮助开发者更有效地进行数据检索。 问题背景 在使用 Mongoose 和 MongoD…

    2025年12月20日
    000
  • 深入理解HTML Canvas分辨率与高清晰度图像导出

    本文旨在阐明HTML Canvas元素的内在分辨率与页面显示尺寸之间的关键区别,并提供一套行之有效的方法,帮助开发者在Canvas上绘制高分辨率图像后,以期望的原始高分辨率进行导出,同时兼顾其在网页上的显示效果,避免因误解分辨率概念而导致图像失真或尺寸缩减。 在Web开发中,HTML Canvas元…

    2025年12月20日
    000
  • 优化jQuery AJAX请求:数据序列化与响应处理实践指南

    本文旨在解决jQuery AJAX success回调中功能调用不当及数据序列化常见问题。核心内容包括:使用serializeArray()替代serialize()以正确发送表单数据,尤其当预期服务器接收结构化数据时;强调验证服务器响应结构的重要性,避免因数据格式不匹配导致逻辑错误;并提供完整的代…

    2025年12月20日
    000
  • JSX中Props转发的展开运算符:语法与内部机制解析

    本文深入探讨了JSX中用于Props转发的展开运算符({…rest})的必要性及其内部机制。我们将解释为何直接使用{rest}是无效的,并明确JSX中大括号的正确使用场景。同时,文章将澄清关于展开运算符在JavaScript和JSX中如何处理属性分隔符的常见误区,揭示JSX如何通过Rea…

    2025年12月20日
    000
  • 深入解析Socket.io国际象棋对局中的将军检测与同步机制

    本文深入探讨了在基于Socket.io的在线国际象棋游戏中,如何准确实现将军(Check)状态的检测与客户端同步。核心问题在于初始的将军检测逻辑错误地检查了当前玩家的棋盘,而非对手的棋盘。通过调整checkControl变量的逻辑,我们成功修正了这一问题,确保将军事件能够正确触发并通知所有连接的客户…

    2025年12月20日
    000
  • 如何利用JavaScript的Speech Synthesis API实现语音合成?

    JavaScript的Speech Synthesis API通过window.speechSynthesis实现文本转语音,创建SpeechSynthesisUtterance实例并调用speak()方法即可输出语音,支持调整音量、语速、音调和语言,需注意语音列表异步加载及语言设置,结合pause…

    2025年12月20日
    000
  • 深入理解 JSX 中的展开运算符与属性传递

    本文深入探讨了 JSX 中展开运算符({…})在属性传递中的核心作用,解释了为何 {rest} 语法无效,以及 JSX 展开语法与 JavaScript 对象展开在行为上的区别。我们将通过代码示例揭示 JSX 编译为 React.createElement 的机制,从而理解属性如何最终以…

    2025年12月20日
    000
  • 如何用Vue 3的Composition API重构大型项目?

    重构大型Vue项目需逐步迁移至Composition API,先分析Options API中数据、逻辑分散问题,识别可复用逻辑;再通过setup函数整合data、method与computed,提升代码组织性;接着将分页、权限等公共逻辑抽离为composable函数,增强复用性;最后结合Pinia优…

    2025年12月20日
    000
  • 在JavaScript中,如何实现剪贴板的读写操作?

    JavaScript通过Clipboard API操作剪贴板,需用户触发且页面在安全上下文中运行;2. 使用navigator.clipboard.writeText()写入文本,readText()读取文本,均返回Promise并需处理权限与异常。 在JavaScript中操作剪贴板,主要通过现代…

    2025年12月20日
    000
  • JavaScript的生成器函数如何模拟异步操作?

    生成器函数通过yield暂停执行,结合Promise和迭代器可模拟异步操作。使用function*定义的生成器返回迭代器,调用next()逐次推进,yield传出Promise,执行器等待完成后再将结果传回,实现类似async/await的同步写法效果。该机制避免回调地狱、支持错误捕获,为async…

    2025年12月20日
    000
  • 使用 Vue Router 构建多页面 Chrome 扩展

    本文介绍了如何使用 Vue Router 构建一个多页面的 Chrome 浏览器扩展程序。通过 Vue Router,可以在单个 popup 页面中实现页面跳转和状态管理,从而实现登录验证等复杂功能。文章将指导你如何配置 Vue Router,并根据用户登录状态进行页面重定向,最终构建一个功能完善的…

    2025年12月20日
    000
  • JavaScript中的函数式编程概念(如Functor、Monad)如何理解?

    Functor是支持map方法的容器,能安全映射值并保持类型,如数组和Maybe;Monad是增强版Functor,提供chain方法以扁平化方式处理嵌套容器,适用于异步流程与错误处理,Promise即是Monad实例,通过组合函数提升代码可靠性。 函数式编程在JavaScript中越来越受到关注,…

    2025年12月20日
    000
  • React useState 与锚点(Anchor)失效问题排查与解决

    在使用 React 开发过程中,我们可能会遇到需要获取 DOM 元素并将其存储在 state 中的情况,以便后续操作,例如弹出层的位置定位。然而,直接将 DOM 元素存储到 state 中,特别是锚点元素,有时会导致 “Node cannot be found in the curren…

    2025年12月20日
    000
  • 如何实现一个前端日志记录与上报系统?

    前端日志系统需采集错误、行为、性能和自定义日志,通过全局监听与手动触发结合,结构化存储并批量上报,利用sendBeacon保障可靠性,避免重复与敏感信息泄露。 前端日志系统的核心目标是捕获用户在使用网页或应用过程中的行为、错误和性能数据,帮助开发团队快速定位问题并优化体验。要实现一个实用的前端日志记…

    2025年12月20日
    000
  • 深入理解jQuery AJAX成功回调中的数据处理与函数调用

    本文旨在解决jQuery AJAX成功回调中常见的函数调用障碍与数据处理不当问题。核心在于明确当dataType设置为JSON时,data参数应使用serializeArray()进行表单序列化,而非serialize()。同时,强调验证服务器实际返回的数据结构,以确保回调逻辑的正确执行,从而避免因…

    2025年12月20日
    000
  • JavaScript教程:高效检测带特定类名元素的焦点状态

    本文详细介绍了如何使用 document.activeElement 结合 classList.contains() 方法来判断具有特定 CSS 类名的 HTML 元素是否获得了焦点。通过监听元素的 focus 和 blur 事件,可以实时、准确地检测并响应用户界面中元素的焦点状态,解决直接比较元素…

    2025年12月20日
    000
  • JavaScript中高效重命名与转换大型对象属性的教程

    本教程详细阐述了如何在JavaScript中高效地对大型对象进行属性重命名和值类型转换。通过运用解构赋值(Destructuring Assignment)和扩展运算符(Spread Syntax),我们能够简洁、优雅地创建新对象,同时保留大部分原始属性,仅对指定字段进行修改和转换,从而优化代码可读…

    2025年12月20日
    000
  • 如何构建一个支持Tree-shaking的通用工具库?

    答案是构建支持Tree-shaking的工具库需使用ES模块语法、合理组织代码结构并配置打包工具。具体包括:采用export单独导出函数,避免默认或聚合导出;每个函数独立文件存放,入口文件仅重新导出;通过Rollup或Vite生成ESM格式产物;在package.json中设置module字段指向E…

    2025年12月20日
    000
  • JavaScript引擎如何进行垃圾回收以及如何避免内存泄漏?

    JavaScript引擎通过标记-清除算法自动回收内存,避免内存泄漏需注意全局变量、定时器、闭包和DOM引用的管理,利用开发者工具监控内存使用。 JavaScript引擎通过自动管理内存来减轻开发者负担,其中垃圾回收(Garbage Collection, GC)是核心机制。它的主要任务是识别不再使…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信