Протокол Modbus – самый распространенный промышленный протокол для межмашинного (M2M) взаимодействия. Является стандартом де-факто и поддерживается почти всеми производителями промышленного оборудования. В этой статье мы рассмотрим последовательную связь по протоколу Modbus RS-485 используя плату Arduino Uno в качестве ведомого устройства (Slave).
Также на нашем сайте вы можете посмотреть проект последовательной связи по протоколу Modbus RS-485 с Arduino (ведущей).
Что такое Modbus
Modbus — протокол, работающий по принципу «клиент-сервер». Широко применяется в промышленности для межмашинного взаимодействия и не только. Протокол Modbus был разработан в 1979 году. Modbus может использоваться для передачи данных через последовательные линии связи RS-485, RS-422, RS-232, а также через сети TCP/IP. В данной статье мы рассмотрим его использование на примере линии RS-485. Достаточно подробно протокол Modbus описан в соответствующей статье Википедии. Также неплохое описание протокола Modbus есть в этом документе (уже не помню откуда его скачал но его автору отдельное спасибо).
Modbus RS-485 использует линию последовательной связи RS-485 для передачи данных. Modbus является программным (не аппаратным) протоколом и состоит из двух частей: Modbus Master (ведущий) и Modbus Slave (ведомый). В сети Modbus RS-485 может быть один ведущий и 127 ведомых устройств, каждое из которых имеет уникальный адрес от 1 до 127. Master адреса не имеет — он в сети может быть только один.
Modbus чаще всего используется в программируемых логических контроллерах (PLCs — Programmable Logic Controllers). Но также он широко применяется в медицине, транспорте, проектах автоматизации дома и т.п. Modbus имеет 255 функциональных кодов. Наиболее распространены 3 версии данного протокола:
- MODBUS RTU;
- MODBUS ASCII;
- MODBUS/TCP.
Какая разница между протоколами Modbus ASCII и Modbus RTU? По сути, это практически одинаковые протоколы. Только в протоколе Modbus RTU данные передаются последовательно в двоичном коде, а в Modbus ASCII – в ASCII кодах. В этом проекте мы будем использовать Modbus RTU. Структура пакета в проколе Modbus RTU выглядит следующим образом:
Назначение элементов данного пакета рассмотрено далее в статье.
В данной статье мы будем использовать последовательную связь по протоколу Modbus RS-485 используя плату Arduino Uno в качестве ведомого устройства (Slave). Мы установим программное обеспечение Simply Modbus Master Software на компьютер и будем управлять двумя светодиодами и сервомотором, подключенными к ведомой плате Arduino. Управлять ими мы будем при помощи передачи специальных значений от Master Modbus Software.
Перед изучением данного проекта вам желательно прочитать статью о последовательной связи с помощью RS-485 между платами Arduino Uno и Arduino Nano. Также мы рассматривали и связь с помощью RS-485 между платами Arduino Uno и Raspberry Pi.
Принципы работы интерфейса последовательной связи RS-485
RS-485 представляет собой асинхронный интерфейс последовательной связи, не требующий для своей работы импульсов синхронизации. Для передачи двоичных данных от одного устройства к другому интерфейс использует дифференциальный сигнал.
Если следовать определению из википедии, дифференциальный сигнал представляет собой способ электрической передачи информации с помощью двух противофазных сигналов. В данном методе один электрический сигнал передаётся в виде дифференциальной пары сигналов, каждый по своему проводнику, но один представляет инвертированный сигнал другого, противоположный по знаку. Пара проводников может представлять собой витую пару, твинаксиальный кабель или разводиться по печатной плате. Приёмник дифференциального сигнала реагирует на разницу между двумя сигналами, а не на различие между одним проводом и потенциалом земли.
В нашем случае дифференциальный сигнал образуется при помощи использования положительного и отрицательного напряжения 5V. Интерфейс RS-485 обеспечивает полудуплексную связь (Half-Duplex) при использовании 2-х линий (проводов) и полноценную дуплексную связь (Full-Duplex) при использовании 4-х линий (проводов).
Основные особенности данного интерфейса:
- Максимальная скорость передачи данных в интерфейсе RS-485 – 30 Мбит/с.
- Максимальная дистанция связи – 1200 метров, что значительно больше чем в интерфейсе RS-232.
- Основным достоинством интерфейса RS-485 по сравнению с RS-232 является использование нескольких ведомых (multiple slave) при одном ведущем (single master) в то время как RS-232 поддерживает только одного ведомого.
- Максимальное число устройств, которое можно подключить по интерфейсу RS-485 – 32.
- Также к достоинствам интерфейса RS-485 относится хорошая помехоустойчивость вследствие использования дифференциального сигнала.
- RS-485 обеспечивает более высокую скорость передачи по сравнению с интерфейсом I2C.
Использование интерфейса RS-485 в Arduino
Для использования интерфейса RS-485 в плате Arduino мы будем использовать модуль 5V MAX485 TTL to RS485, в основе которого лежит микросхема Maxim MAX485. Модуль является двунаправленным и обеспечивает последовательную связь на расстояние до 1200 метров. В полудуплексном режиме он обеспечивает скорость передачи данных 2,5 Мбит/с.
Модуль 5V MAX485 TTL to RS485 использует питающее напряжение 5V и логический уровень напряжения также 5V, что позволяет без проблем подключать его к платам Arduino.
Данный модуль имеет следующие особенности:
- работает с напряжениями 5V;
- имеет в своем составе чип MAX485;
- отличается низким энергопотреблением;
- всеми его контактами можно управлять с помощью микроконтроллера;
- размеры платы модуля: 44 x 14mm.
Внешний вид модуля RS-485 показан на следующем рисунке.
Назначение контактов (распиновка) модуля RS-485 приведена в следующей таблице.
Название контакта | Назначение контакта |
VCC | 5V |
A | вход/выход линии RS-485 |
B | вход/выход линии RS-485 |
GND | GND (0V) |
R0 | выход приемника (RX pin) |
RE | разрешение работы приемника |
DE | разрешение работы передатчика |
DI | вход передатчика (TX pin) |
Как видите, контакты на модуле RS-485 расположены очень логично — с одной стороны к модулю подключается устройство, а с другой — линия.
Модуль преобразования USB в RS-485
На представленном рисунке показан внешний вид адаптера (модуля преобразования) USB в RS-485. Он способен работать в различных операционных системах и обеспечивает интерфейс RS-485 при помощи использования одного из COM портов компьютера. Этот модуль является устройством plug-and-play. Все, что передается через виртуальный COM порт, автоматически преобразуется данным модулем в RS-485, и наоборот. Модуль питается от порта USB – никакого дополнительного питания не требуется.
В компьютере он виден как последовательный/ COM порт и доступен для использования различными приложениями. Модуль обеспечивает полудуплексную связь с помощью интерфейса RS-485. Скорость передачи – от 75 до 115200 бод/с, максимальная – до 6 Мбит/с.
В сети интернет можно найти достаточно много программного обеспечения, способного работать с данным адаптером. Мы в этом проекте будем использовать программу Simply Modbus Master.
Программное обеспечение Modbus Master
Программу Modbus Master Software мы будем использовать для передачи данных ведомой плате Arduino с помощью интерфейса RS-485.
Вы можете скачать программу Simply Modbus Master по следующей ссылке. Документацию по этой программе (на английском языке) можно прочитать здесь.
Перед использованием данной программы необходимо ознакомиться со следующими терминами, используемыми в ней.
Slave ID (идентификатор/адрес ведомого)
Каждому ведомому устройству в сети назначается уникальный адрес в диапазоне от 1 до 127. Когда ведущее устройство запрашивает данные, то первый байт, который он передает, содержит адрес ведомого устройства. Благодаря этому каждое ведомое устройство знает стоит ли ему отвечать на этот запрос или нет.
Регистры Modbus
Регистры флагов (Coils) хранят однобитные значения — то есть могут находится в состоянии 0 или 1. Такие регистры могут обозначать текущее состояние выхода (включено реле). Название «coil» буквально и означает обмотку-актюатор электромеханического реле. Регистры флагов допускают как чтение, так и запись. Имеют номера от 1 до 9999.
Дискретные входы (Discrete Inputs) также являются однобитными регистрами, описывающими состояние входа устройства (например, подано напряжение — 1). Эти регистры поддерживают только чтение. Имеют номера от 10001 до 19999.
Регистры ввода (Input Registers) – 16-битные регистры, используемые для ввода информации. Эти регистры поддерживают только чтение. Имеют номера от 30001 до 39999.
Регистры хранения (Holding Registers) представлены двухбайтовым словом и могут хранить значения от 0 до 65535 (0x0000 — 0xFFFF). Регистры хранения поддерживают как чтение, так и запись (для хранения настроек). Имеют номера от 40001 до 49999.
Function code (код функции/функциональный код)
Второй байт, передаваемый ведущим, содержит функциональный код. Этот код определяет действие, которое необходимо выполнить (считать, записать и т.д.). Действия сгруппированы по таблицам. В протоколе Modbus существует четыре таблицы с данными:
Таблица | Тип элемента | Тип доступа |
Дискретные входы (Discrete Inputs) | один бит | только чтение |
Регистры флагов (Coils) | один бит | чтение и запись |
Регистры ввода (Input Registers) | 16-битное слово | только чтение |
Регистры хранения (Holding Registers) | 16-битное слово | чтение и запись |
В реальной практике чаще всего встречаются устройства, в которых есть только таблица Holding Registers, иногда объединённая с таблицей Input Registers.
Для доступа к этим таблицам существует ряд стандартный функций ModBus:
Чтение:
- 1 (0x01) — чтение значений из нескольких регистров флагов (Read Coil Status).
- 2 (0x02) — чтение значений из нескольких дискретных входов (Read Discrete Inputs).
- 3 (0x03) — чтение значений из нескольких регистров хранения (Read Holding Registers).
- 4 (0x04) — чтение значений из нескольких регистров ввода (Read Input Registers).
Запись одного значения:
- 5 (0x05) — запись значения одного флага (Force Single Coil).
- 6 (0x06) — запись значения в один регистр хранения (Preset Single Register).
Запись нескольких значений:
15 (0x0F) — запись значений в несколько регистров флагов (Force Multiple Coils)
16 (0x10) — запись значений в несколько регистров хранения (Preset Multiple Registers)
Наиболее часто используемые на практике функции (функциональные коды) ModBus это 3, 6 и 16 («Read Holding Registers», «Preset Single Register» и «Preset Multiple Registers» — соответственно).
В этой статье описана реализация команды 0x10 — запись значений в несколько регистров хранения, работа с командами 0x03 и 0x04, наиболее часто используемыми для считывания информации с датчиков по протоколу ModBus, описана в данной статье (написать такую статью очень просили посетители нашего сайта).
CRC
CRC расшифровывается как Cyclic Redundancy check и переводится как “циклический избыточный код”. Это два байта, которые добавляются к каждому передаваемому сообщению протокола Modbus для обнаружения ошибок.
Необходимые компоненты
Аппаратное обеспечение
- Плата Arduino Uno (купить на AliExpress).
- MAX485 TTL to RS485 Converter Module (модуль преобразования логики TTL в RS485) ( купить на AliExpress).
- USB to RS-485 Converter Module (преобразователь USB в RS-485) ( купить на AliExpress).
- Светодиод – 2 шт. (купить на AliExpress).
- Резистор 1 кОм – 2 шт. (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Потенциометр 10 кОм (купить на AliExpress).
- Сервомотор SG-90 (купить на AliExpress).
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Программное обеспечение
Схема проекта
Схема для последовательной связи по протоколу Modbus RS-485 с платой Arduino представлена на следующем рисунке.
Arduino Uno | Модуль MAX485 TTL to RS485 |
0(RX) | RO |
1(TX) | DI |
4 | DE & RE |
+5V | VCC |
GND | GND |
В следующей таблице представлены необходимые соединения между модулями MAX485 TTL to RS485 и USB to RS-485.
MAX485 TTL to RS485 | USB to RS-485 |
A | A |
B | B |
В следующей таблице представлены необходимые соединения между платой Arduino Uno и ЖК дисплеем 16х2.
ЖК дисплей 16х2 | Плата Arduino Uno |
VSS | GND |
VDD | +5V |
V0 | к потенциометру для управления яркостью/контрастностью дисплея |
RS | 8 |
RW | GND |
E | 9 |
D4 | 10 |
D5 | 11 |
D6 | 12 |
D7 | 13 |
A | +5V |
K | GND |
В следующей таблице представлены необходимые соединения между платой Arduino Uno, светодиодами и сервомотором.
Arduino Uno | 1-й светодиод | 2-й светодиод | сервомотор |
2 | Anode через 1k resistor | — | — |
5 | — | Anode через 1k resistor | — |
6 | — | — | PWM pin (Orange) |
+5V | — | — | +5V (RED) |
GND | Cathode GND | Cathode GND | GND (Brown) |
Со схемой разобрались, можно переходить к написанию программы.
Объяснение программы Arduino для связи по протоколу Modbus RS-485
В нашем проекте плата Arduino Uno используется в качестве ведомого устройства (Slave) протокола Modbus. К плате Arduino Uno подключены два светодиода и сервомотор. Ведомая плата Arduino Uno управляется программным обеспечением Master Modbus. Связь между Master Modbus и платой Arduino Uno осуществляется с помощью модулей RS-485. Для подключения к компьютеру используется модуль преобразования USB в RS-485, а для подключения к плате Arduino Uno используется модуль преобразования MAX-485 TTL to RS-485. Собранная конструкция проекта выглядит следующим образом:
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Для использования протокола Modbus в плате Arduino Uno мы подключим в программе библиотеку <ModbusRtu.h>. Эта библиотека применяется для связи с ведущим или ведомым устройством Modbus RS-485 при помощи протокола RTU. Скачайте эту библиотеку по следующей ссылке — Modbus RTU. Добавьте ее в Arduino IDE при помощи команды Sketch->include library->Add .zip Library.
Первым делом в программе мы подключим необходимые библиотеки: <ModbusRtu.h> для работы с Modbus RS-485, а также библиотеки для работы с ЖК дисплеем и сервомотором.
1 2 3 |
#include<ModbusRtu.h> #include<LiquidCrystal.h> #include <Servo.h> |
Затем дадим названия контактам, к которым подключены светодиоды.
1 2 |
#define led1 2 #define led2 5 |
Далее сообщим плате Arduino Uno к каким ее контактам подключен ЖК дисплей при помощи создания объекта ЖК дисплея.
1 |
LiquidCrystal lcd(8,9,10,11,12,13); |
Далее инициализируем объекты для работы с сервомотором и протоколом Modbus.
1 2 |
Servo servo; Modbus bus; |
Затем объявим массив, в котором будем хранить значение, получаемые по протоколу Modbus. Первоначально эти значения будут равны 0.
1 |
uint16_t modbus_array[] = {0,0,0}; |
Далее в функции setup зададим режим работы ЖК дисплея (16×2), покажем на его экране приветственное сообщение и затем после задержки очистим экран.
1 2 3 4 5 6 |
lcd.begin(16,2); //Lcd set in 16x2 mode lcd.print("RS-485 Modbus"); //Welcome Message lcd.setCursor(0,1); lcd.print("Arduino Slave"); delay(5000); lcd.clear(); |
После этого зададим режим работы для контактов, к которым подключены светодиоды – на вывод данных.
1 2 |
pinMode(led1,OUTPUT); pinMode(led2,OUTPUT); |
Сервомотор в нашем проекте подключен к контакту 6 (ШИМ) платы Arduino, поэтому используем соответствующую команду:
1 |
servo.attach(6); |
Теперь для связи по протоколу Modbus установим следующие параметры. Первая ‘1’ будет обозначать адрес ведомого (Slave ID), вторая ‘1’ будет обозначать что модуль RS-485 будет передавать данные, а ‘4’ будет обозначать, что контакты DE&RE модуля RS-485 подключены к контакту 4 платы Arduino.
1 |
bus = Modbus(1,1,4); |
Используемая нами скорость передачи данных по протоколу Modbus – 9600 бод/с.
Далее в функции loop мы будем использовать функцию bus.poll() чтобы задать параметры приема информации от ведущего устройства Modbus.
1 |
bus.poll(modbus_array,sizeof(modbus_array)/sizeof(modbus_array[0])); |
Мы будем проверять есть ли какие-нибудь данные в приемнике последовательного порта. Если там есть какие-нибудь данные, то с помощью библиотеки Modbus RTU мы будем проверять сообщение (адрес устройства, длину данных и проверочный код (CRC)) и на основании этого выполнять соответствующие действия.
К примеру, чтобы записать или считать данные от ведущего устройства (master), мы должны принять массив данных типа unsigned 16-bit integer и его длину от ведущего устройства Modbus.
В нашем проекте мы будем использовать три значения этого массива – два для управления светодиодами и одно для управления углом поворота оси сервомотора.
Чтобы включать/выключать первый светодиод (LED1) мы будем использовать значение modbus_array[0].
1 2 3 4 5 6 7 8 9 10 11 12 |
if (modbus_array[0] == 0) //Depends upon value in modubus_array[0] written by Master Modbus { digitalWrite(led1,LOW); //LED OFF if 0 lcd.setCursor(0,0); lcd.print("L1:OFF"); } else { digitalWrite(led1,HIGH); //LED ON if value other than 0 lcd.setCursor(0,0); lcd.print("L1:ON"); } |
Чтобы включать/выключать второй светодиод (LED2) мы будем использовать значение modbus_array[1].
1 2 3 4 5 6 7 8 9 10 11 12 |
if (modbus_array[1] == 0) //Depends upon value in modbus_array[1] written by Master Modbus { digitalWrite(led2,LOW); //LED OFF if 0 lcd.setCursor(8,0); lcd.print("L2:OFF"); } else { digitalWrite(led2,HIGH); //LED ON if value other than 0 lcd.setCursor(9,0); lcd.print("L2:ON"); } |
Для управления углом поворота оси сервомотора мы будем использовать значение modbus_array[2]. Также это значение мы будем показывать на экране ЖК дисплея 16×2.
1 2 3 4 5 6 7 |
int pwm = modbus_array[2]; servo.write(pwm); lcd.setCursor(0,1); lcd.print("Servo angle:"); lcd.print(pwm); delay(200); lcd.clear(); |
Тестирование работы проекта
После того, как все необходимые соединения в проекте сделаны, программа загружена в плату Arduino и на компьютере установлена программа Simple Modbus Master, откройте диспетчер устройств на вашем компьютере и посмотрите там к какому COM порту подключен модуль преобразования USB в RS-485. После этого запустите программу Simply Modbus Master 8.1.1. Затем выполните следующую последовательность шагов.
1. В программе Simply Modbus откройте опции записи (Write option).
2. После этого установите параметры записи в программе Simply Modbus Master: режим RTU, COM порт к которому подключен модуль преобразования USB в RS-485 (в нашем случае это COM6), скорость 9600 бод, 8 бит данных, 1 стоповый бит, отсутствие бита четности (Parity None) и идентификатор ведомого (Slave ID) равный 1.
3. После этого установите в первом регистре (first register) значение 40001, число передаваемых значений (values) равное 3 и функциональный код (function code) равный 16 (Write Holding Register).
После этого запишите 1 в 40001 (для включения первого светодиода), 1 в 40002 (для включения второго светодиода) и 90 в 40003 (для задания угла поворота оси сервомотора), затем нажмите кнопку SEND (передать) – см. рисунок.
После этого вы увидите как загорятся оба светодиода, а сервомотор повернется на 90 градусов.
4. После этого запишите 1 в 40001, 0 в 40002 и 180 в 40003.
В результате этой операции первый светодиод включится, второй – выключится, а сервомотор повернется на угол 180 градусов.
5. Теперь запишите 135 в 40003, 0 в 40001 и 1 в 40002.
Вы увидите что сервомотор повернется на угол 135 градусов, первый светодиод выключится, а второй – включится.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
//RS-485 Modbus Slave (Arduino UNO) //Circuit Digest #include<ModbusRtu.h> //Library for using Modbus in Arduino #include<LiquidCrystal.h> //Library for using 16x2 LCD display #include <Servo.h> //Library for using Servo Motor #define led1 2 //Define as 2 led1 #define led2 5 //Define as 5 led2 LiquidCrystal lcd(8,9,10,11,12,13); //initizlize lcd object with pins (RS,E,D4,D5,D6,D7) for class liquid crystal Servo servo; //Initilize servo object for class Servo Modbus bus; //Define Object bus for class modbus uint16_t modbus_array[] = {0,0,0}; //первоначально в массив записываем нулевые значения void setup() { lcd.begin(16,2); //режим 16x2 для ЖК дисплея lcd.print("RS-485 Modbus"); //приветственное сообщение lcd.setCursor(0,1); lcd.print("Arduino Slave"); delay(5000); lcd.clear(); pinMode(led1,OUTPUT); //Led1 на вывод данных pinMode(led2,OUTPUT); //Led2 на вывод данных servo.attach(6); //Servo PWM pin 6 (контакт, к которому подключен сервомотор) bus = Modbus(1,1,4); //Modbus slave ID as 1 and 1 connected via RS-485 and 4 connected to DE & RE pin of RS-485 Module //адрес ведомого равен 1, используется связь через интерфейс RS-485 (вторая 1), 4 – номер контакта Arduino, к которому подключены контакты DE & RE модуля RS-485 bus.begin(9600); //Modbus slave baudrate at 9600 (скорость 9600 бод) } void loop() { bus.poll(modbus_array,sizeof(modbus_array)/sizeof(modbus_array[0])); //Used to receive or write value from Master if (modbus_array[0] == 0) //Depends upon value in modubus_array[0] written by Master Modbus { digitalWrite(led1,LOW); //выключаем первый светодиод lcd.setCursor(0,0); lcd.print("L1:OFF"); } else { digitalWrite(led1,HIGH); // включаем первый светодиод lcd.setCursor(0,0); lcd.print("L1:ON"); } if (modbus_array[1] == 0) //Depends upon value in modbus_array[1] written by Master Modbus { digitalWrite(led2,LOW); //LED OFF if 0 lcd.setCursor(8,0); lcd.print("L2:OFF"); } else { digitalWrite(led2,HIGH); //LED ON if value other than 0 lcd.setCursor(9,0); lcd.print("L2:ON"); } int pwm = modbus_array[2]; //Depends upon value in modbus_array[1] written by Master Modbus servo.write(pwm); // поворачиваем сервомотор на угол pwm (от 0 до 180 градусов), принятый от Modbus Master lcd.setCursor(0,1); lcd.print("Servo angle:"); lcd.print(pwm); //выводим значение угла на экран ЖК дисплея 16х2 delay(200); lcd.clear(); } |
59 ответов к “Последовательная связь по протоколу Modbus RS-485 с Arduino (ведомой)”
А вы не в курсе, как указать указать первый регистр, отличный от 400001?
В примерах есть «software_serial_simple_master». Там «modbus_t telegram;»
typedef struct
{
uint8_t u8id; /*!< Slave address between 1 and 247. 0 means broadcast */
uint8_t u8fct; /*!< Function code: 1, 2, 3, 4, 5, 6, 15 or 16 */
uint16_t u16RegAdd; /*!< Address of the first register to access at slave/s */
uint16_t u16CoilsNo; /*!< Number of coils or registers to access */
uint16_t *au16reg; /*!< Pointer to memory image in master */
}
modbus_t;
Я так понял, что это работает только в режиме master. А для slave указать начальный адрес регистра никак?
Где вы их хотите указать? В данной статье мы используем команду 0x10 для чтения Holding Registers, а адреса этих самых Holding Registers могут лежать только в диапазоне 40001-49999.
К примеру, мне нужно прочитать Holding Registers начиная с адресов 40200, 10 регистров.
Например, в этой статье рассмотрен случай, когда мы сначала записываем в регистры значения с помощью node.writeSingleRegister(0x40000,value), а потом считываем их с помощью программы на компьютере. Вы это имели ввиду?
Да, похоже это то, что нужно. Спасибо большое. Там используется библиотека ModbusMaster.h, а здесь ModbusRtu.h и похоже у неё нет такой возможности указать адрес первого регистра.
Хорошо, успехов вам в реализации проекта
Библиотека ModbusRtu работает только с массивом modbus_array[]. Это только для чтения и записи всего трёх двухбайтовых значений. Адреса будут 4001-4003.
Отличная статья! Все сразу заработало.
Я несколько упростил, сделал только два светодиода и отправлял сообщения в Serial.print().
Как и предыдщий комментатор прошу выложить статью именно о режиме Slave, так чтоб ардуино получал команды от Master и например сообщал температуру. Если у меня получится такая разработка скину вам.
Не совсем понял какая именно статья нужна. Ведь в этой статье и так рассмотрена работа Arduino в режиме Slave (ведомого устройства)
Нечто я смастерил:
https://cloud.mail.ru/public/3bqc/JUaei4h5n
Поздравляю с успехом
Посмотрели?
Нет, пока не смог, к сожалению
Появилась уже новая реализация. Более расширенная.
К сожалению, найти готовое решение не удалось. Пришлось, отталкиваясь от вашей работы, мастерить самому.
От админа: ну что поделать, сочувствую. На сайте уже очень много статей и следить за актуальным состоянием каждой я уже, к сожалению, не всегда успеваю
Подскажите плз! при первом опросе возвращает мусор непонятный, а далее нормально! В чём может быть причина?
Не совсем понял на каком этапе работы программы и где вы видите этот мусор?
Добрый день. Спасибо за статью. В своё время я писал уже тут, занялся реализацией ответной рпограммы чтобы с ПК управлять блоком питания на основе ардуино. Но возникли проблемы с периодическим зависанием ардуино при передачи сигналов от мастера (монитор порта или своё приложение — одинаково). Пришёл к мысли, что проблема в питании ардуины от батарейки. Здесь https://docs.arduino.cc/hardware/mkr-485-shield написано «A DC-DC converter with pulse-skipping Eco-Mode feature, which allows the use of batteries as a power supply.»
Подскажите, пожалуйста, в вашем проекте Вы от чего запитывали ардуино?
Добрый вечер. Через USB. Вот статья про способы подачи питания на плату Arduino Uno, может она вам чем-нибудь поможет
Спасибо, Ваш контент очень полезен! Не знаю точно почему, но при питании через USB, а не посредством кроны 9В подключенной в разъём 2,1мм, ардуинка действительно не зависает. ПК — именно стационарный компьютер воткнутый в заземлённую розетку, не ноутбук. Правда последние тесты делал на другой библиотеке SimpleModbusSlave (не знал на что грешить) Вдруг кому-то будет полезно… я с этим проваландался полторы недели 🙂
Спасибо что оценили мой труд. И вам спасибо за полезный комментарий. А вы только на одной Ардуино это пробовали? Не пробовали на другом экземпляре? Может, просто у вашей платы есть какой нибудь дефект контакта или цепи, к которой подключается батарейка
Здравствуйте! У меня такая же проблема. По проекту питание Ардуино нано предусматривается от преобразователя напряжения AC/DC и при переходе на питание преобразователя, передача данных с ардуинки прекращается, пока побороть не получается эту досадную ситуацию. У Вас получилось? Не подскажите, в чем проблема кроется?
Здравствуйте. Отличная статья которая позволяет хоть как то начать понимать вообще что к чему в этом Modbus. Крайне признателен за ваш труд!
Поддерживаю вопрос о функциях (0x03) или (0x04)
Добрый вечер. Так в тексте статьи есть же уже ссылка на статью про функции (0x03) и (0x04) — вот она.
Здравствуйте. Эта ссылка изучена. Она в ведущую ардуину. Интересно как на ведомую ардуину записывать и считывать состояния.
Добрый вечер. Если не секрет, то где такое применение платы Arduino вам понадобилось? Если Arduino считывает информацию с датчиков с помощью функций (0x03) и (0x04), то логично что она выступает в качестве ведущей
Приветствую. Благодарю за внимание к моему вопросу. Считывать не ардуиной нужно, а с ардуины: состояния ее пинов.
Грубо говоря разрабатываю себе пульт для станка под LinuxCNC.
Да, с этим вопросом я пока не разбирался, к сожалению. Но если вдруг разберетесь с ним раньше меня, просьба отпишитесь как удалось его решить. Может быть тогда на основе вашего ответа мне удастся дополнить статью полезной информацией по данному вопросу
Добрый день. Спасибо за статью, очень познавательно. Попробовал на Arduino Uno и преобразователе MAX485 реализовать передачу — включить/выключить светодиод. При компиляции компилятор выдал предупреждения, но процесс завершил. При работе с монитором порта Simply Modbus 8.1.2 отправляю сообщение как описано в статье при этом ничего не происходит. Такое ощущение что библиотека ModbusRtu.h — которую я скачал с репозитория немного другая, но так как я начинающий в ардуино (и собственно с++), разобраться не получается. Можете помочь мне с этим?
скетч
#include
#include //Library for using Modbus in Arduino
#define led 8
Modbus bus(1,1,4); //Define Object bus for class modbus
uint16_t modbus_array[] = {1,0,0}; //первоначально в массив записываем нулевые значения
void setup()
{
delay(1000);
pinMode(led, OUTPUT);
bus.begin(9600); //Modbus slave baudrate at 9600 (скорость 9600 бод)
}
void loop()
{
delay(5000);
bus.poll(modbus_array,sizeof(modbus_array)/sizeof(modbus_array[0])); //Used to receive or write value from Master
if (modbus_array[0] == 0) //Depends upon value in modubus_array[0] written by Master Modbus
{
//Serial.println(«first is 0»);
digitalWrite(led, LOW);
}
else
{
//Serial.println(«first high»);
digitalWrite(led, HIGH);
}
if (modbus_array[1] == 0) //Depends upon value in modbus_array[1] written by Master Modbus
{
}
else
{
}
if (modbus_array[2] == 0) //Depends upon value in modbus_array[1] written by Master Modbus
{
}
else
{
}
delay(200);
}
Сообщение компилятора:
C:\Users\user\Documents\Arduino\modbustest1\modbustest1\modbustest1.ino:6:17: warning: ‘Modbus::Modbus(uint8_t, uint8_t, uint8_t)’ is deprecated [-Wdeprecated-declarations]
Modbus bus(1,1,4); //Define Object bus for class modbus
^
In file included from C:\Users\user\Documents\Arduino\modbustest1\modbustest1\modbustest1.ino:3:0:
C:\Program Files (x86)\Arduino\libraries\Modbus-Master-Slave-for-Arduino-master/ModbusRtu.h:272:1: note: declared here
Modbus::Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin)
^~~~~~
C:\Users\user\Documents\Arduino\modbustest1\modbustest1\modbustest1.ino: In function ‘void setup()’:
C:\Users\user\Documents\Arduino\modbustest1\modbustest1\modbustest1.ino:19:17: warning: ‘void Modbus::begin(long int)’ is deprecated [-Wdeprecated-declarations]
bus.begin(9600); //Modbus slave baudrate at 9600 (скорость 9600 бод)
^
In file included from C:\Users\user\Documents\Arduino\modbustest1\modbustest1\modbustest1.ino:3:0:
C:\Program Files (x86)\Arduino\libraries\Modbus-Master-Slave-for-Arduino-master/ModbusRtu.h:385:6: note: declared here
void Modbus::begin(long u32speed)
^~~~~~
Скетч использует 4812 байт (14%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 406 байт (19%) динамической памяти, оставляя 1642 байт для локальных переменных. Максимум: 2048 байт.
Добрый вечер. Так сложно сразу определить в чем у вас проблема. Может быть, вы сначала попробуете запустить простой пример из этой библиотеки: https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino/blob/master/examples/simple_slave/simple_slave.ino
Добрый день. Нет этот пример тоже не заработал. Решил проверить преобразователь UART-RS485 из этой Вашей статьи https://microkontroller.ru/arduino-projects/posledovatelnaya-svyaz-po-protokolu-rs485-mezhdu-arduino-uno-i-arduino-nano/. Он заработал, т.е. я хотя бы проверил что проблема либо в скетче либо в библиотеке. В скетче найти проблему тоже не могу.
Я обратил внимание, что библиотека ModbusRTU.h с репозитория имеет обновление(в частности обновлён конструктор класса, насколько я понял, и вместо Modbus.begin(baud rate) требуют использовать Modbus.start() ) от 2019 г и имеет версию 1.21.
Вы не могли бы скинуть библиотеку ModbusRTU.h на которой проверялся скетч этой статьи, может быть была предыдущая версия библиотеки?
Добрый вечер. Нет, к сожалению у меня та версия библиотеки не сохранилась
Добрый день. Заработало! Проблема оказалась в преобразователе USB-RS485 (если что — bolid rs485 с гальванической изоляцией). Он был новый — при этом драйвер встал прямо, COM порт определялся, не подумал на него грешить. Решил со старым преобразователем на схеме CH340 (он без опто-развязки из-за этого не хотел им пользоваться) и всё заработало. Правда пока проверил как раз на старой версии библиотеки ModbusRTU версии 1.20 которую на просторах нашёл.
Если быть точным проблема была во мне. Надо было внимательней читать инструкцию к данному преобразователю, там после установки драйвера нужно настроить COM-порт, выставив галку «RS485». Так что вопрос закрыт. Спасибо.
От админа: я рад что у вас получилось. Заходите к нам еще
Добрый день! Хочу поделиться результатами своего проекта по передачи данных с промышленного контроллера RX3i на телефон Android. Надеюсь мои труды будут полезны.
В архиве находиться все необходимое для повторения.
https://disk.yandex.ru/d/xYeU61dNAeA52A
Добрый вечер. Спасибо за помощь в развитии нашего сайта. Может быть ваши труды опубликовать на сайте в виде отдельной статьи? Вы не против?
Не против. Можете опубликовать. Там только один момент, не получается передавать больше 27 точек и в чем причина не выяснил.
Хорошо, постараюсь опубликовать в ближайшее время. Просьба тогда к вам указать на ошибки/опечатки если они будут в опубликованной статье на основе ваших материалов
Полностью Вам доверяю. Думаю что не потребуется внесения уточнений.
Хорошо. Но на всякий случай все равно прошу посмотреть статью после того как я ее опубликую
Добрый день!
Увеличил размер modbus_array [] до 12 символов, но информацию получаю только по 3 первым. В чем проблема?
Добрый вечер. А в программе Simply Modbus Master вы увеличили число передаваемых значений (values)?
Данные я передаю с промышленного контроллера RX3i Fanuc. Значит никаких ограничений в библиотеке ModbusRtu.h не должно быть? Буду проверять данные передаваемые контроллером. Спасибо большое за Вашу работу!!!!
Все заработало. Была моя ошибка в логике RX3i
Спасибо что оценили мой труд и я рад что у вас все получилось. А вы не могли хотя бы в нескольких строках описать суть вашего проекта, что вы хотите сделать в результате? Мне интересно узнать, где все таки на практике применяется протокол Modbus. Какие задачи решаются с его помощью. А то статья, в основном, теоретическая, хотелось бы самому побольше узнать про практическое применение Modbus в проектах, выполняемых читателями нашего сайта
У меня на производстве используются автоматизированные системы под управлением контроллеров Fanuc RX3i, которые получают информацию с датчиков по дискретным и аналоговым сигналам. Еще эти контролеры имеют управляющие дискретные и аналоговые сигналы. Также к этим контроллерам можно подключить приборы учета типа ИРВИС. Дак вот они (и другие приборы) как раз обмениваются информацией по протоколу Modbus. Вся обрабатываемая информация контроллерами отображается на экране монитора. Для «сложного оборудования» имеющего более 10 датчиков температуры, по которым при настройке проверяется результат изменения «определенных точек управления» и они находятся не в зоны установки монитора. Для настройки требуются два человека с постоянной связью. Один производит настройку, а второй следит за изменениями и сообщает о них первому.
Моя задача:
1. Получить информацию информацию по протоколу Modbus с RX3i.
2. Отправить информацию по Bluetooth или WiFi на мобильное устройство Android или IOS в удобочитаемостью виде.
Т.о. операцию по настройке сможет производить один человек имеющий мобильное устройство.
От админа: спасибо за столь подробный ответ, хотя бы немного просветили меня в реалиях промышленного применения протокола Modbus
Наконец то закончил работу над первым вариантом статьи по считыванию информации с датчиков в Arduino по протоколу Modbus (реализация команд 0x03 и 0x04 — как вы и просили) — она пока не такая подробная (нет картинок и видео) как хотелось, но думаю определенную помощь она вам все же окажет
Спасибо за Вашу проделанную работу. Ждем продолжение статьи. Очень хочется узнать как читать регистры(0x03 или 0х04) из Arduino slave. Еще один вопрос почему номера регистров для записи начинаются с 4000x? Есть ли возможность сделать адреса регистров например 0x01?
Начал работу по изучению команд 0x03 и 0х04. К сожалению, в русскоязычном сегменте интернета работа с этими командами рассматривается не с помощью библиотеки ModbusRtu.h от пользователя smarmengol, использованной в данной статье, а в основном с помощью других библиотек. Хотелось бы все таки для решения этой задачи использовать библиотеку ModbusRtu.h чтобы сохранить общую стилистику статьи. Если бы кто-нибудь подсказал какую-нибудь англоязычную статью, где рассмотрено решение этой задачи, то я бы мог просто перевести такую статью и тогда, скорее всего, вопрос был бы закрыт. Но пока, к сожалению, не могу найти и подходящей англоязычной статьи.
По поводу вашего вопроса про номера регистров пока не могу точно ответить, к сожалению, потому что пока временно нет возможности снова собрать описанный в данной статье проект. Если у вас есть такая возможность попробуйте поизменять номера регистров на 30000х, 20000х и т.д. (только не забывайте в этом случае изменять и значение сдвига — minus offset). Но 0x01 здесь не подойдет — это все таки другой формат записи числа. Если только с помощью другой программы для работы с Modbus, поддерживающей такой формат записи чисел.
Нашел ответ на ваш вопрос, касающийся адресов регистров. Дело в том, что в данной статье мы используем команду 0x10 для чтения Holding Registers, а адреса этих самых Holding Registers могут лежать только в диапазоне 40001-49999. Добавил в статью информацию по поводу доступных адресов регистров
Буду ждать, потому что для новичка в ардуино очень доступно все объясняете, спасибо)
Спасибо за то, что оценили мой труд. Достаточно большую часть статей я перевожу с сайта индийских энтузиастов (ссылки на их сайт есть во многих статьях на моем сайте) — им тоже огромное спасибо. Часть этой статьи тоже является переводом с их сайта, но некоторые моменты у них, на мой взгляд, были недостаточно хорошо объяснены. Поэтому мне пришлось перерабатывать материалы с других сайтов и добавлять кое что от себя чтобы доработать данную статью. Честно говоря, даже не ожидал что эта статья вызовет такой большой интерес
https://microkontroller.ru/arduino-projects/posledovatelnaya-svyaz-po-protokolu-modbus-rs-485-s-vedomoj-arduino/
bus = Modbus(1,1,4); //Modbus slave ID as 1 and 1 connected via RS-485 and 4 connected to DE & RE pin of RS-485 Module
//адрес ведомого равен 1, используется связь через интерфейс RS-485 (вторая 1), 4 – номер контакта A
pvsm.ru/umny-j-dom/80884
//Задаём ведомому адрес, последовательный порт, выход управления TX
Modbus slave(ID, 0, 0);
У ATmega328 есть только один UART
https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino/blob/master/examples/simple_slave/simple_slave.ino
/**
* Modbus object declaration
* u8id : node id = 0 for master, = 1..247 for slave
* port : serial port
* u8txenpin : 0 for RS-232 and USB-FTDI
* or any pin number > 1 for RS-485
*/
Modbus slave(1,Serial,0); // this is slave @1 and RS-232 or USB-FTDI
Не совсем понял что вы хотите спросить. Да, у ATmega328 есть только один UART, но с помощью библиотеки последовательной связи у платы Ардуино можно организовать еще один последовательный порт с помощью ее двух любых цифровых контактов. Могу даже привести статью на нашем сайте, где это используется. Но какое отношение это имеет к теме рассматриваемой статьи про Modbus?
Спасибо за хорошую статью!
А как реализовать передачу информации от slave к master (состояние пинов, информацию с датчиков температуры и т.д.)
Спасибо!
Спасибо за добрые слова поддержки. Посмотрите вот эту статью — последовательная связь по протоколу Modbus RS-485 с Arduino (ведущей). Надеюсь, она решит вашу проблему.
В статье — «последовательная связь по протоколу Modbus RS-485 с Arduino (ведущей)» описана работа Arduino в режиме master, а мне нужно реализовать работу arduino в режиме slave (запись и чтение). В этой статье рассмотрен пример команды (0x10) — запись значений в несколько регистров хранения, а мне нужны команды чтения (0x03) или (0x04).
Да, действительно этот вопрос у нас на сайте пока не рассматривался. Попробую в ближайшее время найти в англоязычном сегменте интернета информацию по этому поводу и тогда добавлю ее в эту статью.
Спасибо за полезные комментарии, они помогают мне узнать чего не хватает на сайте и постепенно улучшать сайт
Здравстуйте, получилось узнать на счет передачи данных в режиме slave к master ?
Добрый день, был в отпуске поэтому пока не получилось узнать, но в ближайшие две недели постараюсь заняться этой проблемой