Пример программы для modbus

Возникла задача — соединить устройство на микроконтроллере atmega avr с компьютером по rs232. Что бы не изобретать велосипед, в качестве протокола обмена был выбран modbus.

  1. Поддерживается большинством промышленных (scada) систем.
  2. Существуют большое количество свободно распространяемых библиотек/программ с открытым исходным кодом.

Для отладки собрал стенд: stk500 c atmega avr подключенный к обычному компьютеру через переходник rs232-usb. Роль мастера (master) будет выполнять ПК, роль ведомого (slave) — avr atmega на stk500.

За основу возьмем:

  • Для ведомого (slave) — freemodbus;
  • Для ведущего (master) — qmodbus;

freemodbus

freemodbus — реализация ведомого устройства (slave), поддерживает modbus-rtu, modbus-ascii, modbus-tcp, портирован на большое количество архитектур, в том числе и для atmega avr. Скачать исходники можно тут тут ( версия 1.5.0).

Компиляция freemodbus

Скачиваем, разархивируем, заходим в freemodbus-v1.5.0/demo/AVR.

Работа в программе FLProg с протоколом Modbus по интерфейсу RS-485

Запускаем make и… ничего не собирается, получаем ошибку:

make: /opt/gcc-avr/bin/avr-gcc: Command not found make: *** [demo.o] Error 127

Что бы поправить сборку под avr редактируем Makefile, изменяем переменные СС, OBJCOPY, AVRDUDE. В них надо указать путь к соответствующим программам. У меня путь указан в переменной окружения PATH, по этому просто указываю имена программ:

CC=avr-gcc OBJCOPY=avr-objcopy AVRDUDE=avrdude

Далее задаем используемый avr микроконтроллер:

MCU = atmega16

В CFLAGS указываем какой используется кварц — 8 МГц:

-DF_CPU=8000000UL

И из правила сборки по-умолчанию убираем cof и eep, оставляем elf и hex:

all: $(TARGET).elf $(TARGET).hex

Теперь все собирается.

Доступ к данным в modbus

В описании протокола modbus определено четыре типа данных:

  • Discrete Inputs: размер — один бит, доступен только на чтение.
  • Coils: размер — один бит, доступен на чтение и на запись.
  • Input Registers — 16-битный регистр, доступен только на чтение.
  • Holding Registers — 16-битный регистр, доступен на чтение и на запись.

Для каждого типа в freemodbus надо реализовать функцию, обеспечивающую доступ к данным.

Для Input Registers:

eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs );

eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs );

Для Holding Registers:

eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode );

eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode );

eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode );

eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode );

Для Discrete Inputs:

eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete );

eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete );

Протокол MODBUS

Где:
pucRegBuffer — массив в который будет записаны значения регистров при чтении, или из которого будут считаны значения регистров которые надо записать.
usAddress — начальный адрес регистров
usNRegs, usNDiscrete, usNCoils — количество регистров
eMode — чтение или запись

На stk500 есть 8 светодиодов и 8 кнопок, сделаем так что бы управление светодиодами осуществлялось через Holding Register, а состояние кнопок считывалось из Input Register. При при помощи шлейфов PORTВ подключим к светодиодам а PORTA к кнопкам.

Получается у нас будет один регистр хранения (Holding Register) с адресом 1 и один регистр ввода (Input Register) тоже с адресом 1.
У каждого типа регистров в modbus свое адресное пространство, по этому регистры разного типа могут иметь одинаковые адреса.

В файле freemodbus-v1.5.0/demo/AVR/demo.c изменим код функций eMBRegInputCB и eMBRegHoldingCB:

eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) { eMBErrorCode eStatus = MB_ENOERR; if( ( usAddress == 1 ) ( usNRegs == 1 ) ) { *pucRegBuffer++ = 0; *pucRegBuffer++ = ~PINA; } else { eStatus = MB_ENOREG; } return eStatus; } eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ) { eMBErrorCode eStatus = MB_ENOERR; if( ( usAddress == 1 ) ( usNRegs == 1 ) ) { if( eMode == MB_REG_READ ) { *pucRegBuffer++ = 0; *pucRegBuffer++ = ~PINB; } else { pucRegBuffer++; PORTB = ~(*pucRegBuffer++); } } else { eStatus = MB_ENOREG; } return eStatus; }

В качестве реализаций eMBRegCoilsCB и eMBRegDiscreteCB оставим функции — ‘заглушки’:

eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) { return MB_ENOREG; } eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) { return MB_ENOREG; }

eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) < return MB_ENOREG; >eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )

Так же надо не забыть настроить PORTB на выход и выставить начальное значение, для этого в функции main добавим строки:

Читайте также:
Программа убрать ярлыки с рабочего стола

DDRB = 0xFF; //настраиваем PORTB на выход PORTB = 0xFF; //выключаем все светодиоды

DDRB = 0xFF; //настраиваем PORTB на выход PORTB = 0xFF; //выключаем все светодиоды

Настройка подключения modbus

Согласно описанию протокола modbus существует три варианта реализации : RTU, ASCII и TCP.

  • modbus ASCII — все данные передаются в текстовом виде, удобно отлаживать, но уменьшатся скорость
  • modbus RTU — данные в бинарном виде, скорость выше чем у modbus ASCII
  • modbus TCP — для обмена поверх протокола TCP

Наш выбор — modbus RTU.

Для настройки соединения в freemodbus надо вызывать функцию eMBInit:

eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity );

eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity );

  • eMode — тип реализации, MB_RTU или MB_ASCII
  • ucSlaveAddress — адрес устройства на шине modbus
  • ucPort — номер CОМ порта, в реализации для avr atmega не имеет значения
  • ulBaudRate — скорость обмена, например 38400
  • eParity — контроль четности: MB_PAR_NONE — без контроля четности, MB_PAR_ODD — дополнение до нечетности , MB_PAR_EVEN — дополнение до четности.

Пример настройки: протокол modbus RTU, адрес контроллера 10, скорость 38400, включен контроль дополнения до четности.

eStatus = eMBInit( MB_RTU, 10, 0, 38400, MB_PAR_EVEN );

eStatus = eMBInit( MB_RTU, 10, 0, 38400, MB_PAR_EVEN );

Так как modbus TCP и modbus ASCII использовать не будем, отключим ненужные части кода, что бы уменьшить размер программы. Для этого отредактируем файл modbus/include/mbconfig.h, заменим (1) на (0) у дефайнов MB_ASCII_ENABLED и MB_TCP_ENABLED.

/*! brief If Modbus ASCII support is enabled. */ #define MB_ASCII_ENABLED ( 0 ) /*! brief If Modbus RTU support is enabled. */ #define MB_RTU_ENABLED ( 1 ) /*! brief If Modbus TCP support is enabled. */ #define MB_TCP_ENABLED ( 0 )

/*! brief If Modbus ASCII support is enabled. */ #define MB_ASCII_ENABLED ( 0 ) /*! brief If Modbus RTU support is enabled. */ #define MB_RTU_ENABLED ( 1 ) /*! brief If Modbus TCP support is enabled. */ #define MB_TCP_ENABLED ( 0 )

QModBus

QModBus, кросcплатформенная реализация на Qt, компилируется под windows и под linux. Поддерживает modbus-rtu и modbus-ascii. Скачать исходники можно тут (версия 0.2.1 )

Компиляция QModBus

Скачиваем исходники тут. разархивируем. пытаемся собрать

qmake make

И опять компиляция не проходит, выдает предупреждения и ошибки:

WARNING: Failure to find: 3rdparty/libmodbus/modbus.c WARNING: Failure to find: 3rdparty/libmodbus/modbus-data.c WARNING: Failure to find: 3rdparty/libmodbus/modbus-rtu.c WARNING: Failure to find: 3rdparty/libmodbus/modbus-tcp.c WARNING: Failure to find: 3rdparty/libmodbus/modbus.h src/mainwindow.h:30:20: fatal error: modbus.h: No such file or directory compilation terminated.

WARNING: Failure to find: 3rdparty/libmodbus/modbus.c WARNING: Failure to find: 3rdparty/libmodbus/modbus-data.c WARNING: Failure to find: 3rdparty/libmodbus/modbus-rtu.c WARNING: Failure to find: 3rdparty/libmodbus/modbus-tcp.c WARNING: Failure to find: 3rdparty/libmodbus/modbus.h src/mainwindow.h:30:20: fatal error: modbus.h: No such file or directory compilation terminated.

Изменяем файл проекта qmodbus.pro, исправляем перменные SOURCES, HEADERS, INCLUDEPATH:

SOURCES += src/main.cpp src/mainwindow.cpp 3rdparty/qextserialport/qextserialport.cpp 3rdparty/libmodbus/src/modbus.c 3rdparty/libmodbus/src/modbus-data.c 3rdparty/libmodbus/src/modbus-rtu.c 3rdparty/libmodbus/src/modbus-tcp.c HEADERS += src/mainwindow.h 3rdparty/qextserialport/qextserialport.h 3rdparty/qextserialport/qextserialenumerator.h 3rdparty/libmodbus/src/modbus.h INCLUDEPATH += 3rdparty/libmodbus/src 3rdparty/libmodbus 3rdparty/qextserialport

SOURCES += src/main.cpp src/mainwindow.cpp 3rdparty/qextserialport/qextserialport.cpp 3rdparty/libmodbus/src/modbus.c 3rdparty/libmodbus/src/modbus-data.c 3rdparty/libmodbus/src/modbus-rtu.c 3rdparty/libmodbus/src/modbus-tcp.c HEADERS += src/mainwindow.h 3rdparty/qextserialport/qextserialport.h 3rdparty/qextserialport/qextserialenumerator.h 3rdparty/libmodbus/src/modbus.h INCLUDEPATH += 3rdparty/libmodbus/src 3rdparty/libmodbus 3rdparty/qextserialport

qmake make

Теперь сборка работает.

Обмен данными с avr по modbus

чтение состояние кнопок

Устанавливаем соответствующий COM-порт, скорость 38400, 8 бит данных, контроль дополнения до четности, 1 стоп бит. Slave ID — адрес контроллера avr на шине modbus равен 10.

Читаем состояние кнопок, для этого выбираем команду «Read Input Registers», выставляем адрес регистра = 0, и количество = 1. После нажатия на кнопку Send происходит обмен. Считанное из avr значение отображается в поле Data (на картинке прочитано число 128).

Для управления светодиодам используем команду «Write Single Register». В поле Data надо занести значение, которое будет записано в PORTB. После нажатия Send светодиоды, подключенные к avr, загораются.

Исходники

Архив проекта со всеми изменениями можно скачать тут

Запись опубликована в рубрике Микроконтроллеры avr с метками avr, modbus, qt, uart. Добавьте в закладки постоянную ссылку.

Источник: mainloop.ru

Взаимодействие с устройствами через ModBus RTU в Qt

Недавно мне на аутсорсе предложили выполнить небольшую работу: разработать ПО с графическим интерфейсом для управления источником питания по протоколу ModBus RTU. Не раздумывая я согласился решить поставленную задачу, однако меня ждал “интересный” сюрприз, вызванный моей же невнимательностью. В этой заметке я приведу пример работы с протоколом ModBus RTU в Qt с подробными коментариями, а заодно расскажу о своей досадной оплошности допущенной при решении этой задачи.

Задача и начальные данные

Прежде всего определим задачу: разработать ПО для управления источником питания по протоколу ModBus RTU с возможностью указания адреса устройства, параметров COM-порта, и управлением некоторым количеством параметров (запись и чтение заданных регистров).

Читайте также:
Какой программой проверить производительность процессора

Для отладки мне выдали какую-то железяку с поднятым на ней модбасом и возможностью хранить записанные ранее данные. Всё! Больше никакого функционала, полезного действия и смысловой нагрузки она не несёт. В прошлом это была некая плата “универсального интерфейса” – преобразователя различных протоколов обмена данных в привычный UART.

Симулятор устройства работающего про протоколу Modbus RTU

Начальные данные: перед этой задачей я уже делал подобное ПО для этой компании с одним лишь отличием – там управление осуществлялось целой сетью устройств с индивидуальным управлением каждым источником. Таким образом, я рассчитывал значительно упростить себе жизнь используя модули, созданные для решения прошлой задачи.

Поспешишь – людей насмешишь. Или лишний код напишешь…

Народная мудрость….. дополненная мною

Однако, в предыдущей задаче я допустил досадную для меня оплошность, суть которой в том, что я использовал лишь библиотеки для работы с последовательным портом, а реализацию протокола ModBus взял на себя. Почему я так сделал? *смех* В общем: “поспешишь – людей насмешишь!”, или свой код напишешь. Всё уже давно изобретено за нас. На помощь пришла встроенная библиотека, а именно класс QModBusRtuSerialMaster, наследуемый от QModBusDevice. Приступим!

Пишем код!

При реализации были использованы примеры программного кода из открытой документации Qt с ресурса doc.qt.io, которые были адаптированы для решения поставленной мне задачи.

Запускаем среду, создаем проект и приступаем к редактированию файла *.pro. Дополним параметр QT параметрами “serialbus serialport“. Должно получиться нечто такое:

QT += core gui serialbus serialport

Закрываем файл .pro и перейдем к форме главного окна программы QMainWindow. Начнем с заголовочного файла. Прототипы функций я пояснять сейчас не буду, а сделаю это позже, когда будем описывать реализацию класса.

// mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include class QModbusClient; namespace Ui < class MainWindow; >class MainWindow : public QMainWindow < Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); QModbusDataUnit readRequest(int, int) const; QModbusDataUnit writeRequest(int, int) const; private: Ui::MainWindow *ui; QModbusClient *modbusDevice; private slots: void onStateChanged(int); void readReady(); void prepareWrite(int, int); void prepareRead(int, int); void errorMessage(QString); void on_connectButton_clicked(); >; #endif // MAINWINDOW_H

Далее будем реализовывать интерфейс класса. Конструктор и деструктор класса.

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), modbusDevice(nullptr) // Предварительно инициализируем указатель «нулевым» указателем < ui->setupUi(this); /* * Создаем экземпляр класса QModbusRtuSerialMaster * Связываем сигнал errorOccurred с методом класса errorString(), * обрабатывающим ошибки. */ modbusDevice = new QModbusRtuSerialMaster(this); connect(modbusDevice, errorMessage(modbusDevice->errorString()); >); /* * Также соединяем сигнал изменения состояния объекта modbusDevice * с методом onStateChanged, где мы будем обрабатывать изменения состояния (подключение или отключение порта) */ if(modbusDevice) < connect(modbusDevice, MainWindow::onStateChanged); >> MainWindow::~MainWindow() < /* При завершении работы окна вызываем функцию отключения порта, * если указатель на объект modbusDevice существует. Если соединение * отсутствует, то функция не сделает ничего. * После чего удаляем экземпляр объекта. */ if(modbusDevice) modbusDevice->disconnectDevice(); delete modbusDevice; delete ui; >

Опишем используемые в коде выше методы: errorMessage(..) и onStateChanged(..). Метод errorMessage(…) выводит переданное в него сообщение в статус-баре окна программы и как отладочную информацию. onStateChanged(…) в зависимости от состояния порта (подключен или отключен) изменяет текст кнопки подключения connectButton и также выводит отладочное сообщение.

void MainWindow::errorMessage(QString msg) < /* STATUSBAR_MESSAGE_TIMEOUT — константа, определяющая время * «свечения» сообщения об ошибке в статус баре приложения */ ui->statusBar->showMessage(msg, STATUSBAR_MESSAGE_TIMEOUT); qInfo() void MainWindow::onStateChanged(int state) < if(state == QModbusDevice::UnconnectedState) < ui->connectButton->setText(«Подключить COM-порт»); qInfo() else if (state == QModbusDevice::ConnectedState) < ui->connectButton->setText(settings->getPortName() + QString(» «) + QString::number(settings->getBaudRate()) + » bps»); qInfo() getPortName() + QString(» «) + QString::number(settings->getBaudRate()) + » bps»; > else < return; // exit from function >>

Далее возникает закономерный вопрос: “Если у нас есть метод обработки изменения состояния подключения, то как мы создадим или уничтожим это подключение?”. Вот для этого давайте и займёмся реализацией следующего метода-обработчика нажатия кнопки connect.

void MainWindow::on_connectButton_clicked() < /* * Если экземпляр объекта по каким-либо причинам не существует, * то во избежание критических ошибок и проблем покидаем функцию */ if(!modbusDevice) return; /* Если порт не подключен, то настраиваем его и пытаемся установить соединение. * Если соединение установлено, то по нажатию кнопки мы разрываем соединение * Функция setConnectionParameter принимает 2 параметра: * 1) название устанавливаемого параметра * 2) значение параметра */ if(modbusDevice->state() != QModbusDevice::ConnectedState) < modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, settings->getPortName()); // Объект settings в моей программе хранит и возвращает заданные пользователем параметры COM-порта modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8); modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity); modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, settings->getBaudRate()); modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::TwoStop); // COM_TIMEOUT — константа. Задает время таймаута в милисекундах. modbusDevice->setTimeout(COM_TIMEOUT); // Пробуем установить соединение и в случае ошибки выводим соответствующее сообщеие if(!modbusDevice->connectDevice()) < errorMessage(«Подключение неудалось: » + modbusDevice->errorString()); > > else < modbusDevice->disconnectDevice(); > >

Читайте также:
Как обновить программу сканматик 2

Далее реализуем функционал чтения данных с устройства. Нам понадобиться 3 функции. Функция readRequest(…) формирует “единицу данных”, которая определяет тип запрашиваемого элемента согласно протоколу Modbus (holding register в моём случае), стартовый адрес и количество считываемых элементов. В моём случае это достаточно тривиальная функция, так что её можно было и упразднить, подставив возвращаемое выражение напрямую в функцию prepareRead().

Аналогичную ситуацию вы увидите позже при рассмотрении реализации функционала записи данных.

// Входные параметры: startAddress — адрес первого элемента, count — количество элементов (1 или более). QModbusDataUnit MainWindow::readRequest(int startAddress, int count) const < return QModbusDataUnit(QModbusDataUnit::HoldingRegisters, startAddress, count); >// Входные параметры: startAddress — адрес первого элемента, count — количество элементов (1 или более). void MainWindow::prepareRead(int startAddress, int count) < if(!modbusDevice) return; /* «Единица данных» передается в качестве параметра в функцию sendReadRequest(..) совместно с адресом устройства. * Если запрос произведен — удаляем ссылку на указатель ответа. * Если запрос ещё не закончен (в процессе), то связываем сигнал об окончании запроса * с функцией обработчика прочитанных данных */ if(auto *lastRequest = modbusDevice->sendReadRequest(readRequest(startAddress, count), settings->getAddress())) < if(!lastRequest->isFinished()) < connect(lastRequest, MainWindow::readReady); >else < delete lastRequest; >> else < errorMessage(tr(«Ошибка чтения: «) + modbusDevice->errorString()); > >

Третьей функцией, завершающей реализацию функционала чтения будет обработчик поступивших данных readReady(..)

void MainWindow::readReady() < auto reply = qobject_cast(sender()); if (!reply) return; if (reply->error() == QModbusDevice::NoError) < const QModbusDataUnit unit = reply->result(); QStringList resultsList; // Формируем список результатов в виде строк entry И складываем их в контейнер resultsList for (uint i = 0; i < unit.valueCount(); i++) < QString entry = tr(«Address: %1, Value: %2»).arg(unit.startAddress()) .arg(QString::number(unit.value(i)); results += entry; >> else if (reply->error() == QModbusDevice::ProtocolError) < // Выводим сообщение об ошибке протокола используя объект reply->errorString(); > else < // Выводим сообщение об остальных типах ошибки используя объект reply->errorString(); // В принципе, можно убрать столь подробное деление обработчика ошибок, оставив только лишь этот блок. > reply->deleteLater(); >

Реализация функционала записи требует меньшего количества функций, а именно две, хотя, повторюсь, в данной задаче, можно упразднить одну из функций, подставив возвращаемое выражение функции writeRequest(…) вместо её вызова.

// Входные параметры: startAddress — адрес первого элемента, count — количество элементов (1 или более). QModbusDataUnit MainWindow::writeRequest(int startAddress, int count) const < return QModbusDataUnit(QModbusDataUnit::HoldingRegisters, startAddress, count); >// Входные параметры: startAddress — адрес первого элемента, count — количество элементов (1 или более). void MainWindow::prepareWrite(int startAddress, int count) < if(!modbusDevice) return; QModbusDataUnit writeUnit = writeRequest(startAddress, count); for(uint i = 0; i < unit.valueCount(); ++i) < /* setValue(int arg1, quint16 arg2) требует двух параметров * 1) arg1 — номер ячейки для записи. Нумерация идёт с нуля, т.к. при записи этот «ноль» * будет отсчитываться от startAddress. * arg2 — значение элемента для записи. * value — массив данных, которые будут записаны в регистры. */ writeUnit.setValue(i, value[i]); >if(auto *lastRequest = modbusDevice->sendWriteRequest(writeUnit, settings->getAddress())) < if(!lastRequest->isFinished()) < connect(lastRequest, if(lastRequest->error() == QModbusDevice::ProtocolError) < // Обрабатываем сообщение ошибки проткола используя reply-errorString(); >else if(reply->error() == QModbusDevice::TimeoutError) < // В случае таймаута отправляем сообщение об ошибки в метод-обработчик errorString(); errorString(modbusDevice->errorString()); > else if (reply->error() != QModbusDevice::NoError) < // Обрабатываем сообщение других ошибок используя reply-errorString(); >else if(reply->error() == QModbusDevice::NoError) < // Здесь мы можем обработать факт успешной записи данных. >reply->deleteLater(); >); > else < reply->deleteLater(); > > else < errorMessage(«Ошибка записи: » + modbusDevice->errorString()); > >

Прошу обратить внимание, что формировать список параметров для записи можно не по штучно функцией setValue(..), а импортируя вектор значений функцией void QModbusDataUnit::setValues(const QVector https://zhitenev.ru/vcaimodeistvie-s-ustroistvami-cherez-modbus-rtu-in-qt/» target=»_blank»]zhitenev.ru[/mask_link]

Работа с Modbus-устройствами Wiren Board без контроллера

Большинство устройств Wiren Board могут работать без управления контроллером, но для их настройки потребуется подключиться к ним по протоколу Modbus. Для этого вы можете использовать компьютер с ОС Windows или Linux и преобразователь интерфейса USB-RS-485, например, WB-USB485 .

Для начала работы надо клеммы A, B и GND устройства подключить к входам адаптера, подать на устройство питание и настроить программное обеспечение на компьютере.

Подготовка к работе

Перед настройкой устройства вам нужно знать:

  1. modbus-адрес устройства,
  2. коды функций чтения и записи регистров,
  3. адреса регистров устройства.

Перечень общих для всех устройств Wiren Board регистров можно найти в таблице общих регистров. Полный список регистров для каждого устройства смотрите в документации к нему.

Программы для работы по протоколу Modbus

Интерфейс программы Rilheva Modbus Poll

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru