Node.js笔记:SerialPort(串口)模块使用(基于10.x.x)

目的

上位机与各种电路模块间常常采用串口进行通讯,Node.js中可以使用SerialPort模块操作串口,这篇文章将对其使用进行简单说明。

官网:https://serialport.io/
项目地址:https://github.com/serialport/node-serialport

目前SerialPort模块版本为 10.4.0

模块安装

使用下面命令就可以安装SerialPort模块:

# npm init -y # 初始化项目
npm install serialport
# npm install serialport@10 # 安装10.x.x版本中最新的包

SerialPort模块功能中有部分是用C/C++实现的,所以不同的平台需要该平台可用的二进制文件才能运行,对于常见的平台通常会有预编译好的二进制文件。如果没有的话通常会尝试使用 node-gyp (依赖Python)进行编译,通常包管理器会自动处理相关事务。

在Linux中使用root用户或是sudo方式安装的话需要带上额外参数,不然可能会报错:
sudo npm install serialport --unsafe-perm

快速使用

模块导入

安装完成后使用可以使用下面两种方式导入模块:

const {
    
     SerialPort } = require('serialport');
// import { SerialPort } from 'serialport'; // esm方式

扫描端口

使用SerialPort.list()可以得到设备上的串口列表。这是一个Promise对象,可以使用then方式或是使用async/await方式处理:

const {
    
     SerialPort } = require('serialport');

(async () => {
    
    
    try {
    
    
        let ports = await SerialPort.list();
        console.log(ports); // 打印串口列表
    } catch (error) {
    
    
        console.log(error);
    }
})();

在这里插入图片描述

扫描二维码关注公众号,回复: 14276709 查看本文章

需要注意的是同一个端口在这个列表中有可能会重复出现。

打开端口

可以使用下面方法创建并打开端口:

const {
    
     SerialPort } = require('serialport');

const serialport = new SerialPort({
    
     path: 'COM7', baudRate: 9600 });

打开端口这个动作可以添加回调函数:

const {
    
     SerialPort } = require('serialport');

const port = new SerialPort({
    
     path: 'COM7', baudRate: 9600 }, (err) => {
    
    
    if (err) {
    
    
        console.log('端口打开失败!');
        return;
    }
    console.log('端口打开成功!');
});

另外也可以在创建时不打开端口,在使用前用open方法打开:

const {
    
     SerialPort } = require('serialport');

const serialport = new SerialPort({
    
     path: 'COM7', baudRate: 9600, autoOpen: false });

serialport.open();

发送数据

打开端口后可以使用write方法发送数据:

const {
    
     SerialPort } = require('serialport');
const sp = new SerialPort({
    
     path: 'COM7', baudRate: 115200 });

sp.write('Hello world!\n'); // 发送字符串
sp.write(Buffer.from('Hey!\n')); // 发送Buffer数据
sp.write(new Uint8Array([0x48, 0x69, 0x21, 0x0A])); //发送字节数组

需要注意的是打开端口的动作是异步的,所以上面代码的write执行的时候端口可能还没打开,write会先将数据写入到缓存中,等到端口打开时再发送。
在这里插入图片描述

需要注意的是write方法返回true或是触发回调函数并不代表发送完成,需要结合drain方法才能判断发送完成:

const {
    
     SerialPort } = require('serialport');
const sp = new SerialPort({
    
     path: 'COM7', baudRate: 115200 });

port.write('Hello world!\n');
port.drain(err => {
    
    
    if (err) return;
    console.log('发送完成!');
});

接收数据

可以使用下面两种方式来接收数据:

const {
    
     SerialPort } = require('serialport');
const sp = new SerialPort({
    
     path: 'COM7', baudRate: 115200 });

// 以 paused mode 监听收到的数据,需要主动读取数据
sp.on('readable', () => {
    
    
    console.log(sp.read()); // 使用read方法读取数据,可以指定读取字节数
});

// 以 flowing mode 监听收到的数据
sp.on('data', (data) => {
    
    
    console.log(data);
});

在这里插入图片描述

错误处理

SerialPort对象大多数操作都有回调函数,回调函数中的第一个参数都是异常对象。另外也可以通过 error 事件来统一处理异常:

const {
    
     SerialPort } = require('serialport');
const sp = new SerialPort({
    
     path: 'COM7', baudRate: 115200 });

sp.on('error', err => {
    
    
    console.log(err);
});

SerialPort更多说明

构造方法

new SerialPortStream(openOptions, [openCallback])
构造方法用于创建一个串口对象,openOptions为参数,openCallback为打开端口失败时的回调函数;
openOptions常用选项如下:

选项 类型 说明 默认值
path string 端口号
baudRate number 波特率
dataBits number 数据位,可选值:5、6、7、8 8
lock boolean 锁定端口,防止其它平台打开(Windows上不支持false) true
stopBits number 停止位,可选值:1、1.5、2 1
parity string 校验,可选值:none、even、mark、odd、space none
rtscts boolean 流控制设置 false
xon boolean 流控制设置 false
xoff boolean 流控制设置 false
xany boolean 流控制设置 false
hupcl boolean 流控制设置(关闭串口时将DTR设置为低) true
autoOpen boolean 自动打开端口 true
highWaterMark number 读和写缓存大小 64k (65536?)
endOnClose boolean 当串口关闭时发送end事件 false

属性

SerialPort有下面几个属性可读:
pathbaudRateisOpenbinding

事件

SerialPort会触发的事件有下面几个:

  • open 端口打开时触发;
  • error 发生错误时触发;
  • close 端口关闭时触发;
  • data flowing mode下收到数据时触发;
  • drain 如果write方法返回false,则在恢复可以发送数据时将触发该事件;

方法

SerialPort可用的一些方法如下:

  • open(callback?: (err: Error | null) => {}): 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模块中准备了一些数据解析器,主要用来处理收到的一些常见形式的串口数据。

parser-byte-length
以收到的数据长度为单位进行解析:

const {
    
     SerialPort } = require('serialport');
const sp = new SerialPort({
    
     path: 'COM7', baudRate: 115200 });

const {
    
     ByteLengthParser } = require('@serialport/parser-byte-length');
const parser = sp.pipe(new ByteLengthParser({
    
     length: 8 })); // 每收到8个字节触发
parser.on('data', chunk => {
    
    
    console.log(chunk); // 打印收到的数据
});

在这里插入图片描述

parser-cctalk
解析 ccTalk 格式数据,格式详见:https://en.wikipedia.org/wiki/CcTalk

parser-delimiter
以指定字符为界线处理数据:

const {
    
     SerialPort } = require('serialport');
const sp = new SerialPort({
    
     path: 'COM7', baudRate: 115200 });

const {
    
     DelimiterParser } = require('@serialport/parser-delimiter');
const parser = sp.pipe(new DelimiterParser({
    
     delimiter: ';' })); // 以 ; 分隔处理数据
parser.on('data', chunk => {
    
    
    console.log(chunk.toString()); // 打印收到的数据
});

在这里插入图片描述

DelimiterParser可用参数有:

  • delimiter : string | Buffer | number[]
  • includeDelimiter : 表示数据中是否包含分隔符,默认为false(不包含)

parser-inter-byte-timeout
指定时间未收到数据触发解析:

const {
    
     SerialPort } = require('serialport');
const sp = new SerialPort({
    
     path: 'COM7', baudRate: 115200 });

const {
    
     InterByteTimeoutParser } = require('@serialport/parser-inter-byte-timeout');
const parser = sp.pipe(new InterByteTimeoutParser({
    
     interval: 2000, maxBufferSize: 4 }));
parser.on('data', chunk => {
    
    
    console.log(chunk); // 打印收到的数据
});

在这里插入图片描述

maxBufferSize选项用于指定接收到该数量数据后就算没有超时也将触发动作。

parser-packet-length
以分隔符数据长度等标识数据包进行解析。

parser-readline
以行为单位解析数据,默认行分隔符为 \n,可以使用 delimiter 选项重新设置为其它的,比如 \r\n

parser-ready
以标志字符串进行解析。触发时会触发一个以标志字符串为名称的事件。

parser-regex
以正则表达式为分隔进行解析。

parser-slip-encoder

parser-spacepacket

命令行工具

SerialPort模块也提供了一些命令行工具,用于直接在命令行界面中使用。下面是官网首页的使用演示:
在这里插入图片描述
更多内容可以参考SerialPort模块文档中 Command Line Packages 章节内容。

在Electron渲染进程中使用

SerialPort模块10.x.x版本最大的变化是可以直接在Electron的渲染进程中使用了:
在这里插入图片描述

总结

Node.js的SerialPort模块使用主要就是上面一些内容了。

另外需要提一点的是SerialPort模块并不是直接操作串口,而是调用了各个平台上底层的接口来使用串口,如果有进行相关内容的开发或是有特殊需求的话可以参考SerialPort模块文档中binding相关内容。

猜你喜欢

转载自blog.csdn.net/Naisu_kun/article/details/125146766