ESP32/eModbus Library

eModbus

기하 2021. 8. 20. 01:43

 


https://emodbus.github.io/

Home

이것은 Modbus RTU 및 TCP 프로토콜 모두에 대해

Modbus 클라이언트(이전에는 마스터로 알려짐),

서버(이전에는 슬레이브) 및

브리지/게이트웨이 기능을 제공하는 라이브러리입니다.

 

Modbus 통신은 별도의 작업으로 수행되므로

Modbus 요청응답은 Non-blocking 입니다

응답을 비동기적으로 준비하거나 수신하기 위해 콜백이 제공됩니다.

 

요청응답이 도착하기를 기다리는 곳에서도 사용할 수 있는 동기 인터페이스가 있습니다.

 

주요 특징들:

  • Arduino 프레임워크에서 사용됨
  • 비차단/비동기 API -  non blocking / asynchronous API
  • 대체 동기 API
  • 서버, 클라이언트 및 브리지 모드
  • TCP(이더넷, WiFi 및 비동기) 및 RTU 인터페이스
  • ESP32용으로 설계되었으며 다양한 인터페이스가 지원됩니다. 
    비동기 버전은 ESP8266에서도 실행됩니다. Linux용 클라이언트 코드를 사용할 수 있습니다.
  • 모든 공통 및 사용자 정의 Modbus 표준 기능 코드

Requirements

라이브러리는 Arduino 핵심 개발 환경에서 ESP32 MCU용으로 개발되었습니다. 

원칙적으로 다음 리소스를 제공하는 모든 환경에서 실행되어야 합니다.

  • Arduino 핵심 함수 - Serial interfaces, millis(), delay() 등
  • FreeRTOS의 xTask task 함수. FreeRTOS를 실행하는 수많은 MCU가 있다는 점에 유의하십시오!
    비동기 버전은 ESP8266에서도 사용할 수 있습니다.
  • C++ 표준 라이브러리 구성 요소
    • std::queue
    • std::vector
    • std::list
    • std::map
    • std::mutex
    • std::lock_guard
    • std::forward
    • std::move
    • std::function
    • std::bind
    • std::placeholder

Modbus RTU의 경우 RS485-to-Serial 어댑터가 필요합니다. 

RS485MAX 어댑터 또는 자동 반이중 제어 기능이 있는 XY-017 어댑터가 사용됩니다. 

전압 레벨의 호환성을 확인하십시오.

 

Modbus TCP는 SPI 인터페이스에 연결된 WizNet W5xxx 시리즈와 같은

이더넷 모듈이나 (내부 또는 외부) WiFi 어댑터가 필요합니다. 

클라이언트 라이브러리는 Client.h에 정의된 기능만 사용하는 반면

서버 및 브리지 라이브러리는 내부적으로 Ethernet.h 또는 Wifi.h가 필요합니다. 

비동기 버전은 AsyncTCP 라이브러리에 의존합니다.

 

리눅스 클라이언트가 제공 않습니다 

Client와 IPAddress아두 이노 스타일의 요구 사항을 제공하는 클래스 있지만, TCP로 제한됩니다.

 

Installation

PlatformIO IDE 를 사용하는 것이 좋습니다 . 

당신의 프로젝트의 platformio.ini 파일에서

[env:...]섹션에 있는 lib_deps = entry에 이 라이브러리의 Github URL을 추가 하세요.

[platformio]
# some settings
[env:your_project_target]

# some settings
lib_deps = 
  ModbusClient=https://github.com/eModbus/eModbus.git

 

Arduino IDE를 사용하는 경우

라이브러리 폴더를 라이브러리 디렉토리에 복사하고 싶을 것입니다.

C:\Users\<user_name>\Documents\Arduino\libraries

Arduino IDE의 경우 연관 라이브러리 종속성을 수동으로 설치해야 합니다. 

 

ModbusMessage

 

기본적으로 라이브러리 내부를 오가는 모든 데이터는 

ModbusMessage객체의 형태를 가지고 있습니다. 

이 객체는 Modbus 표준 메시지의 모든 바이트(요청 또는 응답)를 포함하지만

사용된 인터페이스(RTU 또는 TCP)에 따라 달라지는 것은 없습니다. 

 

ModbusMessage는내부적으로 std::vector<uint8_t>이며

여러 측면에서 하나로 사용될 수 있습니다.

Error codes

Modbus 표준은 경우에 따라 응답으로 반환될 몇 가지 오류 코드를 정의합니다.

eModbus 라이브러리는 Modbus 메시지를 생성, 전송 또는 수신할 때 발생할 수 있는

다양한 조건을 설명하는 몇 가지 추가 코드로 이 목록을 확장합니다. 

eModbus의 오류 코드는 데이터 유형이 Error입니다

 

알려진 오류 코드는 아래 목록을 참조하십시오.

  • SUCCESS                              // 0x00, Successful operation, everything’s OK.
                                                 Modbus standard.
  • ILLEGAL_FUNCTION               // 0x01, “Illegal function code” - an invalid function code
                                                  was found. Modbus standard.
  • ILLEGAL_DATA_ADDRESS         // 0x02, “Illegal data address”: the register address given
                                                 does not fit the server. Modbus standard.
  • ILLEGAL_DATA_VALUE             // 0x03, “Illegal data value”: the data value provided is
                                                out of bounds for the requested purpose. Modbus standard.
  • SERVER_DEVICE_FAILURE         // 0x04, Modbus standard.
  • ACKNOWLEDGE                     // 0x05, Modbus standard.
  • SERVER_DEVICE_BUSY             // 0x06, Modbus standard.
  • NEGATIVE_ACKNOWLEDGE      // 0x07, NACK. Modbus standard.
  • MEMORY_PARITY_ERROR        // 0x08, Modbus standard.
  • GATEWAY_PATH_UNAVAIL      // 0x0A, Modbus standard.
  • GATEWAY_TARGET_NO_RESP   // 0x0B, Modbus standard.
  • TIMEOUT // 0xE0, a timeout has struck while waiting for a response etc.
  • INVALID_SERVER // 0xE1, the server ID is unknown or malformed.
  • CRC_ERROR // 0xE2, the Modbus message had a wrong checksum - only for Modbus-RTU
  • FC_MISMATCH // 0xE3, function code mismatch between request and the response
  • SERVER_ID_MISMATCH // 0xE4, server ID mismatch between request and response
  • PACKET_LENGTH_ERROR // 0xE5, the length as announced in the Modbus TCP header did not match the received length
  • PARAMETER_COUNT_ERROR // 0xE6, wrong # of parameters for the given function code
  • PARAMETER_LIMIT_ERROR // 0xE7, parameter out of bounds for the given function code
  • REQUEST_QUEUE_FULL // 0xE8, the request queue is completely filled, no more requests are accepted at this time
  • ILLEGAL_IP_OR_PORT // 0xE9, the IP address or port number given as target server are invalid
  • IP_CONNECTION_FAILED // 0xEA, IP connection to the given target host failed
  • TCP_HEAD_MISMATCH // 0xEB, transaction ID or protocol ID in the TCP request header did not match those of the response
  • EMPTY_MESSAGE // 0xEC, it was attempted to send an empty request message
  • UNDEFINED_ERROR // 0xFF, otherwise uncovered communication error 

 

ModbusMessage/The CoilData type

Modbus 표준의 일부는 디지털 입력 기능 코드에도 사용되는 코일 데이터 유형입니다. 

이 데이터 유형은 기본적으로 비트 집합이며 1 또는 0 만 값으로 갖습니다. 

이러한 값은 일반적으로 1= ON= true 또는 0= OFF=false 와 같이 해석 됩니다.

 

C++ 데이터 유형 bool이 Modbus coil과 거의 동일 합니다.

CoilData Type 으로 bool을  사용할 경우 경우 몇 가지 결함이 있습니다 .

  • bool 은 C++의 기본 저장 단위는 아니지만 항상 8 비트를 보유할 수 있지만 개별적으로 주소 를 지정할 수 는 없는 uint8_tor의 일부입니다 .bytebool
  • 따라서 boolC++ 에는 의 배열과 같은 것이 없으며 coilsModbus 세계에서는 의 배열과 같습니다 .
  • Modbus가 메시지로 전달해야 하는 코일 데이터의 순서는 C++에서 일반적으로 사용되는 순서와 반대입니다.

이러한 단점을 보완하기 위해 eModbus에 CoilData 유형이 추가되었습니다 .

사용 참고 사항

  •  eModbus와 함께 CoilDatae유형을 사용해야할 의무는 전혀 없습니다 . 
    원하는 경우 언제든지 코일의 고유한 표현을 사용할 수 있습니다.
  • 현재 구현은 베타 버전입니다. 철저하게 테스트되었지만 분명히 버그가 있을 것입니다!
  • 내부 코드는 현재 속도가 아닌 기능에 중점을 두고 있습니다. 앞으로 성능 향상을 위해 변경될 것입니다.

CoilData interface

생성자 
① CoilData(), 
② CoilData(uint16_t size) 
③ CoilData(uint16_t size, bool initValue)

 

① 매개 변수없이 생성된 CoilData 객체는 코일 용량이 0 이지만 다른 CoilData 객체 할당에 의해
    변경 될 수 있습니다. "bit image array"(아래 참조)에 의해서도 가능합니다.

② 두 번째 생성자는 정상적인 일반 생성자이며
    내부적으로 주어진 수의 코일을 위한 공간을 만듭니다. 
    이 크기는 Modbus 표준에 따라 2000개의 코일로 제한됩니다
    (표준 Modbus 메시지의 용량으로 인해 최대 255바이트만 가능).

③ 세 번째 형태는 현재 만드는 코일이 사전 설정된 값을 지정할 수 있습니다.
    initValue에 true 를 지정하면 모든 코일이 1로 세팅되며 false은 0으로 초기화 됩니다.

비트 이미지 배열 생성자 CoilData(const char *initVector)

또는 비트 이미지 배열로 CoilData 개체의 크기와 초기 값을 지정할 수 있습니다 . 
이는 0 또는 1의 문자를 순서대로 갖고있는 문자배열입니다. 

예를 들어  "11110000" 은 8-코일 비트 이미지 배열인데

생성자에서 사용될 때 객체에 8코일을 위한 공간을 할당하고

주어진   값을 순서대로 초기화합니다 .

  • 코일 0은 1
  • 코일 1은 1
  • 코일 2는 1
  • 코일 3은 1
  • 코일 4는 0
  • 코일 5는 0
  • 코일 6은 0
  • 코일 7은 0

참고 : 코일은 일반적으로 C++ 배열에서와 같이 0부터 시작하여 번호가 매겨집니다!

비트 이미지 배열에는  "1111 0000 1010 1101"처럼 공백 즉 무시되는 가시적 구조를 제공하는

다른 문자가 포함될 수 있습니다.

심지어 코멘트도 포함 할 수 잇습니다: "pump A=1, pump B=0, vent 34=1". 

당신이 코일 값으로 해석되어서는 안되는 0 또는 1을 코멘트에 추가하고자하면

_(밑줄)을 사용하면 됩니다.

"We have _16 coils here: 0101 1100 1110 0111"은
정확하게 16개의 코일을합니다 .

과제

CoilData객체는 서로에게 안전하게 할당될 수 있습니다. 원본 개체는 대상의 이전 데이터를 완전히 대체하며 이후에는 원본과 대상이 동일합니다.

CoilData가 사용할 수 있도록 유형은 C ++ 이동 패턴을 지원 CoilData등의 기능의 리턴 값으로 개체

CoilData전에 설명한 기능으로 객체는 이미지 비트 배열을 할당 할 수있다. 배열의 내용은 이전에 대상 개체에 있던 데이터도 완전히 대체합니다.

CoilData c(12); c = "0101 1111 0000 1010";

c16개의 코일 을 만들고 배열에 정의된 대로 초기화합니다.

비교 연산자

등호( ==) 및 부등식( !=) 비교 연산자는 CoilData객체를 다른 CoilData객체 또는 비트 이미지 배열과 비교하는 데 지원됩니다 .

CoilData c("11100"); CoilData d("11111111"); if (c == "11100"); // true! if (c != d); // true! if (d == c); // false! if (d != "11111111"); // false!

유형 변환

다음에 대한 두 가지 유형 변환 연산자가 있습니다 CoilData.

  • bool: bool컨텍스트 에서 사용되는 경우 객체는 true정의된 코일이 있는지 평가합니다 . 따라서 공백 CoilData이 false대신 반환 됩니다.
  • vector<uint8_t>: std::vector<uint8_t>객체에 할당된 경우 CoilData객체는 코일이 내부적으로 표시되는 순서대로 데이터 내용을 바이트 벡터로 반환합니다.

(재)초기화 완전한 코일을 1 또는 0으로 설정하고 void init(),void init(bool value)

init()호출을 사용하면 매개변수가 로 지정된 경우 CoilData객체의 모든 코일(있는 경우)  0또는 로 설정 됩니다 .1valuetrue

CoilData개체 에 대한 정보

이러한 호출은 개체의 내부 매개변수 값을 반환합니다.

uint16_t coils()

객체의 코일 용량을 반환합니다.

bool empty()

 true, 객체에 코일이 없으면 false입니다.

uint8_t size()

내부 버퍼의 크기를 바이트 수로 제공합니다. 와 함께

uint8_t *data()

내부 버퍼에 대한 포인터를 반환하면 코일 데이터를 고전적인 uint8_t배열 방식으로 사용하는 데 사용할 수 있습니다 .

uint16_t coilsSetON() 그리고uint16_t coilsSetOFF()

각각 1또는 로 설정된 객체의 코일 수를 반환합니다 0.

코일 값 읽기

bool operator[](uint16_t index)

배열 요소 연산자 []는 단일 코일의 값을 읽는 데 사용할 수 있습니다. (가) index의 코일 내에 있어야합니다 CoilData개체 - 다른, false반환됩니다. bool패킹된 바이트 의 개별 주소 지정 기능이 없기 때문에 이 연산자는 읽기 전용 입니다. 코일을 다른 값으로 설정하려면 아래의 코일 값 변경을 참조하십시오 .

다시 주의하십시오 : 코일 번호는 0에서 시작하며 가능한 가장 높은 코일 번호는 물체의 코일 크기 - 1입니다.

CoilData slice(uint16_t start, uint16_t length),
CoilData slice(uint16_t start)그리고
CoilData slice()

"슬라이스"는 CoilData다른 CoilData개체, 즉 복사본 과 같은 개체의 일부 또는 완전한 개체 입니다. 첫 번째 형식은 slice()시작할 첫 번째 코일 번호와 복사할 코일 수를 사용하고 두 번째 형식은 코일 수를 생략하면 소스의 시작부터 끝까지 모든 코일을 반환합니다 CoilData. 마지막 품종은 완전한 소스 코일 세트를 복사합니다.

슬라이스 CoilData자체이므로 의 모든 기능을 CoilData슬라이스에 적용할 수 있습니다.

uint16_t numberOfSetCoilsInSlice = myCoils.slice(4,7).coilsSetON(); // return all coils set to on within coils #4 to #10 myCoils.slice(1,8) = "11011100"; // will in fact work, but is senseless, because the copy is thrown away afterwards!

슬라이스는 Modbus 요청에 코일 값으로 응답하는 데 편리합니다. examples애플리케이션을 보려면 코드 디렉토리 의 TCPcoilsExample 을 참조하십시오.

는 IF start매개 변수가 범위를 벗어날의 인 CoilData목적, 또는이 length최대 코일 수를 초과 할 빈 CoilData객체가 반환됩니다.

코일 값 변경

코일 값은 set()호출 그룹에 의해 변경됩니다 . 단일 코일 값의 기본 변경 외에도 다양한 소스를 사용하여 하나 이상의 코일을 한 번에 새 값으로 설정할 수 있습니다. 시작 인덱스, 길이 또는 기타 데이터 속성 CoilData이 적용되는 개체 와 관련하여 잘못된 경우 set()작업이 실패하고 를 반환 false합니다. 변경이 성공하면 true대신 반환 값이 됩니다.

bool set(uint16_t index, bool value)

이 매우 기본적인 것은 set가 value가리키는 코일에 주어진 것을 씁니다 index.

bool set(uint16_t index, uint16_t length, vector<uint8_t> newValue)

 vector<uint8_t>벡터의 바이트의 비트 시퀀스 코일 값에 대한 소스로서 사용된다. 따라서 숫자 index가 있는 코일 은 벡터의 첫 번째 바이트의 비트 0으로 index+1설정되고 코일 은 동일한 바이트의 비트 1로 설정되는 식으로 length코일이 설정 될 때까지 계속 됩니다. 벡터에 모든 코일을 포함할 수 있는 몇 바이트가 포함되어 있으면 작업이 실패합니다.

bool set(uint16_t index, uint16_t length, uint8_t *newValue)

이전 호출과 유사하게 이것은 여러 개의 코일을 연속적으로 변경합니다. 값은 바이트의 비트 newValue에서 순서대로 가져옵니다 .

참고 : newValue포인터에 "자연스러운" 끝 표시가 없기 때문에 길이에 대한 잘못된 값으로 인해 데이터가 의도한 영역을 벗어난 코일 값으로 사용될 수 있습니다! 따라서 포인터와 길이가 올바른지 다시 확인하는 것이 좋습니다.

 set()변형은 CoilData0x0F "WRITE_MULT_COILS" 요청과 함께 오는 Modbus 메시지에서 읽은 값 으로 변경 하는 데 유용합니다 .

bool set(uint16_t index, const CoilData& c)

이 호출은 지정된 CoilData객체 의 코일을 c코일 번호에서 시작하여 대상에 씁니다 index. 코일 c은 #0부터 가져옵니다. 앞에서 설명한 두 가지 호출과 달리 여기에서는 CoilData관련된  개체 의 크기에 관계없이 복사본이 만들어집니다 .

  • 소스가 사용 가능한 대상 공간보다 크면 복사는 대상의 가장 마지막 코일에서 중지됩니다.
  • 사용 가능한 대상 공간보다 짧은 소스 코일 세트는 완전히 복사되고 나머지 대상 코일은 그대로 유지됩니다.
  • 소스가 비어 있으면 CoilData아무 것도 변경되지 않습니다.

CoilData A("1111 1111 1111 1111"); CoilData B("0011 0011"); A.set(8, B); // A is "1111 1111 0011 0011" now! B.set(4, A); // B is "0011 1111" now

bool set(uint16_t index, const char *initVector)

이 마지막 항목 set()은 위에서 설명한 대로 비트 이미지 배열에서 가져온 새 코일 값을 제외하고 이전 항목과 유사합니다. 하지만 동일한 규칙이 적용됩니다. 너무 긴 배열은 마지막 피팅 값까지만 복사되고 더 짧은 배열은 나머지가 변경되지 않은 상태로 남습니다.

디버그 도우미

때때로 16진 덤프나 일반 숫자 출력에서 ​​주어진 코일 세트의 값이 무엇인지 보기가 어렵습니다. CoilData개체 의 모든 코일을 멋지게(글쎄, 일종의...) 형식화된 방식으로 인쇄하는 도우미 기능이 있습니다 .

void print(const char *label, Print& s)

label원하는 대로 선택할 수 있으며 초기 에 값 앞에 인쇄됩니다. s참조는 가리된다 Print이 대부분이 될 것입니다 - 타입의 객체 Serial표준 모니터 출력. 출력은 아래와 같이 보일 것입니다. Coil index설명을 위해 여기에 추가  줄은 myCoils.print("Initial coil state", Serial);마지막 줄만 담당합니다.

Coil index 0 4 8 12 16 20 24 28 32 | | | | | | | | | Initial coil state: 0001 0111 0000 0110 0000 0000 0000 1011 010

참고 : 이 기능은 Linux에서는 사용할 수 없습니다. 와 같은 개념이 없기 때문 Print입니다. 이는 Arduino 환경의 일부일 뿐입니다!

 

ModbusMessage constructors

ModbusMessage는  여러 생성자 중 하나로 생성됩니다. 가장 첫 번째는 기본입니다.

 

ModbusMessage() 또는 ModbusMessage(uint16_t dataLen)

이는 빈 ModbusMessage인스턴스를  생성합니다 . 

두 번째 형식은 dataLen 매개변수를 사용하여 주어진 바이트 수를 할당하는 것입니다. 

사전 할당된 메모리가 충분한 한 내부적으로 재할당이 수행되지 않기 때문에

인스턴스 사용 속도를 높일 수 있습니다.

 

모든 추가 생성자는 ModbusMessage를 정의된 Modbus 메시지로 채울 것 입니다.

 

ModbusMessage(uint8_t serverID, uint8_t functionCode)

이것은 0x07, 0x0B, 0x0C 및 0x11과 같이 추가 매개변수가 필요하지 않은 Modbus 기능 코드에 대한 Modbus 표준 메시지를 설정하는 데 사용할 수 있습니다.

다른 수의 매개변수를 사용하는 잘못된 서버 ID 또는 Modbus 표준 기능 코드를 지정하는 경우 오류 메시지가 전송되고 Serial메시지가 생성되지 않습니다.

이는 이 그룹의 모든 생성자에 적용됩니다. 알려진 표준 Modbus 메시지에 대한 매개변수는 적합성을 확인합니다.

으로functionCode 당신은 숫자 값 또는 미리 정의 된 상수의 이름 중 하나를 지정할 수 있습니다

 

 

생략 나중추가

 


                           Modbusclient                                       

1. 시작하고 실행하려면 코드에 몇 줄만 넣으면 됩니다. 

   먼저 일치하는 헤더 파일을 포함해야 합니다.

#include "ModbusClientRTU.h"

2. ModbusClientRTU의 경우 RS485 어댑터에 연결하는 직렬 인터페이스가 필요합니다. 

  이것은 ModbusClientRTU 생성자 에 대한 매개변수로 제공됩니다 . 

  반이중을 사용하기 위해 선택적 핀을 제공할 수 있습니다.

ModbusClientRTU RS485(Serial2);          // for auto half-duplex
ModbusClientRTU RS485(Serial2, rtsPin);  // use rtsPin to toggle DE/RE in half-duplex

3. 다음으로 들어오는 데이터 응답에 대한 콜백 함수를 정의합니다.

   이 예제에서는 범위 반복자를 사용하여 응답 데이터의 16진수 덤프를 인쇄합니다.

void handleData(ModbusMessage msg, uint32_t token) 
{
  Serial.printf("Response: serverID=%d, FC=%d, Token=%08X, length=%d:\n", msg.getServerID(), msg.getFunctionCode(), token, msg.size());
  for (auto& byte : msg) {
    Serial.printf("%02X ", byte);
  }
  Serial.println("");
}

 

선택적으로 오류 응답이 수신될 때 호출될 다른 콜백을 정의할 수 있습니다. 

콜백은 Error 을 반환할 것이며 사람이 읽을 수 있는 형식 ModbusError 로 변환하여 주어집니다.

void handleError(Error error, uint32_t token) 
{
  // ModbusError wraps the error code and provides a readable error message for it
  ModbusError me(error);
  Serial.printf("Error response: %02X - %s\n", error, (const char *)me);
}

이제 우리는 setup()함수 에서 모든 것을 모을 것입니다 :

void setup() {
  // Set up Serial2 connected to Modbus RTU
Serial2.begin(19200, SERIAL_8N1);

  // Set up ModbusClientRTU client.
  // - provide onData and onError handler functions
RS485.onDataHandler(&handleData);
RS485.onErrorHandler(&handleError);

  // Start ModbusClientRTU background task
RS485.begin();
}

 

다음은 request을 시작합니다. 
아래 코드에서 "read holding register" 요청이 서버 id로 전송되어 

주소 10에서 하나의 데이터 워드를 요청합니다. 

지금은 token 값 0x12345678는 무시하십시오. 아래에서 자세히 설명합니다.

Error err = RS485.addRequest(0x12345678, 1, READ_HOLD_REGISTER, 10, 1);
  if (err!=SUCCESS) {
    ModbusError e(err);
    Serial.printf("Error creating request: %02X - %s\n", err, (const char *)e);
  }

 

이 메서드는 당신의 요청과 리턴값을 모두 큐에 넣

매개변수에 문제가 있거나 대기열(큐)가 가득 찬 경우 요청이 생성되지 않습니다. 

무엇이 잘못되었는지 알아보기 위해 오류 반환 값이 제공됩니다. 

모든 것이 정상인 경우 요청이 생성되어 처리할 백그라운드 큐에 넣습니다. 

응답 시 귀하 handleData 또는 handleError콜백이 호출됩니다.

 

ModbusClient Common API

내부적으로 요청 및 응답에 대한 Modbus 메시지 내용은

프로토콜이 요구하는 요소와 별도로 보관됩니다. 

따라서 몇 가지 API 요소는 두 프로토콜 모두에 공통입니다.

bool onDataHandler(MBOnData handler)

응답 수신 시 호출할 콜백 함수를 등록하는 인터페이스입니다. 유일한 매개변수는 다음 서명이 있는 함수에 대한 포인터입니다.

void func(ModbusMessage msg, uint32_t token);

  • msg: 응답 메시지 수신
  • token: 이것은 라이브러리 전반에 걸친 일반적인 개념입니다. 아래를 참조하십시오.

메모

핸들러는 한 번만 요청할 수 있습니다. 이전에 이미 수행된 경우 후속 호출에서 false값을 반환 합니다.

token개념

각 요청에는 사용자 정의 token값 이 제공되어야 합니다 . 이 토큰은 각 요청과 함께 저장되고 콜백에서 반환됩니다. 토큰에 대한 어떠한 처리도 수행되지 않으며, 귀하가 제공한 것을 받게 됩니다. 이를 통해 사용자는 응답을 수신할 때 전송된 요청을 추적할 수 있습니다.

여러 ModbusClient가 작동하는 응용 프로그램을 상상해보십시오. 일부는 전용 TCP Modbus 서버용, 다른 하나는 RS485 RTU Modbus용, 또 다른 하나는 다른 TCP 서버를 요청하기 위한 것입니다.

응답을 보낸 서버에 관계없이 모든 응답을 처리하는 단일 onData 및 onError 함수만 갖고 싶다면 하나의 응답을 다른 응답과 구별할 수단이 필요합니다.

응답이 정확히 해당 토큰을 반환하므로 요청 시 제공한 토큰을 통해 알 수 있습니다.

bool onErrorHandler(MBOnError handler)

onDataHandler호출 과 매우 유사 하며 콜백 함수로 모든 오류 응답을 포착할 수 있습니다.

메모

엄격하게되지 필요한 등록 오류 콜백을 가지고. 그러나 아무 것도 없으면 오류가 눈에 띄지 않게됩니다!

onErrorhandler호출은 다음과 같은 서명 함수 포인터를 받아 들인다 :

void func(Error errorCode, uint32_t token);

매개변수는

  • errorCode요청한 서버가 생성  오류
  • token값으로서 기재에 onDataHandler상기 부.

라이브러리는 ModbusError모든 Error코드 로 할당하거나 초기화할 수 있는 별도의 래퍼 클래스  제공하며 const char *컨텍스트 에서 사용되는 경우 사람이 읽을 수 있는 오류 텍스트 메시지를 생성합니다 . 적용 방법은 기본 사용 예 에서 참조하십시오 .

bool onResponseHandler(MBOnResponse handler)

onDataHandler/ onErrorHandler쌍을 사용하는 대신 onResponseHandler데이터 또는 오류에 관계없이 모든 응답 메시지에 대해 호출 되는 단일 을 제공할 수 있습니다 . 의 기능 서명 onResponseHandler은

void func(ModbusMessage msg, uint32_t token);

onResponseHandler패턴을 사용할 때 제공한 콜백 onDataHandler또는 onErrorHandler콜백은 더 이상 유효하지 않습니다!

오류 응답에서 데이터를 알리려면 ModbusMessage 에서 getError()호출을 사용해야 합니다 msg. 데이터 응답과 Error다른 코드 와 함께 SUCCESS를 반환 합니다.

uint32_t getMessageCount()

성공적으로 대기열에 넣은 각 요청이 계산됩니다. 전화 getMessageCount()를 걸면 지금까지 누적된 번호를 읽을 수 있습니다.

이 개수는 인스턴스에 따라 다르므로 생성한 각 ModbusClient 인스턴스에는 고유한 개수가 있습니다.

void begin(),
void begin(int coreID)및
void begin(int coreID, uint32_t interval)(RTU만 해당)

이것은 ModbusClient 인스턴스가 작동하도록 하는 가장 중요한 호출입니다. 요청 대기열을 열고 대기 중인 요청을 처리하기 위해 백그라운드 작업자 작업을 시작합니다.

두 번째 형식을 begin()사용하면 작업자 작업을 실행할 CPU 코어를 선택할 수 있습니다(ESP32와 같은 멀티 코어 시스템에서만). 이것은되는 추천 을 위해 특히 ModbusClientRTURS485 모드 버스의 처리는 시간이 중요하며 자신의 핵심 실행하는 데에서 이익이되므로, 클라이언트.

세 번째 형식은 메시지 끝 상태를 감지하기 위해 메시지 사이에 허용 가능한 시간을 늘리는 방법을 추가합니다. interval끝의 메시지가 가정 될 때까지 변수를 지정 밀리 초 대기. 이것은 느리게 반응하는 서버에 유용할 수 있지만 이것은 엄격히 말해서 Modbus 표준을 위반한다는 점에 유의하십시오!

메모

작업자 작업은 영원히 또는 이를 시작한 ModbusClient 인스턴스가 종료될 때까지 실행됩니다. 소멸자는 대기열에 있는 모든 요청을 처리하고 제거한 다음 실행 중인 작업자 작업을 중지합니다.

요청 설정

비동기 요청(비차단)

모든 인터페이스 addRequest()는 요청을 설정하고 대기열에 넣는 공통 메소드 세트를 제공합니다 .  장에 설명된 호출 addRequest()과 매우 유사한 7 가지 변형이 있습니다 . 내부적으로 정확히 이러한 호출은 이러한 함수에서 사용됩니다 . 의 주요 차이점 은 메시지 매개변수 앞에 첫 번째 인수로 제공되는 추가 매개변수입니다.ModbusMessage.setMessage()ModbusMessagesetMessage()addRequest()setMessage()Token

그래서 우리는 다음을 가지고 있습니다:

  1. Error addRequest(uint32_t token, uint8_t serverID, uint8_t functionCode);
  2. Error addRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1);
  3. Error addRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2);
  4. Error addRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint16_t p3);
  5. Error addRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint8_t count, uint16_t *arrayOfWords);
  6. Error addRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint8_t count, uint8_t *arrayOfBytes);
  7. Error addRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t count, uint8_t *arrayOfBytes);

다시 말하지만, addRequest()이번에는 미리 포맷된 8번째 가 있습니다 ModbusMessage.

  1. Error addRequest(ModbusMessage request, uint32_t token);

메모

메서드 token의 내부 처리에 필요한 이 호출 에서 매개변수 의 다른 위치에 유의하십시오 addRequest().

동기 요청(응답 대기)

addRequest()앞에서 설명한 것처럼 각각 에는 동기식 syncRequest()펜던트가 있습니다. 생성한 것과 동일한 요청을 설정 addRequest()하고 서버로 보내는 데 사용할 수 있습니다 .

syncRequest()호출은 서버의 응답이 수신 될 때까지 기다렸다가 호출자에게 그 반환합니다 :

  1. ModbusMessage syncRequest(uint32_t token, uint8_t serverID, uint8_t functionCode);
  2. ModbusMessage syncRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1);
  3. ModbusMessage syncRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2);
  4. ModbusMessage syncRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint16_t p3);
  5. ModbusMessage syncRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint8_t count, uint16_t *arrayOfWords);
  6. ModbusMessage syncRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t p1, uint16_t p2, uint8_t count, uint8_t *arrayOfBytes);
  7. ModbusMessage syncRequest(uint32_t token, uint8_t serverID, uint8_t functionCode, uint16_t count, uint8_t *arrayOfBytes);
  8. ModbusMessage syncRequest(ModbusMessage request, uint32_t token);

60초의 최종 시간 초과가 있지만 그 이후에는 어떤 경우에도 호출이 반환되고 물론 TIMEOUT 오류 메시지가 표시됩니다.

동기 호출은 일반적으로 호출이 끝날 때까지 동기화 호출을 사용하는 태스크(또는 스레드)에서 수행할 수 있는 다른 작업이 없기 때문에 작은 단일 태스크 MCU에서 사용하기에 적합하지 않다는 점에 유의해야 합니다. 물론 이를 지원하는 MCU의 다른 병렬 작업은 영향을 받지 않습니다.