Modbus

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Modbus

Непрочитанное сообщение Olej » 28 июл 2019, 22:35

В одной из работ возникла необходимость связи Linux с специальным контроллером по Modbus через RS-232 (или через преобразователь USB <-> RS-232).

Последний раз я работал с Modbus RTU & Modbus TCP ... лет 15 назад, или чуть больше...
Начинаем разбираться по-новой и что там за это время произошло.

P.S. Кроме того, по этому проекту работа с Modbus должна осуществляться из Python 3.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 28 июл 2019, 22:37

Спецификация: MODBUS over Serial Line Specification and Implementation Guide V1.02.
MODBUS over serial line specification and implementation guide V1.02
...
Dec 20, 2006
44 стр.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 29 июл 2019, 00:14

Olej писал(а):Спецификация: MODBUS over Serial Line Specification and Implementation Guide V1.02.
Один из вопросов, который мне задал ... "мой" разработчик специализированного контроллера:
меня интересует - на каком полиноме у Вас будет вычисляться CRC16? Я обычно использую 0х10281.
Начинаем разбираться...

Циклический избыточный код
Name Width Poly Init RefIn RefOut XorOut Check
...
CRC-16/MODBUS 16 0x8005 0xFFFF true true 0x0 0x4B37
Популярные и стандартизованные полиномы
Название Полином Представления: нормальное / реверсированное / реверсированное от обратного
...
CRC-16-IBM (Bisync, Modbus, USB, ANSI X3.28, многие другие; также известен как CRC-16 и CRC-16-ANSI) 0x8005 / 0xA001 / 0xC002
Стандартизованные полиномы
Название Полином Представления: нормальное / реверсированное / реверсированное от обратного
...
CRC-16-IBM (Bisync, Modbus, USB, ANSI X3.28[20], многие другие; также известен как CRC-16 и CRC-16-ANSI) 0x8005 / 0xA001 / 0xC002
Т.е. оказывается как минимум 3 разных порождающих полинома, которые при разных алгоритмах вычисления дают одно и то же CRC16.
Для используемой для тестирования последовательности байт "123456789" все они должны давать CRC16 = 0x4B37.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 29 июл 2019, 00:30

Olej писал(а):Для используемой для тестирования последовательности байт "123456789" все они должны давать CRC16 = 0x4B37.
Из разных источников, я нашёл и значительно трансформировал коды-алгоритмы для 2-х первых полиномов, нормального - 0x8005 и реверсированного - 0xA001 (для третьего варианта полинома - 0xC002 - реализации мне не попадались ... да я и не сильно искал).

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ cat crc_modbus.c 
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>

uint16_t const crcinit = 0xFFFF;

uint16_t crc_revr( const unsigned char* p, unsigned long lenght, uint16_t polynom ) {
    uint16_t crc = crcinit, bit;
    for( unsigned long i = 0; i < lenght; i++ ) {
        crc ^= (uint16_t)*p++;
        for( int j = 0; j < 8; j++ ) {
            bit = crc & 0x0001;
            crc >>= 1;
            if( bit ) crc ^= polynom;
        }
    }
    return crc;
}

unsigned long reflect( unsigned long crc, int bitnum ) { // зеркально отобразить биты
	unsigned long i, j = 1, crcout = 0;
	for ( i = (unsigned long)1 << ( bitnum - 1 ); i; i >>= 1 ) {
		if( crc & i ) crcout |= j;
		j <<= 1;
	}
	return crcout;
}

uint16_t crc_norm( const unsigned char* p, unsigned long lenght, uint16_t polynom ) {
	unsigned long crc = crcinit; 
	for( unsigned long i = 0; i < lenght; i++ ) {        
        uint16_t c = reflect( (unsigned long)*p++, 8 );
		for( uint16_t j = 0x80; j; j >>= 1 ) {
			uint16_t bit = crc & 0x8000;
			crc <<= 1;
			if( c & j ) bit ^= 0x8000;
			if( bit ) crc^= polynom;
		}
	}	
    crc = reflect( crc, 16 );
    return crc;
}

uint16_t ( *crc_fun[] )( const unsigned char*, unsigned long, uint16_t ) =
    { crc_norm, crc_revr };
uint16_t polynom[] = { 0x8005, 0xA001 };

int main( int argc, char *argv[] ) {
    unsigned char string[ 800 ] = "123456789"; 
    bool bStr = true;
    if( argc > 1 )
        if( strcmp( argv[ 1 ], "-" ) != 0 )             // параметр из команды 
            strcpy( string, argv[ 1 ] );
        else { 
            if( isatty( 0 ) ) {                         // проверка на терминал 
                printf( "> " );
                fflush( stdout );
                fgets( string, sizeof( string ) - 1, stdin );
                string[ strlen( string ) - 1 ] = '\0';  // удалить '\n'
            }
            else {                                      // чтение из конфейера
                bStr = false;
                string[ 0 ] = '\0'; 
                char s[ 160 ];
                while( 1 ) 
                    if( fgets( s, 160, stdin ) ) 
                        strcat( string, s );
                    else break;
            }
        }
    for( int i = 0; i < sizeof( crc_fun ) / sizeof( crc_fun[ 0 ] ); i++ )
        if( bStr )
            printf( "%X : %s -> %X\n", polynom[ i ], string,
                    crc_fun[ i ]( string, strlen( string ), polynom[ i ] ) );
        else 
            printf( "%X : [%d] -> %X\n", polynom[ i ], strlen( string ),
                    crc_fun[ i ]( string, strlen( string ), polynom[ i ] ) );    
}

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ gcc crc_modbus.c -o crc_modbus

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ ./crc_modbus
8005 : 123456789 -> 4B37
A001 : 123456789 -> 4B37

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ ./crc_modbus -
> 123456789
8005 : 123456789 -> 4B37
A001 : 123456789 -> 4B37

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ ./crc_modbus 123456789
8005 : 123456789 -> 4B37
A001 : 123456789 -> 4B37

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ hexdump 2_7_.dat 
0000000 0702 0000                              
0000003

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ xxd 2_7_.dat 
00000000: 0207 00                                  ...

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ cat 2_7_.dat | ./crc_modbus -
8005 : [2] -> 1241
A001 : [2] -> 1241

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ hexdump -b 123456789.dat 
0000000 061 062 063 064 065 066 067 070 071                            
0000009

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ cat 123456789.dat | ./crc_modbus -
8005 : [9] -> 4B37
A001 : [9] -> 4B37
Вложения
crc_modbus.c
(2.66 КБ) 81 скачивание

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 29 июл 2019, 00:44

Или в упрощённом для понимания варианте:

- нормальное представление полинома:

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ cat crc20.c
#include <stdint.h>
#include <string.h>
#include <stdio.h>

const unsigned char *string = "123456789";   // Data character string
const uint16_t polynom = 0x8005;
const uint16_t crcinit = 0xFFFF;

unsigned long reflect( unsigned long crc, int bitnum ) { // зеркально отобразить биты
	unsigned long i, j = 1, crcout = 0;
	for ( i = (unsigned long)1 << ( bitnum - 1 ); i; i >>= 1 ) {
		if( crc & i ) crcout |= j;
		j <<= 1;
	}
	return crcout;
}

uint16_t crc_norm( const unsigned char* p, unsigned long lenght ) {
	unsigned long crc = crcinit; 
	for( unsigned long i = 0; i < lenght; i++ ) {
        uint16_t c = reflect( (uint16_t)*p++, 8 );
		for( uint16_t j = 0x80; j; j >>= 1 ) {
			uint16_t bit = crc & 0x8000;
			crc <<= 1;
			if( c & j ) bit ^= 0x8000;
			if( bit ) crc^= polynom;
		}
	}	
    crc = reflect( crc, 16 );
	return crc;
}

int main() {
    printf( "%X : %s -> %X\n", polynom, string, crc_norm( string, strlen( string ) ) );
}

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ ./crc20
8005 : 123456789 -> 4B37
- реверсированное представление полинома:

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ cat crc10.c
#include <stdint.h>
#include <string.h>
#include <stdio.h>

const unsigned char* string = "123456789";   // Data character string
const uint16_t polynom = 0xA001;
const uint16_t crcinit = 0xFFFF;

uint16_t crc_revr( const unsigned char* p, unsigned long lenght ) {
    uint16_t crc = crcinit, bit;
    for( unsigned long i = 0; i < lenght; i++ ) {
        crc ^= (uint16_t)*p++;
        for( int j = 0; j < 8; j++ ) {
            bit = crc & 0x0001;
            crc >>= 1;
            if( bit ) crc ^= polynom;
        }
    }
    return crc;
}

int main() {
   printf( "%X : %s -> %X\n", polynom, string, crc_revr( string, strlen( string ) ) );
}

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/WaterBiz/Modbus/CRC16.c$ ./crc10
A001 : 123456789 -> 4B37
Вложения
crc20.c
(966 байт) 72 скачивания
crc10.c
(648 байт) 75 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 29 июл 2019, 01:55

Olej писал(а): Один из вопросов, который мне задал ... "мой" разработчик специализированного контроллера:
меня интересует - на каком полиноме у Вас будет вычисляться CRC16? Я обычно использую 0х1021.
В отношении кода 0х1021 ...

https://ru.wikipedia.org/wiki/Циклическ ... точный_код

Код: Выделить всё

Name	Width	Poly	Init	RefIn	RefOut	XorOut	Check
...
CRC-16/AUG-CCITT	16	0x1021	0x1D0F	false	false	0x0	0xE5CC
CRC-16/CCITT-FALSE	16	0x1021	0xFFFF	false	false	0x0	0x29B1
CRC-16/GENIBUS		16	0x1021	0xFFFF	false	false	0xFFFF	0xD64E
CRC-16/MCRF4XX		16	0x1021	0xFFFF	true	true	0x0	0x6F91
CRC-16/RIELLO		16	0x1021	0xB2AA	true	true	0x0	0x63D0
CRC-16/TMS37157		16	0x1021	0x89EC	true	true	0x0	0x26B1
CRC-A			16	0x1021	0xC6C6	true	true	0x0	0xBF05
CRC-16/KERMIT		16	0x1021	0x0	true	true	0x0	0x2189
CRC-16/X-25		16	0x1021	0xFFFF	true	true	0xFFFF	0x906E
CRC-16/XMODEM		16	0x1021	0x0	false	false	0x0	0x31C3
https://www.turkaramamotoru.com/ru/Цикл ... 43206.html
Название Полином Представления: нормальное / реверсированное / реверсированное от обратного
...
CRC-16-CCITT (X.25, HDLC, XMODEM, Bluetooth, SD и др.) 0x1021 / 0x8408 / 0x8810
1). Полином 0х1021 действительно широко применяется для разных CRC16 ... но CRC16 отличных от Modbus.
2). ... в очень разных модификациях параметров алгоритма:
- Стартовые данные (init), то есть значения регистров на момент начала вычислений;
- Флаг (RefIn), указывающий на начало и направление вычислений. Существует два варианта: False — начиная со старшего значащего бита (MSB-first), или True — с младшего (LSB-first);
- Флаг (RefOut), определяющий, инвертируется ли порядок битов регистра при входе на элемент XOR;
- Число (XorOut), с которым складывается по модулю 2 полученный результат;
- Значение CRC (check) для строки «123456789» .
3). и имеет 3 альтернативных значения в зависимости от направления вычисления (алгоритма): 0x1021 / 0x8408 / 0x8810.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 29 июл 2019, 15:42

Olej писал(а):Спецификация: MODBUS over Serial Line Specification and Implementation Guide V1.02.
MODBUS over serial line specification and implementation guide V1.02
...
Dec 20, 2006
44 стр.
Ещё один основополагающий документ - MODBUS APPLICATION PROTOCOL SPECIFICATION
V1.1b3
...
April 26, 2012
50 стр.
The size of the MODBUS PDU is limited by the size constraint inherited from the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256 bytes).
Therefore:
MODBUS PDU for serial line communication = 256 - Server address (1 byte) - CRC (2 bytes) = 253 bytes.
Consequently:
RS232 / RS485 ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256 bytes.
TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
P.S. Оба документа - в формате PDF.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 29 июл 2019, 20:06

Olej писал(а):P.S. Кроме того, по этому проекту работа с Modbus должна осуществляться из Python 3.
Теперь с инструментарием Python под Modbus...

Код: Выделить всё

olej@ACER:~$ aptitude search modbus
i   libmodbus-dev                                                            - development files for the Modbus protocol library                                 
i A libmodbus5                                                               - library for the Modbus protocol                                                   
p   python-pymodbus                                                          - full Modbus protocol implementation for Python 2                                  
i   python-pymodbus-doc                                                      - full Modbus protocol implementation, documentation                                
v   python2.7-pymodbus                                                       -                                                                                   
i   python3-pymodbus                                                         - full Modbus protocol implementation for Python 3                                  

Код: Выделить всё

olej@ACER:~$ pip3 search modbus
modbus (3.2)                     - Modbus TCP Server and Client Programs
bubot-Modbus (0.0.1)             - Modbus bridge for Bubot
exoedge-modbus (19.7.26)         - An ExoEdge source for interfacing with Modbus devices.
ebs-modbus (1.2.0)               - Python host interface to EBS modbus devices
chirp-modbus (1.0.0rc1)          - A wrapper library for communicatin with Modbus based Chirp soil moisture sensor
aio-modbus-client (0.0.3)        - Easy work with modbus device. You do not need to know the protocol.
bubot-ThermostatSML1000 (0.0.1)  - Modbus bridge for Bubot
cpymodbus (0.1dev)               - Modbus slave package
MinimalModbus (0.7)              - Easy-to-use Modbus RTU and Modbus ASCII implementation for Python
EasyModbus (1.2.6)               - THE standard library for Modbus RTU and Modbus TCP - See www.EasyModbusTCP.NET for documentation
modbus_tk (1.0.0)                - Implementation of modbus protocol in python
volcano-mbsrv (1.1.10)           - Modbus server satellite for Volcano
sdm-collector (1.0.3)            - Eastron SDM120 Modbus collector
pyModbusTCP (0.1.8)              - A simple Modbus/TCP library for Python
DomotApiModbus (0.4.0)           - Working with modbus devices in domot-api
pyModSlave (0.4.2.1)             - A modbus RTU/TCP slave application
uModbus (1.0.2)                  - Implementation of the Modbus protocol in pure Python.
modpypes (0.2.12)                - Python library for MODBUS based on BACpypes
uModbus-extended (1.0.4)         - Implementation of the Modbus protocol in pure Python.
pymodbus3 (1.0.0)                - A fully featured modbus protocol stack in python
pysmarty (0.8)                   - Python API for Salda Smarty Modbus TCP
bfabio.pymodbus (1.3.1)          - A fully featured modbus protocol stack in python
ccatterina.pymodbus (1.5.2.1)    - A fully featured modbus protocol stack in python
pymodbus (2.2.0)                 - A fully featured modbus protocol stack in python
  INSTALLED: 2.1.0
  LATEST:    2.2.0
modbus_cli (0.1.3)               - Command line tool to access Modbus devices
nrgmodbus (0.1.6)                - library for making modbus connections to NRG Systems devices.
python-airzone (0.1.0)           - Python library for interfacing with Airzone using the modbus protocol
renogy-rover (0.0.1)             - MODBUS Driver for the Renogy Rover 20A/40A Charge Controller
Tolk (0.2.1)                     - JSON-RPC proxy for talking Modbus over RTU and TCP.
modbusreader (1.0.5)             - Read values of a modbus server automatically based on a defined config
GroMaster (0.0.2)                - modbus lib for Growatt to get data and set data easily.
pyusbmodule (0.1.7)              - Python interface to expansion modules via USB-Modbus/UART connection
CI_CloudConnector (0.55)         - IOT application that collect data from PLC (ModBus or AnB Ethernet/IP) and send to cloud using https
CI_LocalConnector (0.18)         - IOT application that collect data from PLC (ModBus or AnB Ethernet/IP) and send to cloud using https
pystiebeleltron (0.0.1.dev2)     - Python API for interacting with the Stiebel Eltron ISG web gateway via Modbus for controlling integral ventilation units and
                                   heat pumps.
IOT-GD (1.0.8)                   - IoT. You can read moacon modules (Modbus communication - cubloc.com) and mcp3208 - 8 channel 12Bit ADC from Rpi 3 and
                                   others.
modbusStructConvert (1.0)        - modbus&#23492;&#23384;&#22120;&#20540;&#19982;&#21487;&#35835;&#20540;&#20043;&#38388;&#36827;&#34892;&#36716;&#25442;,&#259
                                   03;&#25345;&#21508;&#31181;&#23492;&#23384;&#22120;&#22320;&#22336;&#39034;&#24207;

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 29 июл 2019, 20:19

[quote="Olej"]
Теперь с инструментарием Python под Modbus...

Код: Выделить всё

olej@ACER:~$ aptitude search modbus
...
p   python-pymodbus                                                          - full Modbus protocol implementation for Python 2                                  
...
i   python3-pymodbus                                                         - full Modbus protocol implementation for Python 3                                  

Код: Выделить всё

olej@ACER:~$ pip3 search modbus
...
modbus_tk (1.0.0)                - Implementation of modbus protocol in python
...
uModbus (1.0.2)                  - Implementation of the Modbus protocol in pure Python.
...
[/quote]
На сайте Modbus, страница [url=http://www.modbus.org/tech.php]Modbus Technical Resources[/url] (первоисточник) упоминаются 2 Python реализации: uModbus + modbus_tk, с их кратким описанием + GIT исходниками: [url=https://github.com/AdvancedClimateSystems/uModbus/]uModbus[/url] + [url=https://github.com/ljean/modbus-tk]modbus-tk[/url].
Но я их из GIT не стану устанавливать, если есть в стандартном репозитории PIP.

P.S. Пакет python3-pymodbus был как-то мной подобран и установлен ранее...
Вот на этих 3-х пока и остановлюсь...

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Modbus

Непрочитанное сообщение Olej » 29 июл 2019, 20:28

Olej писал(а): Но я их из GIT не стану устанавливать, если есть в стандартном репозитории PIP.
Но их нужно установить:

Код: Выделить всё

olej@ACER:~$ sudo pip3 install uModbus
Collecting uModbus
  Downloading https://files.pythonhosted.org/packages/9d/ef/a575ba0840854b937ab7e5c6c4b40c4491089e42114a9b4413e87a84b2a8/uModbus-1.0.2.tar.gz
Requirement already satisfied: pyserial~=3.4 in /usr/lib/python3/dist-packages (from uModbus) (3.4)
Building wheels for collected packages: uModbus
  Building wheel for uModbus (setup.py) ... done
  Created wheel for uModbus: filename=uModbus-1.0.2-py2.py3-none-any.whl size=26098 sha256=16c1e7a33648a29353bde04120392de6c220b319d13b8f50c06872474e05c261
  Stored in directory: /root/.cache/pip/wheels/61/8b/06/4b3c843878892f19375c9234b4857b80cdf8047e39f3f2d715
Successfully built uModbus
Installing collected packages: uModbus
Successfully installed uModbus-1.0.2

olej@ACER:~$ sudo pip3 install uModbus-extended
Collecting uModbus-extended
  Downloading https://files.pythonhosted.org/packages/a0/3e/30173819d83e0dbc8829ae67313d3d5cdd39ee5628e56063a049b3df41ed/uModbus_extended-1.0.4-py2.py3-none-any.whl
Requirement already satisfied: pyserial~=3.4 in /usr/lib/python3/dist-packages (from uModbus-extended) (3.4)
Installing collected packages: uModbus-extended
Successfully installed uModbus-extended-1.0.4

Код: Выделить всё

olej@ACER:~$ sudo pip install modbus_tk
Collecting modbus_tk
  Downloading https://files.pythonhosted.org/packages/8b/03/50193a66aac4eeccbaecea22044de6f07f4e8bfcb6ec37d724a0bba50f46/modbus_tk-1.0.0.tar.gz
Requirement already satisfied: pyserial>=3.1 in /usr/lib/python3/dist-packages (from modbus_tk) (3.4)
Building wheels for collected packages: modbus-tk
  Building wheel for modbus-tk (setup.py) ... done
  Created wheel for modbus-tk: filename=modbus_tk-1.0.0-cp37-none-any.whl size=27688 sha256=15e3841dcf8ebc94f25c746bf927d0eb67356c19c356240aedac185eeacb7181
  Stored in directory: /root/.cache/pip/wheels/ed/10/bc/36d75682626cb301a1f67010b38359ac6670e6127d646dd7d8
Successfully built modbus-tk
Installing collected packages: modbus-tk
Successfully installed modbus-tk-1.0.0

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 14 гостей