Node.js | 如何通过串口向设备发送和接收一个字节?

Joe*_*Joe 5 javascript embedded serial-port node.js

我正在尝试编写 Node.js 脚本,该脚本使用serialportnpm 包来读取数据并将数据写入COM5串行端口,该串行端口使用 RS-232 电缆连接到设备。该设备会自动传输其拥有的数据。

要检索设备内部存储的数据,我需要首先uInt8向设备发送一个字节 0x80 ( ),并期望从设备接收 81 作为十六进制数字。其次,我需要发送另一个字节 0x81 ( uInt8),然后期望以行形式接收所有存储的数据(大约 130000 字节)。

无法仅通过两个字节一个接一个地检索整个存储的数据。与设备的通信只能通过字节来完成。

我尝试了以下代码:

import SerialPort from 'serialport';

const sp = new SerialPort.SerialPort({path: "COM5", baudRate: 115200});

const buff = Buffer.allocUnsafe(1);
buff.writeUInt8(0x80, 0);

sp.write(buff, function (err){
    if (err){
        return console.log("Error on write: ", err.message);
    }
    console.log("Port.write: ", buff);
});

sp.on('readable', function () {
    var arr = new Uint8Array(sp._pool);
    console.log('Data:', arr);
});
Run Code Online (Sandbox Code Playgroud)

运行我的脚本(使用node myScript.mjs)时,我看到以下内容:

PortWrite:  <Buffer 80>
Data: Uint8Array(65536) [
    0,  30, 167, 106, 127,   2,  0,  0,  32,  31, 170, 106,
  127,   2,   0,   0,   0, 128,  0,  0,   0,   0,   0,   0,
   16,  84,  18,  76, 196,   0,  0,  0, 100,  84,  18,  76,
  196,   0,   0,   0, 184,  84, 18, 76, 196,   0,   0,   0,
  160,  84,  18,  76, 196,   0,  0,  0, 244,  84,  18,  76,
  196,   0,   0,   0,  72,  85, 18, 76, 196,   0,   0,   0,
  240, 120,  18,  76, 196,   0,  0,  0,  68, 121,  18,  76,
  196,   0,   0,   0, 152, 121, 18, 76, 196,   0,   0,   0,
  240, 120,  18,  76,
  ... 65436 more items
]
Run Code Online (Sandbox Code Playgroud)

直到我点击 ,程序才会退出Ctrl+c。我不确定ps._pool是什么,但输出似乎不正确,但看起来像是随机给出一些东西。

我是 Node.js 新手。我也不知道如何TimeOut在对象中添加 10 秒的参数sp

我尝试使用Matlab进行测试,并且可以成功检索数据。

我也尝试过Python,但对我不起作用 - PySerial 包在写入之前读取串行数据?

ug_*_*ug_ 1

我相信您错误地监听了您的数据。SerialPort 是一种称为双工的流形式,既可读又可写。要侦听流上的新数据,通常的做法是侦听data事件

在 Javascript 中还值得注意的是,当变量以下划线开头时,_pool它通常意味着它是一个通常不应该使用的私有变量。请参阅此问题以获取更多信息

只需sp.on('readable', function () {将部分重写为

sp.on('data', function(buffer) {
    console.log(buffer);
});
Run Code Online (Sandbox Code Playgroud)

应该让您开始看到您期望的数据。


为了测试这一点,我写了您概述的场景,但只在 0x81 之后写入了 10,000 字节进行测试。

请不要将此视为在 JS 中使用流的好方法。这是我尝试“轻量级”,可能有更好的方法来写这个

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

const sp = new SerialPort({path: "COM2", baudRate: 115200});

function Deferred(data) {
    this.data = data;
    this.resolve = null;
    this.reject = null;
    this.reset = () => {
        this.promise = new Promise(function(resolve, reject) {
            this.resolve = resolve;
            this.reject = reject;
        }.bind(this));
    }

    this.reset();
}

async function run() {
    let readBuffer = Buffer.alloc(0);
    let nextReadDeferred = new Deferred();

    sp.on('data', function(newData) {
        readBuffer = Buffer.concat([readBuffer, newData], newData.length + readBuffer.length)
        console.log('Got new data: ' + newData.length + ' buffer length is ' + readBuffer.length);
        nextReadDeferred.resolve(readBuffer);
        nextReadDeferred.reset();
    });

    console.log('Start 0x80')
    sp.write(Buffer.from([0x80]), e => { if(e) throw e; });
    await nextReadDeferred.promise;
    if(0x81 === readBuffer[0]) {
        // clear the buffer in prep of getting our data
        readBuffer = Buffer.alloc(0);
        console.log('Send 0x81 to start data flow')
        sp.write(Buffer.from([0x81]), e => { if(e) throw e; });

        console.log('Starting to receive data. Not sure how to know when were done?');
        // Dont know what to do here, I dont think the serial port closes. Maybe we are supposed to just expect a duration
        // of no data transfer? I dont know a whole lot about COM communication
    } else {
        console.warn('Expected 0x81 but got', readBuffer)
    }
}

run();
Run Code Online (Sandbox Code Playgroud)

输出:

$ node index.js
Start 0x80
Got new data: 1 buffer length is 1
Send 0x81 to start data flow
Starting to receive data. Not sure how to know when were done?
Got new data: 1024 buffer length is 1024
Got new data: 4096 buffer length is 5120
Got new data: 1024 buffer length is 6144
Got new data: 3856 buffer length is 10000
Run Code Online (Sandbox Code Playgroud)

为了测试这一点,我使用eterlogic作为由 TCP 服务器支持的虚拟 com 端口,并将以下节点代码作为我的“设备”

const s = require('net').Socket();
s.connect(5555, '127.0.0.1');

s.on('data', function(d){
    console.log('Got', d);
    if(d.equals(Buffer.from([0x80]))) {
        s.write(Buffer.from([0x81]));
    } else if(d.equals(Buffer.from([0x81]))) {
        s.write(Buffer.alloc(10000, 1));
    }
});
Run Code Online (Sandbox Code Playgroud)