솔루션 SmartDisplay RS485 개요

SmartDisplay RS485 개요

Sep 10, 2022

설명

I. 서문:

 

스마트 디스플레이는 의료, 산업용 제어, 자동차(출시 이후) 등 다양한 분야에서 폭넓게 사용되어 왔습니다. 간단히 말해 스마트 디스플레이는 디스플레이와 마이크로컨트롤러를 합한 형식으로, 복잡한 그래픽 로딩, 설정, 디스플레이는 물론 입력까지 처리할 수 있고 외부 디바이스(호스트)에서는 간단한 명령을 사용해 대화형 작업을 수행할 수 있으므로 다양한 요구 사항에 매우 적합합니다. 다양한 유형의 애플리케이션을 표시하고 제어할 수 있습니다.

스마트 디스플레이는 다양한 통신 인터페이스를 지원합니다. 현재 가장 보편적으로 쓰이는 인터페이스는 CAN/CANopen, RS485/Modbus이며 향후 더 많은 선택지가 추가될 예정입니다. 그중 RS485/Modbus가 업계에서 인기 있는 통신 인터페이스이며, 시중에 적당한 가격대의 RS485 디바이스가 다양하게 출시되어 있습니다. 와이어 두 개(RS485_A/RS485_B)가 통신만 가능하면 되는 간단한 회선 구조를 갖추었으며, 통신 인터페이스는 보통 운영 체제에서 “직렬 포트” 형태로 표시되고, 플랫폼마다 상응하는 개발 함수 라이브러리가 있습니다. 또한 Modbus 프로토콜은 이해하기 매우 쉽기 때문에 다음과 같은 실험과 설명을 통해 예로 들어보았습니다.

이 글에서는 단순한 수준부터 복잡한 수준까지 스마트 디스플레이를 컨트롤하는 법을 설명하고 컨트롤 원리를 안내하며, 마지막으로 크로스 플랫폼 애플리케이션을 만드는 방법을 소개합니다. 본 과정에 산업용 장비 전문가든 DIY 취미 활동가든 모두 참여하실 수 있습니다. 스마트 디스플레이의 세상에 오신 것을 환영합니다.

II. 요구 사항:

 

■Smart Display_RS485

연결 테스트를 하려면 RS485 인터페이스를 지원하는 스마트 디스플레이가 있어야 합니다.

■RS485 동글

PC/Raspberry Pi와 같은 호스트는 RS485 포트가 없는 것이 보통이므로, 필요한 경우 다양한 USB를 RS485 동글에 활용하면 됩니다.

그림 2-1 Types of USB to RS485 동글

그림 2-1 Types of USB to RS485 동글

 

■호스트 디바이스

위의 요구 사항에 부합하면, 다음으로 호스트 역할을 할 테스트 벤치 실행 환경을 선택하면 됩니다. 호스트 디바이스의 유일한 조건은 OS가 Windows든 MacOS, 다양한 Linux(Raspberry Pi용 Raspbian 포함)든, 플랫폼이 단일 보드 컴퓨터, Arduino 등 무엇이든 관계없이 호스트의 직렬 포트를 읽고 쓸 줄 알아야 한다는 것입니다.

Winstar는 편의상 RS485 데모 설정이 기본 내장된 단일 보드 컴퓨터를 제작하며, 이것을 아래 그림과 같이 직접 호스트 디바이스로 사용할 수 있습니다.

WUACLB120V0000N0NX01

Model No. WUACLB120V0000N0NX01

 

III. 컨트롤 인터페이스용 간단한 테스트:

 

■컨트롤 코드 가져오기

호스트를 사용해 스마트 디스플레이에서 협업하는 방식을 이해하려면 다음과 같은 단계를 따릅니다. 우선 컨트롤 코드를 가져와야 합니다. 스마트 디스플레이 GUI 빌더에서 가져오는 것이 가장 쉽습니다. GUI 빌더는 스마트 디스플레이용으로 훌륭한 지원 소프트웨어입니다. 하드웨어 실물 디바이스 없이 사용자 인터페이스를 학습, 가동, 설계하고 표시하는 데 쓸 수 있으며 프로그램을 전혀 작성하지 않고도 UI를 디자인할 수 있게 해줍니다. 위지위그(WYSIWYG) 기능을 사용하면 버튼이나 객체를 끌어오거나 클릭하는 것만으로 사용자 인터페이스를 디자인할 수 있습니다. 또한 스마트 디스플레이와 소스 코드를 공유하는 기본 내장 시뮬레이터가 있어 실물 디바이스와 똑같은 외관과 동작을 보장합니다. 게다가 무료라서 더 좋습니다!

Contact for Smart Display GUI Builder

그림 3-1 Smart Display GUI Builder

그림 3-1 Smart Display GUI Builder

 

GUI 빌더를 두 번 클릭해 Windows OS에서 앱을 실행하고 프로젝트를 엽니다. 여기에서 5인치 RS485 스마트 디스플레이 WL0F00050000FGDAASA00을 선택합니다. 아래의 기본 시나리오는 차량(Vehicle)입니다. 프로젝트 이름을 입력하고, 만들기(Create) 버튼을 눌러 프로젝트를 만듭니다. 이전에 만들어놓은 프로젝트인 경우, 오른쪽에 있는 메뉴에서 바로 프로젝트를 선택할 수도 있습니다.

그림 3-2 Create project

그림 3-2 Create project

 

프로젝트가 열리면 인터페이스부터 선택합니다.

그림 3-3 Select interface

그림 3-3 Select interface

 

그림 3-4 Set interface parameters

그림 3-4 Set interface parameters

 

인터페이스로 RS485를 선택하면 호스트의 RS485 포트가 RS485 동글 연결 포트의 실제 포트로 설정됩니다. 조금이라도 의구심이 드는 경우, 디바이스 관리자의 포트 이름을 확인하면 됩니다(몇 번 반복해서 연결을 해제하여 없어지는지 확인하거나 어느 것이 표시되는지 확인). 전송 속도는 기본값인 115200으로 유지하면 됩니다.

그림 3-5 Com Port display of device administrator

그림 3-5 Com Port display of device administrator

 

하지만, 아직 스마트 디스플레이 RS485 디바이스가 없는 경우 인터페이스를 RS485로 선택하기만 문제가 되지 않습니다. 현재로서는 RS485 포트를 무시해도 됩니다. 지금은 시뮬레이터만 활용하고, 스마트 디스플레이에 실제로 연결하지는 않기 때문입니다.

시뮬레이터/GUI를 포함한 시뮬레이터를 클릭하여 다음을 실행합니다.:

그림 3-6 To run Simulator

그림 3-6 To run Simulator

 

실행하면 시뮬레이션 화면, 각 객체의 컨트롤 항목이 표시되고, 화면 오른쪽에 통신 데이터 기록이 표시됩니다. 명령의 내용을 보려면 객체 값을 변경합니다.

그림 3-7 Change the content of the object and the control code

그림 3-7 Change the content of the object and the control code

 

모든 작업에 TX/RX 명령 두 개가 표시됩니다. 디스플레이 디바이스(실제로는 아직 에뮬레이터일 뿐이지만)가 명령을 수신한 다음 읽음 확인 차원에서 같은 명령을 돌려보내 수신했다는 사실을 표시하기 때문입니다.

서로 다른 객체에 대해 여러 가지 다른 값이 기록되며, 실물 디바이스를 제어할 때는 다음 단계를 사용하면 됩니다.

표 3-1 Control code

표 3-1 Control code

■와이어 연결:

RS485는 신호를 송신하고 수신하는 데 디퍼런셜 페어를 사용하므로, 이 두 개의 와이어가 연결되기만 하면 접지 와이어조차 필요하지 않습니다. RS485의 신호 회선 이름은 A/B이며 이대로 따르기만 하면 됩니다(A는 A에 연결, B는 B에 연결).

그림 3-8 RS485 wire connection

그림 3-8 RS485 wire connection

 

호스트가 자기 자신으로부터 컨트롤 코드를 전송하는 것이 어떻게 가능할까요? 직렬 포트에 쓸 수만 있으면 됩니다. 단, 본격적으로 테스트를 시작하기 전에 염두에 두어야 할 것이 두 가지 있습니다.

1. 서로 다른 운영 체제에서는 통신 포트 이름이 다르므로, 테스트 전에 확인해야 합니다. 예를 들어 다음 표를 참조하세요.

Serial port names for various operating systems

표 3-2 Serial port names for various operating systems

 

2. 운영 체제에 따라 통신 포트 권한이 기본적으로 열려(open) 있지 않을 수도 있습니다. 반드시 설정한 후에 사용해야 합니다. 예를 들어 Linux/Ubuntu에서 통신 포트 이름이 ttyUSB0인 경우, 터미널에서 그냥 실행하면 됩니다.

sudo chmod 666 /dev/ttyUSB0

 

아래와 같은 두 가지 테스트 방식이 제공됩니다.

■직렬 포트 터미널 제어

16진수 입력을 지원하는 직렬 포트 터미널 소프트웨어를 사용하여, 연결 후 16진수 컨트롤 코드를 직접 입력합니다.

그림 3-9 Send Control Codes with Terminal Program

그림 3-9 Send Control Codes with Terminal Program

 

정상인 경우, 디바이스의 객체가 다양한 컨트롤 코드에 따라 작동하는 것을 확인할 수 있습니다.

하지만 이 방식은 연결이 성공했는지 아닌지 테스트할 때만 쓰이며, 실제 용도로는 그다지 편리하지 않습니다. 최선의 결과를 내려면 프로그램을 통해 수행해야 합니다. 어느 언어를 사용해야 할까요? 사실 시도해볼 수 있습니다. 먼저 인기 있는 크로스 플랫폼 프로그래밍 언어인 Python을 사용해 시도해보기로 합시다.

■Python 사용

다음 프로그램은 python3를 사용하여 실행됩니다. 프로그램 구조는 아주 단순합니다. 그냥 컨트롤 코드 3세트를 1초에 한 번씩 직렬 포트에 직접 써서 디바이스의 도구가 계속 회전하게 하기만 하면 됩니다.

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 소스 코드는 다양한 플랫폼에서 실행할 수 있으므로, 직렬 포트의 이름이 올바르게 지정된 이상 적절한 연결 테스트 벤치에서 문제없이 작동하는 것이 정상입니다.

다만, 이와 같은 고정된 컨트롤 코드는 예시일 뿐 실제 애플리케이션에 적용할 수는 없으므로, 제대로 작동하게 하려면 이러한 지침의 내용을 잘 이해해야 합니다.

IV. 컨트롤 코드 분석

 

■비교 분석

같은 객체에 대하여 다른 값을 가진 명령 비교:

Table

파란 부분이 우리가 설정한 객체의 값이라는 사실은 어렵지 않게 확인됩니다.

객체는 다르고 값은 같은 명령 비교:

Table

파란 부분이 일종의 인덱스나 객체에 대한 주소를 가리키는 것이 분명합니다.

마지막 두 개 바이트의 데이터의 경우, 규칙이 없는 것 같습니다. 그런데 이런 메시지는 무슨 의미일까요? 이제 설명하겠습니다.

■컨트롤 코드 분석

사실, 이러한 8개 바이트의 내용을 일명 Modbus 메시지라고 합니다. 간단히 그림을 사용하여 각 필드의 의미를 나타낼 수 있습니다.

그림 4-1 Control code example description

그림 4-1 Control code example description

 

ID
각각의 Modbus 디바이스마다 식별 코드가 있어야 합니다. 스마트 디스플레이의 식별 코드는 0x7B = 123입니다.

Fun(함수 코드)
함수 코드는 이 메시지의 목적을 나타냅니다. 예를 들어 여기서 06은 지정된 장소에 값을 쓰기도 하는 Write Single Register를 의미합니다.

레지스터 주소
작성할 대상이 되는 레지스터 주소입니다(즉, 객체의 주소).

데이터
쓸 내용입니다(즉, 객체의 값).

CRC
첫 6개 바이트의 CRC(Cyclic Redundancy Check) 결과를 사용하여 전송 프로세스 중에 데이터에 오류가 발생했는지 아닌지 확인합니다.

개념이 좀 잡히시나요? 자세한 정보를 알아보려면 Modbus가 무엇인지 살펴보아야 합니다.

V. Modbus 개요

 

■Modbus 프로토콜

Modbus 프로토콜은 사실 데이터 형식의 일종입니다. 이는 기본적으로 마스터-슬레이브 아키텍처의 통신 내용을 정의하는 것입니다. 이것은 데이터 구조의 정의일 뿐이므로, 다양한 물리적 인터페이스를 통해 통신할 수 있으며(예: RS232, RS422, RS485) 심지어 네트워크를 통해서도 가능합니다.

인터넷상에 수많은 교육 및 설명 자료가 워낙 많이 있으니 여기서 Modbus를 자세히 설명하지는 않겠습니다. 사실, Modbus는 몇 가지 개념만 알면 자유자재로 이용할 수 있습니다.

■개념 모델

Modbus는 데이터 전송을 “레지스터” 액세스로 간주합니다. 각 디바이스가 외부 참조 목적으로 자신만의 레지스터 유형과 주소를 정의해야 합니다. 이른바 디바이스로 데이터를 ‘전송’한다는 것은 지정된 레지스터에 쓰고, 데이터를 읽는다는 것은 지정된 레지스터를 읽는 것을 말합니다. 이는 단순하고 명확한 개념입니다. 또한 각 주소 레지스터에 저장된 값은 16비트입니다.

■함수 코드

Modbus는 데이터 특징에 따라 몇 가지 읽기와 쓰기 방식을 정의하는데, 이는 메시지의 함수 코드에 따라 지정됩니다.

표 5-1 Modbus Function Codes

표 5-1 Modbus Function Codes

 

스마트 디스플레이 컨트롤 프로그램의 경우, 가장 보편적으로 쓰이는 것은 06: Write single register(16비트 값 쓰기)와 Read holding registers(여러 레지스터의 값 읽기)입니다.

■CRC

마지막 2개 바이트가 가장 알 수 없는 부분 같지만, 실제로는 그렇게 어렵지 않습니다. 이는 단순히 통신 데이터를 보장하기 위한 CRC(Cyclic Redundancy Check)일 뿐입니다. 사용할 줄만 알면 굳이 심층적으로 원리를 공부할 필요까지는 없습니다(하지만 사실, 이것은 단순한 테이블 검색과 비트 작업에 불과하며, 최종적으로는 16비트 확인 코드를 얻게 됨).

VI. 스마트 디스플레이 객체 제어

 

앞서 언급한 것과 같이, 각 Modbus는 레지스터의 유형과 주소를 정의해야 합니다. 이제부터 이 주제를 다뤄보겠습니다.

■레지스터 분류

스마트 디스플레이 레지스터는 크게 세 가지 범주로 나눌 수 있습니다.

1.)디바이스 정보(예: 버전, 디바이스 이름 등)
04: Read Input Registers를 사용하여 읽습니다. 이러한 데이터는 펌웨어가 업데이트될 때만 변경됩니다. 보통은 디바이스 특징 매개변수를 얻기 위해 막 연결되었을 때입니다.

2.)객체 속성(예: 종류, 위치 등)
03: Read Holding Registers/16: Write Multiple Register를 사용하여 읽고 씁니다. 이러한 데이터는 객체의 외관에 영향을 미치며 보통은 설계 단계를 벗어나서는 변경되지 않습니다. 내용을 변경하려면 스마트 디스플레이의 전원을 일시적으로 꺼야 업데이트할 수 있습니다.

3.)객체 값(RPM, 켜기 또는 끄기, 백분율 등 객체가 나타내는 값이며, 객체마다 각기 다름)
이것이 작업의 주된 변경 항목입니다. 각각의 요소는 16비트 값을 사용하므로, 설정할 때 06: Write Single Register를 사용합니다.

다음은 이러한 레지스터의 목록을 정리한 것입니다.

■Input Registers

표 6-1 Smart Display Input Registers

표 6-1 Smart Display Input Registers

 

■Holding Registers

표 6-2 Smart Display Holding Registers

표 6-2 Smart Display Holding Registers

 

초기 스마트 디스플레이는 객체를 10개만 지원하므로, widgetID 범위는 0~9(끝값 포함)입니다. 펌웨어의 새 버전은 64까지 확장되었지만, 주소 지정 방식이 변경되었습니다(이 부분은 여기에서 다루지 않음).

이러한 데이터를 사용하면(완전하지는 않아도 현재로서는 충분) 컨트롤 지침을 패키징하여 스마트 디스플레이에 보내 컨트롤에 사용하도록 할 수 있습니다. CRC 코드의 패킹 방법과 추가 방법은 다음 챕터에서 설명합니다.

VII. 사용자 인터페이스

 

스마트 디스플레이를 실제로 활용하려면 적절한 HMI(특히 GUI(Graphics User Interface))가 있어야 실효성을 극대화할 수 있습니다. 현재 크로스 플랫폼 GUI 개발 플랫폼의 선택지는 다양하므로, 여기에서는 Qt를 사용해 구현합니다.

많은 이들이 Qt를 단순히 GUI 라이브러리인 줄 알지만, 사실은 상당히 완전한 개발 프레임워크입니다. 애플리케이션이 전적으로 클래스 라이브러리를 통해서만 구현되는 경우, 플랫폼을 거의 수정하지 않고 다른 플랫폼으로 손쉽게 포팅할 수 있습니다(PC/Windows, Mac/MacOS, Raspberry Pi/Raspbian, Android, iOS, 임베디드 등). 이 프로그램은 배우는 데 투자할 가치가 충분히 있는 개발 도구 소프트웨어입니다.

Qt 최신 버전은 이미 Modbus 클래스 라이브러리를 지원하고 있습니다. 다만 여기에서는 설명을 위해, 또한 누구나 다른 언어로 다시 쓰는 과정을 지원하기 위해 이 테스트 프로그램을 가장 기본적인 직렬 포트 읽기 및 쓰기를 통해 구현하겠습니다.

이 예시는 직렬 포트를 선택하고 이전 예시에서 사용한 컨트롤 코드를 전송하는 기능을 제공할 뿐 아니라 지정된 객체의 값을 설정할 수 있는 앱 창의 사용자 인터페이스에 수평 레버를 제공하는 역할도 합니다. 직렬 포트에 COM을 선택하는 경우, 실제 숫자로 채워야 한다는 점에 유의해야 합니다.

다음 그림은 이 프로그램을 Raspberry Pi와 Ubuntu에서 실행한 화면입니다. 프로그램은 전혀 수정할 필요가 없습니다.

그림 7-1 Set WidgetValue screen on Raspberry Pi

그림 7-1 Set WidgetValue screen on Raspberry Pi

 

그림 7-2 Set WidgetValuet screen on Ubuntu

그림 7-2 Set WidgetValuet screen on Ubuntu

 

■CRC operation

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;
}

The contents of crcTable[] are:

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에 따라 컨트롤 코드를 계산해 스마트 디스플레이에 보내는 주요 함수입니다.

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에 이미 친숙한 사용자라면 위의 코드를 어렵지 않게 이해할 수 있습니다. 아직 친숙하지 않다면, 잠시 시간을 들여 살펴보시기 바랍니다. 일부 개념은 사실 아주 쓸모 있고, 심층적으로 공부할 만한 가치가 있습니다. 익숙해진 다음에는 크로스 플랫폼 애플리케이션 개발이나 시스템의 프로토타입을 신속하게 제작하는 데 이용하면 좋습니다.

VIII. 고급 예시

 

이전 예시는 객체 값을 설정하는 용도에 불과합니다. 관심 있는 독자라면 자세히 알아볼 수 있도록 SmartDisplayConsole 애플리케이션 프로그램에 관한 좀 더 온전한 예시가 있습니다. 아래 그림은 Raspberry Pi의 실행 화면입니다.

그림 8-1 SmartDisplayConsole screen on Raspberry Pi

그림 8-1 SmartDisplayConsole screen on Raspberry Pi

 

글 끝에 github URL이 있습니다. 누구든 자료를 참조하여 함께 공부할 수 있습니다.

IX. 결론

 

지금까지 스마트 디스플레이를 제어하는 모든 단계를 설명하고, 다양한 컨트롤 방식도 제시하였습니다. 이 지식과 풍부한 상상력을 활용한다면 다양한 아이디어를 떠올리고 좀 더 다양한 제품을 생산할 수 있을 것이라고 생각합니다. 함께 스마트 디스플레이를 활용해 더 나은 미래를 만들어봅시다.

X. 참고 자료

 

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

XI. Sample source code

 

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

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

비즈니스에 맞는 디스플레이 솔루션에 관해 궁금한 점이 있으십니까? 문의!

구독

Winstar의 최신 소식을 전하는 이메일을 받아보세요.

문의

가격/데이터시트/일반 문의

기술 지원

각종 기술적인 정보가 궁금하시면 문의하세요.

go top
연계
close