首页 解决方案 SmartDisplay RS485入门

SmartDisplay RS485入门

September 10,2022

说明

一、 前言

 

SmartDisplay 近年来已经被广泛地应用在医疗、工控、车用等各种领域。简单地说,它是结合微控制器的显示屏,能够处理复杂的图资加载、设定、显示、甚至是输入等工作,而外界只要利用简单的指令就可以进行互动操作,因此非常适合各种需要显示或控制的各类型应用。

SmartDisplay支持多种通讯接口。目前最常用的是CANbus/CANopen,RS485/Modbus,未来也将提供更多元的选择。其中RS485/Modbus是工业界常用的通讯接口,市面上很容易取得各种价格合理的RS485装置。线路架构单纯,只要两条线(RS485_A/RS485_B)就可以进行通讯,而且RS485通讯接口在操作系统上通常是以『串行端口』(Serial Port)的方式呈现,在每种平台都有对应的发展函式库。再加上Modbus协议相当容易了解,因此我们选择它来进行实验与讲解。

本文将由浅入深介绍如何控制SmartDisplay,了解其控制原理,最后再介绍如何制作跨平台的应用程序。无论您是工业界设备专家,或是热衷动手做的Maker自造者,都欢迎和我们一起进入SmartDisplay的世界!

二、 软硬件需求

 

■SmartDisplay

需要支持RS485接口的SmartDisplay进行联机测试。

■通讯接口RS485

由于个人计算机/树莓派通常没有RS485,我们可以选购各种USB to RS485的转接线。有些单板计算机内建RS485,则可以直接使用。

RS485转接线

图2-1 RS485转接线

 

■测试环境

符合前面两个条件后,就可以选择适合的执行环境。唯一的条件就是能够读写串行端口,因此包括Windows、MacOS、各种Linux(包括树莓派的Raspbian)、Arduino、单板计算机(SBC)等等都可以胜任,华凌型号:WUACLB120V0000N0NX01即是非常好的单板计算机(SBC)选择。

WUACLB120V0000N0NX01

Model No. WUACLB120V0000N0NX01

 

三、 简易控制测试

 

■取得句柄

首先我们要取得句柄。最简单的方式是从SmartDisplay GUI Builder取得。GUI Builder是SmartDisplay的绝佳辅助软件。它可以帮助我们在没有实体装置的情况下学习、操作、设计、显示用户接口,完全不需要写任何程序。具备所见即所得的特性,只要拖曳或点选按钮或组件就可以进行用户接口设计。除此之外,内建与SmartDisplay共享程序原始码的仿真器,因此可以确保与实体装置一致的外观与行为。更棒的是,它还是免费的!

联系我们取得SmartDisplay GUI Builder

SmartDisplay GUI Builder

图 3-1 SmartDisplay GUI Builder

 

执行GUI Builder后,开启一个项目。在此我们选择 5”机种,下方的预设情境则选择车用(Vehicle)。设好专案名称后,按Create创建。如果先前已经产生过,也可以直按右侧的选单直接选取。

开启专案

图3-2开启专案

 

项目打开后,先选取接口

选择接口

图3-3 选择接口

 

设定接口参数

图3-4设定接口参数

 

Interface选择RS485,RS485 Port则要设为RS485转接线实际的端口,若是不清楚则可以在设备管理器中查询(重复拔插看消失或显示的是那一个)。Baudrate采用默认值115200即可。

设备管理器的Com Port显示

图3-5 设备管理器的Com Port显示

 

不过如果现在还没有RS485装置也没关系,只要Interface选择RS485即可,RS485 Port可以先不用管,因为现在我们只使用仿真器,并不会真的联机到装置。

按Simulator/Simulator with GUI 开启仿真器:

执行仿真器

图3-6 执行仿真器

 

执行后可以看到仿真画面,各组件的控件,以及右侧的控制指令记录。改变任何一个组件的值就会看到送出的指令内容:

改变组件内容以及传送的句柄

图3-7 改变组件内容以及传送的句柄

 

每一个动作都会看到TX/RX两个指令,这是因为装置(即使现在其实是仿真器)在收到指令后,会送回相同指令表示已经收到。

我们将不同组件的几个不同数值记录下来,下一个步骤可以用来控制实体装置。

句柄

表 3-1 句柄

■与装置联机

RS485是利用两条讯号线的电位差来传送讯号,所以只要这两条电线就可以联机,连地线都不用接。RS485的讯号线名称为A+/B-,照着接即可。

RS485 接线

图3-8 RS485 接线

 

主机如何传送句柄呢?只要操作系统的程序能写数据到串行端口即可。不过在进行测试之前,有两点得先注意一下。

1. 由于在不同操作系统上的Com Port名称不一样,因此在测试时请先查询确定。例如下表:

各种操作系统的串行端口名称

表 3-2 各种操作系统的串行端口名称

 

2. 有些操作系统Com Port的权限默认为不开放,使用前必须先设定一下,以Linux/Ubuntu为例,如果Com Port名称为 ttyUSB0,则只要在终端机下执行:

sudo chmod 666 /dev/ttyUSB0

下面提供两种测试方法。

 

■Serial Port 终端机控制

使用支持16进位输入的串行端口终端机软件,联机后直接输入16进位句柄:

以终端机程序传送句柄

图3-9 以终端机程序传送句柄

 

正常的话,应该就可以看到装置上的组件根据不同句柄产生动作。

但这种方式只是用来测试是否联机成功,在应用上其实不太方便。要达到最佳效果,还是得藉由程序来完成。至于用那一种语言?其实都可以,我们先用当红的跨平台程序语言python来试试。

■使用python

下列程序使用python3执行。程序结构相当简单,只是直接把三组句柄每隔一秒写入串行端口,让装置上的仪表持续转动。
 

import serial
from time import sleep

"""
The name of Com Port varies according to the operating system, For example:
Raspberry Pi: /dev/ttyUSBn (e.g. /dev/ttyUSB0)
Windows: COMn (e.g. COM22)
"""
# Raspberry Pi / Rasbian
# COM_PORT = '/dev/ttyUSB0'
COM_PORT = 'COM22'

v000 = bytes.fromhex('7B06000600006251')
v050 = bytes.fromhex('7B0600060032E384')
v100 = bytes.fromhex('7B060006006463BA')

ser = serial.Serial(COM_PORT, 115200)
while True:
ser.write(v000)
sleep(1.0)
ser.write(v050)
sleep(1.0)
ser.write(v100)
sleep(1.0)
ser.write(v050)
sleep(1.0)

python原始码可以在各种平台上执行,因此只要串行端口的名称正确,接上适当的转接线后即可正常运作。

不过这示范程序内几个固定的句柄一定不符合实际应用,所以我们接下来要来了解这些指令的内容,才能充份发挥通讯界面的控制功能。

四、 句柄分析

 

■比对分析

比对同一个组件,不同值的指令:

表格

不难发现,蓝色部分就是我们设定组件的值。

比对不同组件,同一个值的指令:

表格

蓝色部份显然是指对组件的某种指针或地址。
至于后方两个bytes的数据看起来没有规则,请见以下的句柄解密。

■句柄解密

其实这8个bytes的内容就是所谓的Modbus讯息。简单地用一张图来说明各字段的意义:

句柄实例说明

图4-1句柄实例说明

 

ID
每个Modbus装置都要有一个标识符。SmartDisplay的标识符就是0x7B = 123

Fun(Function Code)
功能码,说明这个讯息的目的,例如这里的06就是 Write Single Register,也就写入一个值到指定的地方。

Register Address
缓存器地址,也就是要写入的目的地(也就是组件的地址)。

Data
要写入的内容(也就是组件的值)

CRC
对前6个bytes进行CRC(Cyclic Redundancy Check)的结果,用来检查传输过程数据是否发生错误。

有些概念了吗?若要深入了解,还是得先看一下什么是Modbus。

五、 Modbus简介

 

■Modbus协定

Modbus协议其实是一种数据格式。它基本上定义了一个主从架构的通讯内容。由于只是数据结构的定义,因此可以透过各种设备进行通讯,例如RS232, RS422, RS485, 甚至是网络。

由于网络上已经有非常多的教学与说明文件,所以这里并不对Modbus进行详细说明。其实只要知道一些概念,就可以对Modbus运用自如了。

■概念模型

Modbus将数据传输当成是『缓存器』(Register)存取。每个装置都要定义自己的缓存器种类与地址供外界参考。所谓传送数据给装置就是写入指定缓存器,读取数据就是读取指定缓存器,简单明暸。另外,每个地址缓存器储存的值都是16-bits。

■功能码

根据资料的特性,Modbus定义了几种读写的方法,以讯息中的功能码指定。

Modbus Function Codes

表5-1 Modbus Function Codes

 

以SmartDisplay的控制程序来说,最常用的就是06:Write single register(写入一个16-bits的值)以及Read holding registers(读取多个缓存器的值)。

■CRC

这个看起来最神秘的部分其实不难,这只是一个通讯的检查码,用以确保通讯数据的正确性。我们不一定要深入研究其原理(但实际上也只是查表以及位运算,最后得到16-bit检查码),只要了解如何使用即可。

六、 控制SmartDisplay 组件

 

前面提到每个Modbus都要定义缓存器种类与地址,现在就来讨论这个主题。

■缓存器分类

SmartDisplay缓存器大致可分成三类:

1.)装置信息(例如版本、装置名称等)
使用04:Read Input Registers读取。这些数据只有在更新韧体时才会改变,通常是刚联机时读取,用来取得装置特性参数。

2.)组件特性(例如种类、位置等等)
使用03:ReadHoldingRegisters/16: Write Multiple Register 读写。这些数据影响到组件的外观显示,在非设计时间时通常不会改变。若要改变内容,必须先将SmartDisplay显示暂时关闭才能更新。

3.)组件数值(组件表现的值,例如转速、开或关,百分比等等,因组件而异)
这是运作中主要改变的项目。每个组件都使用一个16-bits数值,因此用06:Write Single Register设定。

下面列出这些缓存器的整理列表:

■Input Registers

SmartDisplay Input Registers

表6-1 SmartDisplay Input Registers

 

■Holding Registers

SmartDisplay Holding Registers

表6-2 SmartDisplay Holding Registers

 

早期的SmartDisplay只支持10个组件,因此widgetID的范围介于0 ~ 9(含)。新版的韧体已经扩展到64个,不过寻址方式有些改变,这里暂不讨论。

有了这些资料后(虽然还不完整,但是目前够用了),我们就可以将控制指令进行包装,传送给SmartDisplay进行控制。至于如何包装,以及如何加入CRC码,将在后面的章节说明。

七、 用户接口

 

要让SmartDisplay进入实际应用,还是需要有一个适合的人机接口(尤其是图形人机接口,Graphics User Interface, GUI),才能发挥最大效用。目前跨平台的GUI发展平台有经有很多选择,我们这里使用Qt来实现。

许多人以为Qt仅仅是GUI函式库,但其实它是相当完整的发展框架(Framework)。如果应用程序完全透过它的类别库来实现,就可以很容易地将项目移植到其他平台(PC/Windows、Mac/MacOS、 Raspberry Pi/Raspbian、Android、iOS、Embedded等等),几乎不用修改程序,是相当值得投资学习的发展工具软件。

比较新版的Qt其实也已经支持Modbus类别库了。但这里为了说明,以及方便大家改写成其他语言,我们还是从最基本的串行端口读写来实现这个测试程序。

这个程序除了提供选择串行端口的功能以及传送上个例子使用的句柄以外,在用户界面还进一步提供一个水平拉杆,能够设定指定组件的数值。串行端口如果选择COM的话,要记得再填上实际的编号。

下图这个程序在树莓派以及Ubuntu上的执行画面,程序完全不用修改。

树莓派上的SetWidgetValue画面

图7-1 树莓派上的SetWidgetValue画面

 

Ubuntu上的SetWidgetValuet画面

图7-1 Ubuntu上的SetWidgetValuet画面

 

■CRC运算

CRC运算其实不复杂,以Qt来实现大概就像以下的程序代码:

QByteArray SetWidgetValue::calculateCRC(QByteArray data)
{
uint16_t crc = 0xFFFF;
for(int idx = 0; idx < data.length(); idx++)
{
uint8_t i = (uint8_t)crc ^ data[idx];
crc >>= 8;
crc ^= crcTable[i];
}
QByteArray ba;
ba.append(char(crc & 0xFF));
ba.append(char(crc >> 8));
return ba;
}

其中的 crcTable[] 的内容为:

const uint16_t crcTable[] =
{
0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
. . .
0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040
};

这里没有列出全部内容。github中有完整资料,有兴趣可以自行搜寻下载,在这边技术文章中只需要知道如何运用就好。

■数据报装

下面就是根据UI计算句柄,然后送到SmartDisplay的关键函式:

void SetWidgetValue::on_sbValue_valueChanged(int value)
{
int id = ui->edWidgetID->text().toInt();
sendWidgetValue(id, value);
ui->lbValue->setText(QString::number(value));
}

void SetWidgetValue::sendWidgetValue(int id, int value)
{
QByteArray msg;
uint16_t addr = (uint16_t)(id * 100 + 6);
msg.append(deviceID);
msg.append(writeSingleRegister);
msg.append((uint8_t)addr >> 8);
msg.append((uint8_t)addr & 0xFF);
msg.append((uint8_t)value >> 8);
msg.append((uint8_t)value & 0xFF);
QByteArray msgToSend = msg.append(calculateCRC(msg));
writeSerialPortData(msgToSend);
}

如果您已熟悉Qt,则上述程序代码应该不难理解。若不熟悉的话,花一点时间研究一下,它有些观念其实还相当不错,值得深入学习。熟悉之后,对发展跨平台应用程序,或是快速制作系统雏型来说,都是不错的选择。

八、 进阶范例

 

前面的例子只是针对一个组件值的设定。另外有更完整的范例SmartDisplayConsole供有兴趣的读者进一步了解。下图是在树莓派上的执行画面:

树莓派上的SmartDisplayConsole画面

图8-1 树莓派上的SmartDisplayConsole画面

 

文章最后有github网址,观迎大家一起参考研究。

九、 结语

 

我们已经说明了控制SmartDisplay的每一个步骤,也提供了多种的控制方式。运用这些知识以及丰富的想象力,相信一定可以激荡出各种不一样的火花,制作出更多样性的产品。就让我们一起用SmartDisplay创造更美好的未来吧!

十、 参考数据

 

Serial Terminal Basics
https://learn.sparkfun.com/tutorials/terminal-basics/command-line-windows-mac-linux

Modbus
https://www.modbustools.com/modbus.html
https://www.modbusdriver.com/doc/mbusmaster.net/modbus.htm

十一、 范例原始码

 

GettingStartedWithSmartDisplay
https://github.com/Smart-Display-Series/GettingStartedWithSmartDisplay.git

SmartDisplayConsole
https://github.com/Smart-Display-Series/SmartDisplayConsole.git

对显示器解决方案有疑问?您想做的,由我们实现。 联络我们!

订阅

接收最新显示器技术知识与新品消息

联络我们

价格/规格书/一般查询

技术支持

联系我们询问技术内容

go top
联络我们
close