Web Serial API使用方法

简言之,利用Web Serial API可以在Web端纯JavaScript实现双向串口通信。当然可以用来做嵌入式开发课程设计

详细用法可参考官方文档。本文只介绍基础用法。

环境需求

需要Chromium内核版本89以上的桌面平台。

可以使用最新版的Chrome或Edge等。IE和Firefox不支持。国产浏览器请注意检查Chromium内核版本号,已知最新版的星愿浏览器、360极速浏览器X都是支持的。

可以用以下代码测试浏览器是否支持Web Serial API:

1
2
3
if ('serial' in navigator) {
    console.log('支持Web Serial API');
}

若控制台成功打印支持Web Serial API,说明浏览器支持Web Serial API。

关于Web Serial API的使用还有以下需要注意:

  • Web Serial API在设计上是异步的。
  • 若部署项目到线上,则必须使用https协议。本地环境则无此限制。
  • 通信必须绑定事件由用户主动触发,不允许自动开始通信。

确认这些信息后,可以进入后续步骤。

启动串口连接

首先需要请求串口权限。以下代码在按下按钮时弹出窗口让用户选择一个串口:

1
2
3
connectButton.addEventListener('click', async () => {
  const port = await navigator.serial.requestPort();
});

选择完成后即可打开串口连接:

1
await port.open({ baudRate: 9600 });

此方法还可以指定停止位、数据位、奇偶校验等参数,不在此赘述。

发送与接收数据

发送与接收数据可以使用以下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 发送数据data
const writer = port.writable.getWriter();
await writer.write(data);
await writer.close();

// 接收数据value并打印到控制台
const reader = port.readable.getReader();
while (true) {
    const { value, done } = await reader.read();
    if (done) {
        reader.releaseLock();
        break;
    }
    console.log(value);
}

上面的代码只能发送或接受Uint8数组。如果想发送或接收字符串,可以使用TextEncoder和TextDecoder,它们可以可以进行字符串到UTF-8编码的编解码。

1
2
3
4
5
6
7
8
9
// 将字符串编码为Uint8数组
const encoder = new TextEncoder();
const data = encoder.encode('Hello, world!');
console.log(data); // Uint8Array(13) [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]

// 将Uint8数组解码为字符串
const decoder = new TextDecoder();
const value = decoder.decode(data);
console.log(value); // 'Hello, world!'

为确保数据接收的次序,需要在代码中添加防抖。此外,一般需隔零点几秒就将接收到的数据打印出来一次。

最终的代码示例如下,注意此代码未做任何意外情况的处理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
let port; // 串口对象
let debounceTimeout; // 防抖延迟定时器
let delayTime = 500; // 延迟时间

connectButton.addEventListener('click', () => {
    // 清除之前的防抖延迟定时器
    clearTimeout(debounceTimeout);

    // 创建新的防抖延迟定时器
    debounceTimeout = setTimeout(async () => {
        // 连接串口
        port = await navigator.serial.requestPort();
        await port.open({ baudRate: 9600 });
        console.log('Serial port connected');

        // 监听串口数据
        const reader = port.readable.getReader();
        const decoder = new TextDecoder();

        let receivedData = []; // 用于存储接收到的数据

        while (true) {
            const { value, done } = await reader.read();
            if (done) {
                reader.releaseLock();
                break;
            }

            receivedData = receivedData.concat(Array.from(value)); // 将接收到的字节添加到数组中

            // 打印一次接收到的数据
            setTimeout(() => {
                const text = decoder.decode(new Uint8Array(receivedData));
                console.log(text);
                receivedData = []; // 清空接收到的数据
            }, delayTime);
        }
    }, delayTime);
});

// 发送数据
sendButton.addEventListener('click', async () => {
    const writer = port.writable.getWriter();
    const encoder = new TextEncoder();
    const data = encoder.encode('Hello, world!');
    await writer.write(data);
    await writer.close();
});

进阶应用

更复杂的应用请参考官方文档

博主基于Web Serial API实现了编写了一个简单的Web串口调试工具。如果要配置更多参数、使用UTF-8以外的其他编码、进行意外处理等,其中的代码也可供参考。