Node.js中SerialPort(串口)模塊使用
目的
上位機(jī)與各種電路模塊間常常采用串口進(jìn)行通訊,Node.js中可以使用SerialPort模塊操作串口,這篇文章將對其使用進(jìn)行簡單說明。
官網(wǎng):https://serialport.io/
文檔:https://serialport.io/docs/
項(xiàng)目地址:https://github.com/serialport/node-serialport
目前SerialPort模塊版本為 9.2.7
模塊安裝
使用下面命令就可以安裝SerialPort模塊:
npm install serialport
SerialPort模塊功能中有部分是用C/C++實(shí)現(xiàn)的,所以不同的平臺(tái)需要該平臺(tái)可用的二進(jìn)制文件才能運(yùn)行,對于常見的平臺(tái)通常會(huì)有預(yù)編譯好的二進(jìn)制文件。如果沒有的話通常會(huì)嘗試使用 node-gyp (依賴Python 3.x)進(jìn)行編譯,通常包管理器會(huì)自動(dòng)處理相關(guān)事務(wù):

有時(shí)候或是有些平臺(tái)下可能需要手動(dòng)編譯。對于編譯而言需要平臺(tái)上有相應(yīng)的編譯工具,可以參考 《Node.js入門 02:包管理器npm》 這個(gè)文章中的模塊編譯章節(jié)。
安裝了編譯工具后可以重新安裝SerialPort模塊或者手動(dòng)進(jìn)行編譯處理,具體內(nèi)容可以參考SerialPort模塊文檔中 Installing SerialPort 章節(jié):https://serialport.io/docs/guide-installation/
基礎(chǔ)使用
安裝SerialPort模塊后可以使用 const SerialPort = require('serialport') 方式導(dǎo)入。
掃描端口
使用 SerialPort.list(): Promise<PortInfo[]> 靜態(tài)方法可以獲取設(shè)備上的串口列表,比如下面演示:
const SerialPort = require('serialport');
SerialPort.list().then((ports) => {
console.log(ports); // 打印串口列表
}).catch((err) => {
console.log(err);
});

需要注意的是同一個(gè)端口在這個(gè)列表中有可能會(huì)重復(fù)出現(xiàn)。
也可以使用 async / await 方式使用上面方法:
const SerialPort = require('serialport');
(async () => {
try {
let ports = await SerialPort.list();
console.log(ports); // 打印串口列表
} catch (error) {
console.log(error);
}
})();

打開端口
默認(rèn)情況下創(chuàng)建 SerialPort 對象就會(huì)打開端口,比如下面這樣:
const SerialPort = require('serialport');
const port = new SerialPort('COM6', (err) => {
if (err) {
console.log('端口打開失?。?);
return;
}
console.log('端口打開成功!');
});
SerialPort類的構(gòu)造方法中有一個(gè) autoOpen 選項(xiàng)用于控制創(chuàng)建對象是是否自動(dòng)打開端口,默認(rèn)為自動(dòng)打開,也可以將它關(guān)閉,這樣可以后面手動(dòng)進(jìn)行打開端口動(dòng)作:
const SerialPort = require('serialport');
const port = new SerialPort('COM6', { autoOpen: false });
port.open(function (err) {
if (err) {
console.log('端口打開失?。?);
return;
}
console.log('端口打開成功!');
});
SerialPort類的構(gòu)造方法中可以使用 baudRate 選項(xiàng)設(shè)置串口通訊波特率,默認(rèn)為9600:
const SerialPort = require('serialport');
const port = new SerialPort('COM6', { baudRate: 115200 }); // 設(shè)置波特率為115200
更多內(nèi)容可以參考下面章節(jié)SerialPort類的構(gòu)造方法說明。
發(fā)送數(shù)據(jù)
可以使用SerialPort對象的 write 方法發(fā)送數(shù)據(jù),該方法會(huì)將要發(fā)送的數(shù)據(jù)放入發(fā)送緩存,然后依次發(fā)送,比如下面這樣:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.write('Hello world!\n'); // 發(fā)送字符串
port.write(Buffer.from('Hey!\n')); // 發(fā)送Buffer數(shù)據(jù)
port.write(new Uint8Array([0x48, 0x69, 0x21, 0x0A])); // 發(fā)送字節(jié)數(shù)組

write 方法也可以添加回調(diào)函數(shù):
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.write('Hello world!\n', (err) => {
if (err) {
console.log('write操作失??!');
return;
}
console.log('write操作成功!');
});
需要注意的是上面的回調(diào)函數(shù)非異常狀態(tài)下觸發(fā)的時(shí)候只是表示 write 方法本身操作完成,并不代表數(shù)據(jù)完全從端口發(fā)送完成,可以使用 drain 方法來處理,該方法會(huì)阻塞直到發(fā)送完成:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.write('Hello world!\n');
port.drain(err => {
if (err) return;
console.log('發(fā)送完成!');
});
接收數(shù)據(jù)
可以使用下面方式接收數(shù)據(jù):
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
// 以 paused mode 監(jiān)聽收到的數(shù)據(jù),需要主動(dòng)讀取數(shù)據(jù)
port.on('readable', () => {
console.log(port.read()); // 使用read方法讀取數(shù)據(jù),可以指定讀取字節(jié)數(shù)
});
// 以 flowing mode 監(jiān)聽收到的數(shù)據(jù)
port.on('data', (data) => {
console.log(data);
});

除了上面方式外,也可以使用 pipe 將數(shù)據(jù)傳送到另一個(gè)流。
錯(cuò)誤處理
SerialPort對象大多數(shù)操作都有回調(diào)函數(shù),回調(diào)函數(shù)中的第一個(gè)參數(shù)都是異常對象。另外也可以通過 error 事件來統(tǒng)一處理異常:
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
port.on('error', err => {
console.log(err);
});
數(shù)據(jù)解析器
SerialPort模塊中準(zhǔn)備了一些數(shù)據(jù)解析器,主要用來處理收到的一些一些常見形式的串口數(shù)據(jù),主要提供的功能如下:
ByteLength Parser
以收到的數(shù)據(jù)長度為單位進(jìn)行解析:
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個(gè)字節(jié)觸發(fā)
parser.on('data', chunk => {
console.log(chunk); // 打印收到的數(shù)據(jù)
});

ccTalk Parser
解析 ccTalk 格式數(shù)據(jù),格式詳見:https://en.wikipedia.org/wiki/CcTalk
Delimiter Parser
以指定字符為界限處理數(shù)據(jù):
const SerialPort = require('serialport');
const port = new SerialPort('COM6');
const Delimiter = require('@serialport/parser-delimiter');
const parser = port.pipe(new Delimiter({ delimiter: '\n' })); // 以 \n 分隔處理數(shù)據(jù)
parser.on('data', chunk => {
console.log(chunk.toString()); // 打印收到的數(shù)據(jù)
});

delimiter選項(xiàng)可以是 string|Buffer|number[] ;includeDelimiter選項(xiàng)表示數(shù)據(jù)中是否包含分隔符,默認(rèn)不包含。
InterByteTimeout Parser
指定時(shí)間未收到數(shù)據(jù)觸發(fā)解析:
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毫秒未接到數(shù)據(jù)觸發(fā)
parser.on('data', chunk => {
console.log(chunk); // 打印收到的數(shù)據(jù)
});

maxBufferSize選項(xiàng)用于指定接收到該數(shù)量數(shù)據(jù)后就算沒有超時(shí)也將觸發(fā)動(dòng)作。
Readline Parser
以行為單位解析數(shù)據(jù),默認(rèn)行分隔符為 \n,可以使用 delimiter 選項(xiàng)重新設(shè)置為其它的,比如 \r\n 。
Ready Parser
以開始標(biāo)志進(jìn)行解析。
Regex Parser
以正則表達(dá)式為分隔進(jìn)行解析。
SerialPort類
使用SerialPort模塊主要就是使用SerialPort類,其介紹在SerialPort模塊文檔中 Stream Interface 章節(jié):https://serialport.io/docs/api-stream,這里稍微摘錄下其中部分內(nèi)容。
構(gòu)造方法
new SerialPort(path [, openOptions] [, openCallback])
構(gòu)造方法用于創(chuàng)建一個(gè)串口對象,path為串口號(hào),openCallback為自動(dòng)打開失敗時(shí)的回調(diào)函數(shù);
openOptions常用選項(xiàng)如下:
| 選項(xiàng) | 類型 | 說明 | 默認(rèn)值 |
|---|---|---|---|
| autoOpen | boolean | 自動(dòng)打開端口 | true |
| baudRate | number | 波特率 | 9600 |
| dataBits | number | 數(shù)據(jù)位,可選值:8、7、6、5 | 8 |
| highWaterMark | number | 讀和寫緩存大小 | 65536 |
| lock | boolean | 鎖定端口,防止其它平臺(tái)打開(Windows上不支持false) | true |
| stopBits | number | 停止位,可選值:1、2 | 1 |
| parity | string | 校驗(yàn),可選值:none、even、mark、odd、space | none |
| rtscts | boolean | 流控制設(shè)置 | false |
| xon | boolean | 流控制設(shè)置 | false |
| xoff | boolean | 流控制設(shè)置 | false |
| xany | boolean | 流控制設(shè)置 | false |
屬性
SerialPort有下面幾個(gè)屬性可讀:
path 、 baudRate 、 isOpen 、 binding
事件
SerialPort會(huì)觸發(fā)的事件有下面幾個(gè):
open端口打開時(shí)觸發(fā);error發(fā)送錯(cuò)誤時(shí)觸發(fā);close端口關(guān)閉時(shí)觸發(fā);data收到數(shù)據(jù)時(shí)觸發(fā);drain如果write方法返回false,則再次調(diào)用write方法時(shí)將觸發(fā)該事件;
方法
SerialPort可用的一些方法如下:
open(() => {}): void打開端口;update(options: updateOptions, callback?: err => {}): void更改波特率;write(data: string|Buffer|Array<number>, encoding?: string, callback?: error => {}): boolean發(fā)送數(shù)據(jù);read(size?: number): string|Buffer|null讀取數(shù)據(jù);close(callback?: error => {}): void關(guān)閉端口;set(options: setOptions, callback?: error => {}): void設(shè)置流控制;get(callback: (error, data: ModemStatus) => {}): void獲取已打開端口的流控制狀態(tài);flush(callback? error => {}):void清空接收和發(fā)送緩存中未處理數(shù)據(jù);drain(callback? error => {}):void等待數(shù)據(jù)發(fā)送完成;pause(): this暫停 flowing mode 觸發(fā)data事件,轉(zhuǎn)為 paused mode;resume(): this恢復(fù) data 事件,從 paused mode 轉(zhuǎn)為 flowing mode;
命令行工具
SerialPort模塊也提供了一些命令行工具,用于直接在命令行界面中使用。下面是官網(wǎng)首頁的使用演示:

更多內(nèi)容可以參考SerialPort模塊文檔中 Command Line Tools 章節(jié):https://serialport.io/docs/guide-cli
總結(jié)
Node.js的SerialPort模塊使用主要就是上面一些內(nèi)容了。
另外需要提一點(diǎn)的是SerialPort模塊并不是直接操作串口,而是調(diào)用了各個(gè)平臺(tái)上底層的接口來使用串口,如果有進(jìn)行相關(guān)內(nèi)容的開發(fā)或是有特殊需求的話可以參考SerialPort模塊文檔中Binding相關(guān)內(nèi)容。
到此這篇關(guān)于Node.js中SerialPort(串口)模塊使用的文章就介紹到這了,更多相關(guān)Node.js SerialPort內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Node配合WebSocket做多文件下載以及進(jìn)度回傳
這篇文章主要介紹了Node配合WebSocket做多文件下載以及進(jìn)度回傳功能,本文通過實(shí)例代碼效果截圖給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-11-11
如何使用nvm實(shí)現(xiàn)nodejs版本管理(版本刪除,版本切換及版本添加)
這篇文章主要給大家介紹了關(guān)于如何使用nvm實(shí)現(xiàn)nodejs版本管理(版本刪除,版本切換及版本添加)的相關(guān)資料,nvm是一個(gè)node版本管理工具,通過它可以安裝多種node版本并且可以快速、簡單的切換node版本,需要的朋友可以參考下2023-10-10
Windows系統(tǒng)下Node.js的簡單入門教程
這篇文章主要介紹了Windows系統(tǒng)下Node.js的簡單入門教程,Node.js是用于后端編程的JavaScript框架,需要的朋友可以參考下2015-06-06
安裝Node.js并啟動(dòng)本地服務(wù)的操作教程
今天小編就為大家分享一篇安裝Node.js并啟動(dòng)本地服務(wù)的操作教程,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05
一文詳解Node.js服務(wù)器動(dòng)態(tài)資源處理
動(dòng)態(tài)資源處理也就是對數(shù)據(jù)進(jìn)行重新排序來讀寫數(shù)據(jù)庫,讀取反序列化,寫入序列化,這篇文章主要來和大家聊聊Node.js中的服務(wù)器動(dòng)態(tài)資源處理,感興趣的可以了解下2024-04-04
Express URL跳轉(zhuǎn)(重定向)的實(shí)現(xiàn)方法
Express是一個(gè)基于Node.js實(shí)現(xiàn)的Web框架,其響應(yīng)HTTP請求的response對象中有兩個(gè)用于URL跳轉(zhuǎn)方法res.location()和res.redirect(),使用它們可以實(shí)現(xiàn)URL的301或302重定向。2017-04-04
詳解Node中導(dǎo)入模塊require和import的區(qū)別
本篇文章主要介紹了詳解Node中導(dǎo)入模塊require和import的區(qū)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-08-08
Nodejs中讀取中文文件編碼問題、發(fā)送郵件和定時(shí)任務(wù)實(shí)例
這篇文章主要介紹了Nodejs中讀取中文文件編碼問題、發(fā)送郵件和定時(shí)任務(wù)實(shí)例,本文使用了3個(gè)模塊來解決這3個(gè)需求,并給出了代碼操作實(shí)例,需要的朋友可以參考下2015-01-01

