上位机与各种电路模块间常常采用串口进行通讯,Node.js中可以使用SerialPort模块操作串口,这篇文章将对其使用进行简单说明。
官网:
https://serialport.io/
文档:
https://serialport.io/docs/9.x.x/guide-usage
项目地址:
https://github.com/serialport/node-serialport
目前已推出10.x.x版本,接口有变动,可以参考下面:
Node.js笔记:SerialPort(串口)模块使用(基于10.x.x)
使用下面命令就可以安装SerialPort模块:
npm install serialport
或者可以使用下面方式安装9.x.x版本中最新的包:
npm install serialport@9
SerialPort模块功能中有部分是用C/C++实现的,所以不同的平台需要该平台可用的二进制文件才能运行,对于常见的平台通常会有预编译好的二进制文件。如果没有的话通常会尝试使用 node-gyp (依赖Python)进行编译,通常包管理器会自动处理相关事务:
有时候或是有些平台下可能需要手动编译。对于编译而言需要平台上有相应的编译工具,可以参考
《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 });
更多内容可以参考下面章节SerialPort类的构造方法说明。
可以使用SerialPort对象的 write 方法发送数据,该方法会将要发送的数据放入发送缓存,然后依次发送,比如下面这样:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.write('Hello world!\n');
port.write(Buffer.from('Hey!\n'));
port.write(new Uint8Array([0x48, 0x69, 0x21, 0x0A]));
需要注意的是打开端口的动作是异步的,所以上面代码的write执行的时候端口可能还没打开,write会先将数据写入到缓存中,等到端口打开时再发送。

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');
port.on('readable', () => {
console.log(port.read());
});
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 }));
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' }));
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}));
parser.on('data', chunk => {
console.log(chunk);
});

maxBufferSize选项用于指定接收到该数量数据后就算没有超时也将触发动作。
Readline Parser
以行为单位解析数据,默认行分隔符为 \n,可以使用 delimiter 选项重新设置为其它的,比如 \r\n 。
Ready Parser
以开始标志进行解析。
Regex Parser
以正则表达式为分隔进行解析。
使用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相关内容。
electron+node+node-serialport 实现串口通信+electron-builder打包完整流程
最近有个项目需要连接电子秤到收银系统,然后需要调用硬件串口,因为收银系统,本来是用vue写好的网页,后面突然加了个需求,所以笔者思考了一下实现思路
用node js 操作串口 (serialport )
用electron,建立webSocet 和网页建立通信(用的ws模块)
node-serialport 是一个 Node.js 的包,用来对串口数据进行读写操作。基本示例代码:var SerialPort = require("serialport").SerialPort
var serialPort = new SerialPort("/dev/tty-usbserial1", {
baudrate: 57600
}, false); // this is the openImmediately flag [default is true]
serialPort.open(function (error) {
if ( error ) {
console.log('failed to open: ' error);
} else {
console.log('open');
serialPort.on('data', function(data) {
console.log('data received: ' data);
serialPort.write("ls\n", function(err, results) {
console.log('err ' err);
console.log('results ' results);
});罗列所有串口:var serialPort = require("serialport");
serialPort.list(function (err, ports) {
ports.forEach(function(port) {
console.log(port.comName);
console.log(port.pnpId);
console.log(port.manufacturer);
});串口配置:baudRatedataBitsstopBitsparityrtsctsxonxoffxanyflowControlbufferSizeparserencodingdataCallbackdisconnectedCallbackplatformOptions - sets platform specific options, see below.目前已有很多项目在使用这个包进行串口处理:Johnny-Five - Firmata based Arduino Framework.Cylon.js - JavaScript Robotics, By Your Command.node-l8smartlight (source) A node library to control the L8 Smartlight via Bluetooth or USB portfirmata Talk natively to Arduino using the firmata protocol.tmpad source - a DIY midi pad using infrared, arduino, and nodejs. Videoduino - A higher level framework for working with Arduinos in node.js.Arduino Drinking Game Extravaganza - AKA "The Russian" a hexidecimal drinking game for geeks by Uxebu presented at JSConf EU 2011.Arduino controlling popcorn.js - Controlling a popcorn.js video with an Arduino kit.Robotic JavaScript - The first live presentation of the node-serialport code set as presented at JSConf EU 2010.devicestack - This module helps you to represent a device and its protocol.reflecta A communication protocol that combines Arduino Libraries and NodeJS into an integrated system.rc4pt-node - Control Popcorntime with an
var SerialPort = require("serialport").SerialPort
var serialPort = new SerialPort("/dev/tty-usbserial1", {
baudrate: 57...
QT 调用 Windwos API 读取串口数据
本文只是写出最基本的步骤,可能有些变量没有列出1. 包含windows.h头文件#include 2. 打开串口 portnum = "\\\\.\\" + portnum; //Port避免超过10打不开
HANDLE hCom;hCom = CreateFile((LPCWSTR)portnum.data(),
版本号:Serialport@5.0.0-beta3本文链接想象一个世界,你可以在那写javascript来控制搅拌机,灯,安全系统或者甚至是机器人。是的,我说的是机器人。那个世界就是这儿,现在使用node serialport。它提供一个非常简单的接口所需要的串口程序代码Arduino 单片机, X10 无线通信模块, 或者甚至是上升到 Z-Wave 和Zigbee . 在这个物理世界,你可以...
var SerialPort = require('serialport');
var port = new SerialPort('COM5');
port.on('open', function() {
port.write('main screen turn on', function(err) {
if (err) ...
// 由于SerialPort是调用c/c++代码,所以要进行编译,先安装node-pre-gyp
sudo npm install node-pre-gyp --save
// 一定要使用这个命令,在serialport git上有说明
sudo npm install serialport --unsafe-perm --build-from-...
// 由于SerialPort是调用c/c++代码,所以要进行编译,先安装node-pre-gyp
sudo npm install node-pre-gyp --save
// 一定要使用这个命令,在serialport git上有说明
sudo npm install serialport --unsafe-perm --build-from-source --save
npm i npm to update
npm install -g serial
Serialport 简介
想象这样一个世界,在那里你能用 JavaScript 代码控制榨汁机,灯,安防系统,甚至机器人。嗯,是机器人!你会不会觉得很新奇以致兴奋?
Serialport 库(也称 Node-Serialport,基于 Node),为低级串口编码提供必要的 steam 接口,以控制 Arduino 芯片组,X10 接口,...
文章目录前言实现的功能
最近在项目中需要实现通过串口与外接电流表之间的通信,拿到电流表的实时测试电流同步显示在页面上,由于公司人员不多,这个重任自然而然落到我的头上,起初我也是不敢相信javascript有这么强大,还能通过串口操纵外接硬件设备,但我冷静之后百度了一下果然百度出来serialport.js这么个东西。
开发环境:electron-vue+node+serialport.js
先上效果图:
实现的功能
页面加载默获取所有串口列表遍历出需要打开的串口,将串口打开
点击开始测试,每一秒
2)编写index.js
const SerialPort = require('serialport');
var senddata = [0x02];//串口索要发送的数据源
var port = new SerialPort('COM3');//连接串口COM3
port.on('open', function () {//开启串口
writeport();
setInterval(function () {
以下方式可实现
利用IE 中 ActiveX、mscomm32.ocx控件进行串口通信,没记错的话在IE8之后ActiveX就不能用了。这里给三篇文章参考文章1、文章2、文章3
Nodejs服务端,可以使用SerialPort读写SerialPort说明 serialport官网
Chrome下,在chrome扩展程序和App中使用chrome.serial读写串口 中文官网