整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

小巧的串口绘图软件-serialchart

小巧的串口绘图软件-serialchart

好久没更新了,这次为大家推荐一款小巧的串口绘图软件——serialchart。

啥是serialchart

之前我们讲过PID调试,而且调PID时候最好有对应曲线生成,这样我们再对着口诀来调那真是方便多了!这就需要我们今天推荐的这款软件出场啦=>> SerialChart串口调试工具是一款与众不同的串口调试软件,同时也是一款波形图发现时分析软件,它是通过配置文件来进行串口调试,并显示出波形图,并对波形图进行分析,让你可以更好的观察串口的通信情况,所以又有 串口示波器 之称。

长这个样子:

发文时,小编正在调MPU6050

data是串口输出的数据;

chart是自动绘制的图形;

configuration是设置区域;

怎么配置呢?

我们先说配置文件,后面再说如何把配置文件导入到软件中;大家也可直接跳过本部分,直接看下一部分内容——

配置文件示例。

这种是配置文件,可以修改为txt文档后打开,修改完成后再改为scc后缀。如果 右击-打开方式-记事本 的话,也能打开,但排版很丑。

  • Setup 部分

每个配置文件由此部分开始,这里你能设置全局参数比如:

port=COM3 //这就是软件进行串口通讯的接口啦,比如COM1,COM2.

baudrate=57600 //波特率,目前只支持以下几种波特率:110,300,600,1200,2400,9600,19200,38400,57600,115200.

width=1000 //chart区域的象素宽度和高度

height=201

background_color=white //chart的背景颜色,关于颜色的一些提醒 请注意在.SCC文件中(也就是此软件的配置文件)颜 色可以用16进制来表示(如 #FFF,#FFFFFF)或者用一些已命名的颜色(白色,蓝色,品 红,粉红,灰色)更多颜色请参考 http://www.w3.org/TR/SVG/types.html#ColorKeywords 请 注意特殊的颜色“透明”代表“没有颜色”。如果你不想让一些元素被绘制出来你可以使用它

grid_h_origin=100 //水平方向和竖直方向都有一条原始的轴线,一般和普通的格点线(每条曲线都是由一个个像素组成 的,所以叫格点线)颜色不同这两个参数确定了轴线在图表中距离顶点、左侧边界的位移,单位为 像素

grid_h_step=10 //确定了每次画线的长度

grid_h_color=#EEE //普通格点线的颜色

grid_h_origin_color=#CCC //原始轴线的颜色

grid_v_origin=0

grid_v_step=10 //确定了每次画线的长度

grid_v_color=#EEE //普通格点线的颜色

grid_v_origin_color=transparent

请注意目前的版本不支持流量控制的参数设置,默认设置为“无”,停止位默认为1,采用最常用的设置

  • Default and Field Sections(默认设置和区域设置)

SerialChart能识别CSV(逗号分隔数据)的数据包(将来可能会支持更多的格式)。每一行传送一份数据包,每一份数据包中的不同数据用逗号来分隔。下面的例子是SerialChart能识别的格式:

100,0.50,0.70

101,0.30,0.50

102,0.25,0.35

在配置文件中,下面的部分为每份数据包中的不同数据设定了参数比如:

min=-1

max=1

color=gray

min=0

max=255

color=blue

color=red

通过你可以对所有区域进行一个默认设置。这些参数对所有的数据区都有效除非在区域中他们被相同的名字覆盖在上面的例子中,和将继承区的默认设置

min=-1,max=1,但中的参数把值改为了min=0 and max=255

在你设置了默认设置后你应该为数据包中每个区域进行新的设置。设置顺序应根据他们在数据包中的先后而设置部分的名字可以随意命名但不能和,相同,也不能以'_'开头和结尾,比如可以命名为,,但不能命名为,下面的参数是和区能识别的参数min,max这两个值是对应曲线在图中的上下界。换句话说,如果你设定min=-1,max=1,那数据“1”将会被描绘在图中的顶端,数据“-1”将被描绘在图中的底端,而“0”将会描绘在图的正中间。数据会从映射到图中的,height就是曲线图的高度,在开始的中可以设置(这有点像arduino中的map()函数)

color

设置数据所对应曲线的颜色。如果你不想让某个数据被绘制出来可以设置为transparent(透明)

dash

可将曲线变成一条虚线,如,当dash=3,软件会将3个数据绘制出来,再停止绘制3个数据,再绘制3个数据,如此反复。

配置文件示例

注:只需修改port、baudrate即可。width、height、min、max按需修改

[_setup_]

port=COM7

baudrate=115200

width=700

height=500

background_color=white

grid_h_origin=100

grid_h_step=10

grid_h_color=#EEE

grid_h_origin_color=#CCC

grid_v_origin=100

grid_v_step=10

grid_v_color=#EEE

grid_v_origin_color=transparent

[_default_]

min=-70

max=70

[Acc]

color=green

[Gryo]

color=blue

[angle]

color=yellow

[angle_dot]

color=red

软件配置

1.点击【file】,新建或打开已有的配置文件;

2.点击【run】

3.串口只能同时被一个程序使用,当你要更新程序时,要点SerialChart中的stop。当需要更改参数(如port)时,可以直接在configuration中修改,然后点击stop--run即可。

erialPort是什么?

SerialPort 是一个用于在 Node.js 环境中进行串口通信的库。它允许开发者通过 JavaScript 或 TypeScript 代码与计算机上的串口设备进行交互。SerialPort 库提供了丰富的 API,使得在串口通信中能够方便地进行设置、监听和发送数据。

一般我们的设备(电子秤/扫码枪)会有一根线插入到电脑的USB口或者其他口,电脑上的这些插口就是叫串口。设备上的数据会通过这根线传输到电脑里面,比如电子秤传到电脑里的就是重量数值。那么我们前端怎么接收解析到这些数据的呢?SerialPort的作用就是用来帮我们接收设备传输过来的数据,也可以向设备发送数据。

简单概括一下:SerialPort就是我们前端和设备之间的翻译官,可以接收设备传输过来的数据,也可以向设备发送数据。

SerialPort怎么用?

SerialPort可以在Node项目中使用,也可以在Electron项目中使用,我们一般都是用在Electron项目中,接下来讲一下在Electron项目中SerialPort怎么下载和引入

1、创建Electron项目

mkdir my-electron-app && cd my-electron-app
npm init -y
npm i --save-dev electron


网上有很多Electron教程,这里不再详细说了

在package.json中看一下自己的Electron的版本,下一步会用到

2、下载SerialPort

这里先看一下自己使用的Electron对应的Node版本是什么,打开下面electron官网看表格中的Node那一列

Electron发行时间表:www.electronjs.org/zh/docs/lat…

如果你Electron对应的Node版本高于v12.0.0,直接下载就行

npm install serialport


如果你Electron对应的Node版本低于或等于v12.0.0,请用对应的Node版本对应下面的serialport版本下载

serialport.io/docs/next/g…

  • 对于 Node.js 版本0.10和0.12,最后一个正常运行的版本是serialport@4。
  • 对于 Node.js 版本4.0,最后一个正常运行的版本是serialport@6.
  • 对于 Node.js 版本8.0,最后一个正常运行的版本是serialport@8.
  • 对于 Node.js 版本10.0,最后一个正常运行的版本是serialport@9.
  • 对于 Node.js 版本12.0,最后一个正常运行的版本是serialport@10.

我项目的Electron版本是11.5.0,对应的Node版本号是12.0,对应的serialport版本号是serialport@10.0.0

3、编译Serialport

  • 安装node-gyp 用于调用其他语言编写的程序(如果已安装过请忽略这一步)
npm install -g node-gyp
  • 进入@serialport目录
cd ./node_modules/@serialport/bindings
  • 进行编译,target后面换成当前Electron的版本号
node-gyp rebuild --target=11.5.0

如果编译的时候报错了就将自己电脑的Node版本切换成当前Electron对应的版本号再编译一次

查看Electron对应Node版本号:www.electronjs.org/zh/docs/lat…

编译成功以后就可以在代码里使用Serialport了

4、使用Serialport

serialport官网使用教程:serialport.io/docs/next/g…

4.1、引入Serialport

const { SerialPort }=require('serialport')
// or
import { SerialPort } from 'serialport'


4.2、创建串口(重点!)

创建串口有两种写法,新版本是这样写法new SerialPort(params, callback)

const port=new SerialPort({
  path: 'COM1',  // 串口号
  baudRate: 9600, // 波特率
  autoOpen: true,  // 是否自动打开端口
}, function (err) {
  if (err) {
    return console.log('打开失败: ', err.message)
  }
  console.log('打开成功')
})


旧版本是下面这样的写法new Serialport(path, params, callback),我用的是serialport@10.0.0版本就是这样的写法

const port=new Serialport('COM1', {
  baudRate: 9600,
  autoOpen: true,  // 是否自动打开端口
}, function (err) {
  if (err) {
    return console.log('打开失败: ', err.message)
  }
  console.log('打开成功')
})


创建串口的时候需要传入两个重要的参数是path和baudRate,path是串口号,baudRate是波特率。最后一个参数是回调函数

不知道怎么查看串口号和波特率看这篇文章

如何查看串口号和波特率?

4.3、手动打开串口

如果autoOpen参数是false,需要使用port.open()方法手动打开

const port=new SerialPort({
  path: 'COM1',  // 串口号
  baudRate: 9600, // 波特率
  autoOpen: false,  // 是否自动打开端口, 默认true
})
// autoOpen参数是false,需要使用port.open()方法手动打开
port.open(function (err) {
  if (err) {
    return console.log('打开失败', err.message)
  }
  console.log('打开成功')
})


4.4、接收数据(重点!)

接收到的data是一个Buffer,需要转换为字符串进行查看

port.on('data', function (data) {
  // 接收到的data是一个Buffer,需要转换为字符串进行查看
  console.log('Data:', data.toString('utf-8'))
})


接收过来的data就是设备传输过来的数据,转换后的字符串就是我们需要的数据,字符串里面可能有多个数据,我们把自己需要的数据截取出来就可以了

假设通过电子秤设备获取到的数据就是"205 000 000",中间是四个空格分割的,第一个数字205就是获取的重量,需要把这个重量截取出来。下面是我的示例代码

port.on('data', function (data) {
  try {
      // 获取的data是一个Buffer
      // 1.将 Buffer 转换为字符串 dataString.toString('utf-8')
      let weight=data.toString('utf-8')
      // 2.将字符串分割转换成数组,取数组的第一个值.split('    ')[0]
      weight=weight.split('    ')[0]
      // 3.将取的值 去掉前后空格
      weight=weight.trim()
      // 4.最后转换成数字,获取到的数字就是重量
      weight=Number(weight)
      console.log('获取到重量:'+ weight);
  } catch (err) {
    console.error(`
      重量获取报错:${err}
      获取到的Buffer: ${data}
      Buffer转换后的值:${data.toString('utf-8')}
    `);
  }
})


4.5、写入数据

port.write('Hi Mom!')
port.write(Buffer.from('Hi Mom!'))


4.6、实时获取(监听)所有串口

const { SerialPort }=require('serialport')

SerialPort.list().then((ports, err)=> {
    // 串口列表
    console.log('获取所有串口列表', ports);
})


作者:Yaoqi
链接:https://juejin.cn/post/7323464381172301860

求场景

项目中难免有桌面设备接入的情况,比如扫码枪、RFID扫码器等情况。

方案

1.中间件方案

做一个在客户端微型http服务或者websoket服务,JavaScript调用这个服务与串口通讯。优点兼容浏览器,缺点这个服务得兼容操作系统,这种方案落地过。

2.浏览器插件方案

做一个浏览器插件,JavaScript基于插件与串口通讯。优点是你只需要搞定浏览器即可,缺点是可能需要兼容多种浏览器,这种方案没试过,理论上是可行的。

3.Chrome浏览器读取方案

通过Chrome浏览器的API直接读取串口数据,有点就是没有额外的工作,缺点就是只有Chrome浏览器能用,这种方案落地过。

串口基础知识

串行接口简称为串口,也叫串行通信,这是一个统称,采用串行通信的接口都叫作串口,串口是一个硬件接口。

工作模式

  • 单工:在任何时候都只能从A传输到B,就和在麦克风输出到扩音器的场景类似
  • 半双工:同时只能A传输的B或者B传输的C,跟对讲机的场景差不多吧
  • 全双工:在任何时候A和B都能互相传输数据,跟打电话场景类似。

相关参数

(1)波特率

串口通信时的速率。常见的有9600、14400、115200等等,这个说的就是bps,重点关注。

(2)数据位

这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。

(3)停止位

用于表示单个数据包的最后一位。典型的值为1、1.5或2位。停止位不仅表示传输的结束,并且提供计算机校正时钟同步的机会。停止位的位数越多,不同时钟同步的容错程度越大,但同时数据传输率也越慢。

(4)校验位

在串口通信中一种简单的检错方式。有三种检错方式:偶(E)、奇(O)、无(N)。

Vender ID 和 Product ID

即“厂家标识”和“产品标识”,USB 设备驱动的硬件接口需要识别 Vender ID 和 Product ID,各个平台的查看方式大家自己查询一下,也可以使用API查询

ChromeAPI介绍

判断浏览器是否支持串口

if ("serial" in navigator) {
	// The Web Serial API is supported.
}

根据usbVendorId和usbProductId过滤串口

const filters=[
  { usbVendorId: 0x2341, usbProductId: 0x0043 },
];

// Prompt user to select an Arduino Uno device.
const port=await navigator.serial.requestPort({ filters });

打开关闭串口

//这个参数是波特率
await port.open({baudRate: 9600});
await port.close();

读取和写入数据

const reader=port.readable.getReader();

// Listen to data coming from the serial device.
while (true) {
  const { value, done }=await reader.read();
  if (done) {
    // Allow the serial port to be closed later.
    reader.releaseLock();
    break;
  }
  // value is a Uint8Array.
  console.log(value);
}
onst writer=port.writable.getWriter();

const data=new Uint8Array([104, 101, 108, 108, 111]); // hello
await writer.write(data);

// Allow the serial port to be closed later.
writer.releaseLock();

示例

async function getCOMData() {
    if (!"serial" in navigator) {
        console.error("该浏览器不支持串口")
        return;
    }
    //这个地方换成自己设备
    const filters=[
        {usbVendorId: 0x1a86, usbProductId: 0x7521},
    ];
    let port=await navigator.serial.requestPort({filters});
    await port.open({baudRate: 9600});
    //验证分割符号
    let checkRN=(value)=> {
        if (value < 2) {
            return -1;
        }
        for (let i=1; i < value.length; i++) {
            if (value[i - 1]==0x0D && value[i]==0x0A) {
                return i;
            }
        }
        return -1;
    }
    const reader=port.readable.getReader();
    let tempArray=[];
    let readc=true;
    setTimeout(()=> {
        readc=false;
    }, 5000);
    //这里是流读取,一定要根据协议解决分包和黏包的问题
    while (true && readc) {
        const {value, done}=await reader.read();
        if (done) {
            // Allow the serial port to be closed later.
            reader.releaseLock();
            break;
        }
        let n=checkRN(value);
        if (n==-1) {
            tempArray=[...tempArray, ...value]
        } else {
            let fullArray=[...tempArray, ...value.slice(0, n)]
            tempArray=[...value.slice(n + 1, value.length)];
            let str=String.fromCharCode(...fullArray)
            console.log("解析后的数:",str)
        }
    }
    reader.releaseLock();
    await port.close();
    return undefined;
}

API参考地址:https://web.dev/serial/#close-port