Node.js中SerialPort(串列埠)模組使用
目的
上位機與各種電路模組間常常採用串列埠進行通訊,Node.中可以使用SerialPort模組操作串列埠,這篇文章將對其使用進行簡單說明。
官網:https://serialport.io/
文件:https://serialport.io/docs/
專案地址:https://.com/serialport/node-serialport
目前SerialPort模組版本為 9.2.7
模組安裝
使用下面命令就可以安裝SerialPort模組:
npm install serialport
SerialPort模組功能中有部分是用C/C++實現的,所以不同的平臺需要該平臺可用的二進位制檔案才能執行,對於常見的平臺通常會有預編譯好的二進位制檔案。如果沒有的話通常會嘗試使用 node-gyp (依賴 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); // 列印串列埠列表
}).catchttp://www.cppcns.comh((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 }); // 設定波特率為1152vRVTb00
更多內容可以參考下面章節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(串列埠)模組使用的文章就介紹到這了,更多相關Node.js SerialPort內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!
