Об этом проекте.
Modbus — стандартный протокол последовательной связи. В настоящее время стал общедоступным средством подключения промышленных электронных устройств. В Modbus RTU и Modbus ASCII интерфейс RS485 используется как физический уровень. Этот интерфейс можно использовать Arduino как Slave (а с некоторыми ограничениями и как Master) в приложениях Modbus. В качестве последовательной связи будем использовать плату RS422/RS485 Shield. Она предназначена для использования с Arduino UNO и другими совместимыми платами, такими как Arduino 101, STM Nucleo и т. д. Плата имеет гальваническую развязку между шиной RS485 и Arduino. Без такой изоляции возможно повреждение Arduino или неисправность устройства из-за больших расстояний шины RS485. Кроме того, имеется возможность подключить и полнодуплексный интерфейс — RS422.
Цель этой статьи — показать, как создать простое ведомое устройство Modbus на основе Arduino UNO. Будем использовать ПК в качестве мастера Modbus.
Демонстрация
Инструменты и материалы
- Плата Arduino UNO
- Плата RS485 Shield for Arduino
- Любой USB-RS485-Адаптер для присоединения к ПК
Дополнительно:
- Монтажная платаd
- Кнопка
- Светодиод красного цвета
- Резистор 220 Ом
- Резистор 10 кОм
- Соединительные провода
Схема соединений для RS485
Схема очень проста. Необходимо просто подключить линии А и В адаптера USB-RS485 с такими же линиями платы. Линии Z и Y не используются в нашем случае. Для больших расстояний рекомендуется использовать витую пару.
Подключение Arduino (опция)
Рекомендуется добавить светодиод и кнопку для Arduino, чтобы увидеть некоторые эффекты связи Modbus. Это необязательно, но визуально будет лучше.

Установка DIP-переключателей
Плата RS422/RS485 выполнена с тремя группами DIP-переключателей. Нужно установить эти DIP-переключатели для Modbus, как показано на рисунке ниже.
- Группа 1: 1-Off 2-On 3-On 4-Off
- Группа 2: 1-Off 2-Off 3-On 4-ON
- Группа 3: 1-Off или On * 2-Off 3-Off 4-Off
* В зависимости от положения платы RS422/RS485 в сети Modbus нужно включить или выключить оконечный резистор. Переключите резистор в положение On только в том случае, если плата находится на конце шины. Во всех остальных случаях выключите оконечный резистор

Настройки перемычек
На плате есть 3 группы перемычек. Очень важно правильно выставить перемычку JP1, отвечающую за напряжение питания. Arduino UNO работает с напряжением 5V. Поэтому нужно установить JP1 на 5V (а для плат с питанием 3.3V, например, Arduino 101, в положение 3.3V).
Кроме того, установите перемычки для портов связи в верхнем левом углу, как показано на рисунке выше. Внутренний UART на портах 0 и 1 будет подключен в этом случае к интерфейсу RS485 платы.
И последнее, но не менее важное, необходимо установить перемычку для управляющего порта RX/TX. Мы не используем эту перемычку, потому что настроено автоматическое переключение RX/TX.
Установите программное обеспечение Modbus Tester на ПК
В нашем случае будем использовать ПК в качестве мастера Modbus. Вам нужно скачать Modbustester. После скачивания распакуйте zip-архив в новый каталог на вашем жестком диске. Откройте программное обеспечение и измените отмеченные поля, как показано на рисунке ниже. Вам необходимо подключить USB-RS485-адаптер к ПК. Выберите правильный COM-порт для этого адаптера в Modbustester.
Программное обеспечение Arduino
Загрузите прошивку в среду разработки Arduino для компиляции и программирования платы.
Пришло время проверить вашу работу!
Вы можете нажать кнопку «Read» в Modbustester. Эта команда будет читать 8 байтов памяти нашего нового ведомого устройства. В адресе 400008 вы можете найти статус кнопки. Адрес 400001 — 400006 содержит значения портов ADC.
С помощью кнопки «Write» вы можете управлять регистрами в подключенном устройстве. Вы можете записать 0 или 1 по адресу 400007, чтобы включить или выключить светодиод.
Код прошивки
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
/* * Test program for Arduino RS422/RS485 Shield * Version 1.0 * Copyright (C) 2018 Hartmut Wendt www.zihatec.de * * (based on sources of https://github.com/angeloc/simplemodbusng) * * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <SimpleModbusSlave.h> #define ledPin 12 // onboard led #define buttonPin 7 // push button /* This example code has 9 holding registers. 6 analogue inputs, 1 button, 1 digital output and 1 register to indicate errors encountered since started. Function 5 (write single coil) is not implemented so I'm using a whole register and function 16 to set the onboard Led on the Atmega328P. The modbus_update() method updates the holdingRegs register array and checks communication. Note: The Arduino serial ring buffer is 128 bytes or 64 registers. Most of the time you will connect the arduino to a master via serial using a MAX485 or similar. In a function 3 request the master will attempt to read from your slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES and two BYTES CRC the master can only request 122 bytes or 61 registers. In a function 16 request the master will attempt to write to your slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS, NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write 118 bytes or 59 registers. Using the FTDI USB to Serial converter the maximum bytes you can send is limited to its internal buffer which is 60 bytes or 30 unsigned int registers. Thus: In a function 3 request the master will attempt to read from your slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES and two BYTES CRC the master can only request 54 bytes or 27 registers. In a function 16 request the master will attempt to write to your slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS, NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write 50 bytes or 25 registers. Since it is assumed that you will mostly use the Arduino to connect to a master without using a USB to Serial converter the internal buffer is set the same as the Arduino Serial ring buffer which is 128 bytes. */ // Using the enum instruction allows for an easy method for adding and // removing registers. Doing it this way saves you #defining the size // of your slaves register array each time you want to add more registers // and at a glimpse informs you of your slaves register layout. //////////////// registers of your slave /////////////////// enum { // just add or remove registers and your good to go... // The first register starts at address 0 ADC0, ADC1, ADC2, ADC3, ADC4, ADC5, LED_STATE, BUTTON_STATE, TOTAL_ERRORS, // leave this one TOTAL_REGS_SIZE // total number of registers for function 3 and 16 share the same register array }; unsigned int holdingRegs[TOTAL_REGS_SIZE]; // function 3 and 16 register array //////////////////////////////////////////////////////////// void setup() { /* parameters(long baudrate, unsigned char ID, unsigned char transmit enable pin, unsigned int holding registers size, unsigned char low latency) The transmit enable pin is used in half duplex communication to activate a MAX485 or similar to deactivate this mode use any value < 2 because 0 & 1 is reserved for Rx & Tx. Low latency delays makes the implementation non-standard but practically it works with all major modbus master implementations. */ modbus_configure(9600, 1, 6, TOTAL_REGS_SIZE, 0); pinMode(ledPin, OUTPUT); pinMode(buttonPin, INPUT); } void loop() { // modbus_update() is the only method used in loop(). It returns the total error // count since the slave started. You don't have to use it but it's useful // for fault finding by the modbus master. holdingRegs[TOTAL_ERRORS] = modbus_update(holdingRegs); for (byte i = 0; i < 6; i++) { holdingRegs[i] = analogRead(i); delayMicroseconds(50); } byte buttonState = digitalRead(buttonPin); // read button states // assign the buttonState value to the holding register holdingRegs[BUTTON_STATE] = buttonState; // read the LED_STATE register value and set the onboard LED high or low with function 16 byte ledState = holdingRegs[LED_STATE]; if (ledState) // set led { digitalWrite(ledPin, HIGH); } else if (ledState == 0) // reset led { //digitalWrite(ledPin, LOW); holdingRegs[LED_STATE] = 0; } } |
Хорошая статья!