Node.js笔记:SerialPort(串口)模块使用
Posted Naisu Xu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js笔记:SerialPort(串口)模块使用相关的知识,希望对你有一定的参考价值。
目的
上位机与各种电路模块间常常采用串口进行通讯,Node.js中可以使用SerialPort模块操作串口,这篇文章将对其使用进行简单说明。
官网:https://serialport.io/
文档:https://serialport.io/docs/
项目地址:https://github.com/serialport/node-serialport
目前SerialPort模块版本为 9.2.7
模块安装
使用下面命令就可以安装SerialPort模块:
npm install serialport
SerialPort模块功能中有部分是用C/C++实现的,所以不同的平台需要该平台可用的二进制文件才能运行,对于常见的平台通常会有预编译好的二进制文件。如果没有的话通常会尝试使用 node-gyp (依赖Python 3.x)进行编译,通常包管理器会自动处理相关事务:
有时候或是有些平台下可能需要手动编译。对于编译而言需要平台上有相应的编译工具,可以参考 《Node.js入门 02:包管理器npm》 这个文章中的模块编译章节。
安装了编译工具后可以重新安装SerialPort模块或者手动进行编译处理,具体内容可以参考SerialPort模块文档中 Installing SerialPort 章节:https://serialport.io/docs/guide-installation/
基础使用
安装SerialPort模块后可以使用 const SerialPort = require('serialport')
方式导入。
扫描端口
使用 SerialPort.list(): Promise<PortInfo[]>
静态方法可以获取设备上的串口列表,比如下面演示:
const SerialPort = require('serialport');
SerialPort.list().then((ports) =>
console.log(ports); // 打印串口列表
).catch((err) =>
console.log(err);
);
需要注意的是同一个端口在这个列表中有可能会重复出现。
也可以使用 async / await 方式使用上面方法:
const SerialPort = require('serialport');
(async () =>
try
let ports = await SerialPort.list();
console.log(ports); // 打印串口列表
catch (error)
console.log(error);
)();
打开端口
默认情况下创建 SerialPort 对象就会打开端口,比如下面这样:
const SerialPort = require('serialport');
const port = new SerialPort('COM6', (err) =>
if (err)
console.log('端口打开失败!');
return;
console.log('端口打开成功!');
);
SerialPort类的构造方法中有一个 autoOpen 选项用于控制创建对象是是否自动打开端口,默认为自动打开,也可以将它关闭,这样可以后面手动进行打开端口动作:
const SerialPort = require('serialport');
const port = new SerialPort('COM6', autoOpen: false );
port.open(function (err)
if (err)
console.log('端口打开失败!');
return;
console.log('端口打开成功!');
);
SerialPort类的构造方法中可以使用 baudRate 选项设置串口通讯波特率,默认为9600:
const SerialPort = require('serialport');
const port = new SerialPort('COM6', baudRate: 115200 ); // 设置波特率为115200
更多内容可以参考下面章节SerialPort类的构造方法说明。
发送数据
可以使用SerialPort对象的 write
方法发送数据,该方法会将要发送的数据放入发送缓存,然后依次发送,比如下面这样:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.write('Hello world!\\n'); // 发送字符串
port.write(Buffer.from('Hey!\\n')); // 发送Buffer数据
port.write(new Uint8Array([0x48, 0x69, 0x21, 0x0A])); // 发送字节数组
write
方法也可以添加回调函数:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.write('Hello world!\\n', (err) =>
if (err)
console.log('write操作失败!');
return;
console.log('write操作成功!');
);
需要注意的是上面的回调函数非异常状态下触发的时候只是表示 write
方法本身操作完成,并不代表数据完全从端口发送完成,可以使用 drain
方法来处理,该方法会阻塞直到发送完成:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.write('Hello world!\\n');
port.drain(err =>
if (err) return;
console.log('发送完成!');
);
接收数据
可以使用下面方式接收数据:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
// 以 paused mode 监听收到的数据,需要主动读取数据
port.on('readable', () =>
console.log(port.read()); // 使用read方法读取数据,可以指定读取字节数
);
// 以 flowing mode 监听收到的数据
port.on('data', (data) =>
console.log(data);
);
除了上面方式外,也可以使用 pipe
将数据传送到另一个流。
错误处理
SerialPort对象大多数操作都有回调函数,回调函数中的第一个参数都是异常对象。另外也可以通过 error 事件来统一处理异常:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.on('error', err =>
console.log(err);
);
数据解析器
SerialPort模块中准备了一些数据解析器,主要用来处理收到的一些一些常见形式的串口数据,主要提供的功能如下:
ByteLength Parser
以收到的数据长度为单位进行解析:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
const ByteLength = require('@serialport/parser-byte-length');
const parser = port.pipe(new ByteLength( length: 8 )); // 每收到8个字节触发
parser.on('data', chunk =>
console.log(chunk); // 打印收到的数据
);
ccTalk Parser
解析 ccTalk 格式数据,格式详见:https://en.wikipedia.org/wiki/CcTalk
Delimiter Parser
以指定字符为界限处理数据:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
const Delimiter = require('@serialport/parser-delimiter');
const parser = port.pipe(new Delimiter( delimiter: '\\n' )); // 以 \\n 分隔处理数据
parser.on('data', chunk =>
console.log(chunk.toString()); // 打印收到的数据
);
delimiter选项可以是 string|Buffer|number[] ;includeDelimiter选项表示数据中是否包含分隔符,默认不包含。
InterByteTimeout Parser
指定时间未收到数据触发解析:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
const InterByteTimeout = require('@serialport/parser-inter-byte-timeout');
const parser = port.pipe(new InterByteTimeout(interval: 2000)); // 2000毫秒未接到数据触发
parser.on('data', chunk =>
console.log(chunk); // 打印收到的数据
);
maxBufferSize选项用于指定接收到该数量数据后就算没有超时也将触发动作。
Readline Parser
以行为单位解析数据,默认行分隔符为 \\n
,可以使用 delimiter 选项重新设置为其它的,比如 \\r\\n
。
Ready Parser
以开始标志进行解析。
Regex Parser
以正则表达式为分隔进行解析。
SerialPort类
使用SerialPort模块主要就是使用SerialPort类,其介绍在SerialPort模块文档中 Stream Interface 章节:https://serialport.io/docs/api-stream,这里稍微摘录下其中部分内容。
构造方法
new SerialPort(path [, openOptions] [, openCallback])
构造方法用于创建一个串口对象,path为串口号,openCallback为自动打开失败时的回调函数;
openOptions常用选项如下:
选项 | 类型 | 说明 | 默认值 |
---|---|---|---|
autoOpen | boolean | 自动打开端口 | true |
baudRate | number | 波特率 | 9600 |
dataBits | number | 数据位,可选值:8、7、6、5 | 8 |
highWaterMark | number | 读和写缓存大小 | 65536 |
lock | boolean | 锁定端口,防止其它平台打开(Windows上不支持false) | true |
stopBits | number | 停止位,可选值:1、2 | 1 |
parity | string | 校验,可选值:none、even、mark、odd、space | none |
rtscts | boolean | 流控制设置 | false |
xon | boolean | 流控制设置 | false |
xoff | boolean | 流控制设置 | false |
xany | boolean | 流控制设置 | false |
属性
SerialPort有下面几个属性可读:
path
、 baudRate
、 isOpen
、 binding
事件
SerialPort会触发的事件有下面几个:
open
端口打开时触发;error
发送错误时触发;close
端口关闭时触发;data
收到数据时触发;drain
如果write方法返回false,则再次调用write方法时将触发该事件;
方法
SerialPort可用的一些方法如下:
open(() => ): void
打开端口;update(options: updateOptions, callback?: err => ): void
更改波特率;write(data: string|Buffer|Array<number>, encoding?: string, callback?: error => ): boolean
发送数据;read(size?: number): string|Buffer|null
读取数据;close(callback?: error => ): void
关闭端口;set(options: setOptions, callback?: error => ): void
设置流控制;get(callback: (error, data: ModemStatus) => ): void
获取已打开端口的流控制状态;flush(callback? error => ):void
清空接收和发送缓存中未处理数据;drain(callback? error => ):void
等待数据发送完成;pause(): this
暂停 flowing mode 触发data事件,转为 paused mode;resume(): this
恢复 data 事件,从 paused mode 转为 flowing mode;
命令行工具
SerialPort模块也提供了一些命令行工具,用于直接在命令行界面中使用。下面是官网首页的使用演示:
更多内容可以参考SerialPort模块文档中 Command Line Tools 章节:https://serialport.io/docs/guide-cli
总结
Node.js的SerialPort模块使用主要就是上面一些内容了。
另外需要提一点的是SerialPort模块并不是直接操作串口,而是调用了各个平台上底层的接口来使用串口,如果有进行相关内容的开发或是有特殊需求的话可以参考SerialPort模块文档中Binding相关内容。
以上是关于Node.js笔记:SerialPort(串口)模块使用的主要内容,如果未能解决你的问题,请参考以下文章
Raspberry Pi,Arduino,Node.js和串口
在Node.js中使用serialport自动连接到特定设备