Найти в Дзене
7-100

Работа с ModBUS-TCP "ОВЕН" МК210-311 из браузера

В прошлой статье писал о подключении и чтении данных с прибора "ОВЕН" МВ-110-8А по ModBUS RTU RS485 с использованием преобразователя ОВЕН АС4 https://dzen.ru/a/aCXqApd28zMRehU6. В этой статье будет использоваться протокол ModBUS-TCP, то есть подключение через Ethernet интерфейс. Будем использовать модуль дискретных вводов-выводов "ОВЕН" МК210-311. Обмен можно настроить с любым прибором с поддержкой ModBUS-TCP, просто данные приборы у меня есть под рукой. Здесь сразу же опишем, как можно обмениваясь пакетом в 16 бит, расшифровывать и управлять дискретными выходами побитно. Установку Apache, PHP, modbus-cli опишу еще раз, чтобы не пришлось читать другие статьи, у кого уже установлено и настроено, то можете сразу переходить к Настройке прибора. Установка web-сервера Apache 2 на Linux В терминале вводим команду sudo apt-get install apache2 После установки нам нет необходимости можно проверить установку. Вводим в браузере localhost, Должна появится страница приветствия. Настраивать подключе

В прошлой статье писал о подключении и чтении данных с прибора "ОВЕН" МВ-110-8А по ModBUS RTU RS485 с использованием преобразователя ОВЕН АС4 https://dzen.ru/a/aCXqApd28zMRehU6. В этой статье будет использоваться протокол ModBUS-TCP, то есть подключение через Ethernet интерфейс. Будем использовать модуль дискретных вводов-выводов "ОВЕН" МК210-311. Обмен можно настроить с любым прибором с поддержкой ModBUS-TCP, просто данные приборы у меня есть под рукой. Здесь сразу же опишем, как можно обмениваясь пакетом в 16 бит, расшифровывать и управлять дискретными выходами побитно.

Установку Apache, PHP, modbus-cli опишу еще раз, чтобы не пришлось читать другие статьи, у кого уже установлено и настроено, то можете сразу переходить к Настройке прибора.

Установка web-сервера Apache 2 на Linux

В терминале вводим команду

sudo apt-get install apache2

После установки нам нет необходимости можно проверить установку. Вводим в браузере localhost, Должна появится страница приветствия. Настраивать подключения нет необходимости, потому что будем работать на одном компьютере.

Для программирования нам понадобится скриптовый язык PHP. Установка осуществляется командой:

sudo apt-get install php

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

1.
Удобнее, когда apache запускается от основного пользователя (по умолчанию www-data). Для изменения из терминала открываем файл конфигурации

sudo nano /etc/apache2/envvars

Меняем переменные

export APACHE_RUN_USER=(имя пользователя)

export APACHE_RUN_GROUP=(имя пользователя)

сохраняем файл.

2. Заходим в папку /var. Папку www открыть как root с контекстного
меню. В открытой папке находим папку html. Открываем свойства из
контекстного меню. В правах задаем полный доступ к папкам и файлам для пользователя от которого работаем (для начала можно и для всех задать). Закрываем окно папки открытое от администратора. Теперь нужно перезапустить сервисы, легче перезагрузить компьютер.

Теперь можно написать первую программу. Открываем папку /var/www/html. В ней создаем папку Primer. Заходим в эту папку, в ней созаем файл index.php. В файле можете написать

<?php echo 'Привет, МИР!'; ?>

и сохранить его. Затем в браузере набираем адрес localhost/Primer, и мы должны увидеть на странице браузера "Привет, МИР!".

Мы убедились, что apache и php работают.

Подключение приборов

В прошлой статье https://dzen.ru/a/aCLZIGBtABZip2Gz описывал как подключал и настраивал приборы. Здесь опишу в общих чертах.

Для работы с устройствами по протоколу Modbus используем консольную python-утилиту modbus-cli

Установка:

sudo apt install python3-pip
sudo pip3 install modbus_cli

Настройка прибора

По умолчанию IP-адрес МК210-311 - 192.168.1.99 и маска подсети
255.255.0.0. Настраиваем сетевой адаптер Linux компьютера, чтобы он был участником подсети: задаем адрес 192.168.1.XXX, маску подсети 255.255.0.0.

Номера регистров МК210-311: для чтения входов - 51, для чтения и записи выходов - 470 (Номера узнаем из инструкции на модуль МК210-311).

Теперь можем в терминале вводить команды для обмена

modbus -s 1 -v 192.168.1.99:502 51

-s 1 - это адрес слэйва

502 - порт ModBUS TCP

51 адрес регистра, (правильнее вводить i@51 для чтения).

Для включения выходов команда

modbus -s 1 -v 192.168.1.99:502 h@470=1

включится первый выход, для побитной передачи использую преобразование от двоичного кода в dec, нужно учесть что передается старшим байтом вперед, то есть если хотим включить 1 выход то передаем данные 00000001, если хотим последний, то передаем 10000000 то есть число 128

modbus -s 1 -v 192.168.1.99:502 h@470=128

для чтения состояния выходов используем команду:

modbus -s 1 -v 192.168.1.99:502 i@470

За один такт по ModBUS передается 16 бит информации, это нужно учитывать при обмене с модулями. Самый простой и однозначный обмен - передача и чтение целочисленных данных.

Программа обмена

В папке html создаем еще один файл opros.php. В него записываем скрипт опроса, который будет происходить фоново на открытой странице.

<?php

echo "Входы от МК210-311:<br>";

$Chtenie = shell_exec("modbus -s 1 -v 192.168.1.99 i@51");

$KonProbel = strripos($Chtenie, ' ');

$Chtenie = substr($Chtenie, $KonProbel, 10);

//$Chislo = hexdec($Chtenie); // Вариант с промежуточным преобразованием в dec

//$ChisloBin = decbin($Chislo);

//echo "$ChisloBin<br>";

$ChisloBin = base_convert($Chtenie, 16, 2); // Преобразуем ответ в побитную форму

//echo "$ChisloBin<br>";

echo " 1 2 3 4 5 6";

$Vhody = " 0 0 0 0 0 0";

$DlinaChisloBin = strlen($ChisloBin);

for ($i=1; $i <= $DlinaChisloBin; $i++){

$VhBit = substr($ChisloBin, -$i, 1);

//echo $VhBit;

$Vhody = substr_replace($Vhody, $VhBit, $i*2-1, 1); // Указываем состояния входов

}

echo "<br>$Vhody<br><br>";

echo "Выходы МК210-311:<br><br>";

$Chtenie = shell_exec("modbus -s 1 -v 192.168.1.99:502 i@470");

$KonProbel = strripos($Chtenie, ' ');

$Chtenie = substr($Chtenie, $KonProbel, 10);

$ChisloBin = base_convert($Chtenie, 16, 2);

$Dlina=strlen( $ChisloBin );

$ChisloBin = substr_replace('00000000', $ChisloBin, -$Dlina); // Чтобы увидеть полный код, при 1 (будет 00000001)

//echo "$ChisloBin<br>";

$VyhodBin=strrev($ChisloBin);

echo '<table border="1" cellpadding="0" cellspacing="0">';

echo '<tr>';

for($nomer=1; $nomer <= 8; $nomer++){

$VyhBit = substr($VyhodBin, $nomer-1, 1);

$bgcolor = '#FFFFFF';

if ($VyhBit== '1') { $bgcolor = '#66FF00'; }

echo "<td align=\"center\" style =\"background-color:$bgcolor; width:80px; height:10px; border: '#FFFFFF';\"></td>";

}

echo '</tr>';

echo '</table>';

?>

В файле index.php напишем скрипт для запуска фоновой задачи opros.php и в нем добавим обработку нажатия кнопок для управления выходами

<div class="container" >

<div class="row">

<div class="col-12">

<h2>

<div id="content"></div>

</h2>

</div>

</div>

</div>

<script type="text/javascript"

src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<script>

function timer(){ // функция, которая запрашивает данные с сервера

$.ajax({ // вызываем встроенную функцию, которая поможет нам получить данные с сервера

url: "opros.php", // какой скрипт серверу нужно выполнить

cache: false, // предыдущие ответы не сохраняем

success: function(html){ // если всё хорошо, отправляем ответ от сервера на страницу в блок content

$("#content").html(html);

}

});

}

$(document).ready(function(){ // как только страница полностью загрузилась

timer();

setInterval('timer()',1000); // начинаем каждую секунду запрашивать новые данные

});

</script>

<?php

echo "<form method=\"post\" onkeypress=\"if(event.keyCode == 13) return false;\">"; // Ввод без нажатия энтер

echo '<table border="1" cellpadding="0" cellspacing="0">';

echo '<tr>';

for($nomer=1; $nomer <= 8; $nomer++){

echo "<td align=\"center\" width=\"80\"><input type = \"submit\" style =\"width:78px; height:40px;\" name = \"but$nomer\" value = \"$nomer\"/></td>";

}

echo '</tr>';

echo '</table>';

// Передача данных из чекбокса без учета нажатых кнопок

echo "<br><br><br><br>";

echo '<table border="1" cellpadding="0" cellspacing="0">';

echo '<tr>';

for($nomer=1; $nomer <= 8; $nomer++){

$VyhBit = substr($VyhodZadan, $nomer-1, 1);

if ($VyhBit== '1') {
echo "<td align=\"center\" width=\"60\" style =\"background-color: $bgcolor\">$nomer<br><input type=\"checkbox\" name = \"activ1$nomer\" style =\"width:31px; height:40px;\" checked></td>";

}

else{

echo "<td align=\"center\" width=\"60\" style =\"background-color: $bgcolor\">$nomer<br><input type=\"checkbox\" name = \"activ1$nomer\" style =\"width:31px; height:40px;\"></td>";

}

if (isset($_POST["activ1$nomer"])){$activ1V[$nomer] = '1';}
else {$activ1V[$nomer] = '0';}

$VyhodZadan=$VyhodZadan.$activ1V[$nomer] ;

}

echo '</tr>';

echo '</table>';

//echo "<br>$VyhodZadan";

echo "<br><input type = \"submit\" name = \"button1\" value = \"ЗАПИСАТЬ\"/><br>";

echo '</form>';

// обработка нажатий кнопок

for($nomer=1; $nomer <= 8; $nomer++){

if ($_POST["but$nomer"]){

$Chtenie = shell_exec("modbus -s 1 -v 192.168.1.99 i@470"); // Читаем текущее состояние выходов

$KonProbel = strripos($Chtenie, ' ');

$Chtenie = substr($Chtenie, $KonProbel, 10);

$ChisloBin = base_convert($Chtenie, 16, 2);

$Dlina=strlen( $ChisloBin );

$ChisloBin = substr_replace('00000000', $ChisloBin, -$Dlina); // Чтобы увидеть полный код, при 1 (будет 00000001)

$VyhodBin=strrev($ChisloBin);

$VyhodSost = substr($VyhodBin, $nomer-1, 1);

if ($VyhodSost == '1' ){ // Условие для инверсии переключения

$perekluch = 0;

} else {

$perekluch = 1;

}

$VyhodBin = substr_replace($VyhodBin, $perekluch, $nomer-1, 1); // Вставляем нужное состояние при нажатии кнопки в текщую комбинацию

$VyhodyMK=strrev($VyhodBin);

$Vyhody = bindec($VyhodyMK);

shell_exec("modbus -s 1 -v 192.168.1.99 h@470=$Vyhody"); // Записываем в прибор в виде dec числа

}

}

// Передача из чекбокса

if ($_POST['button1']){

$VyhodMK=strrev($VyhodZadan);

$Vyhody = bindec($VyhodMK);

shell_exec("modbus -s 1 -v 192.168.1.99:502 h@470=$Vyhody");

}

?>

Сохраняем и обновляем страницу в браузере localhost/Primer.

Должно получиться:

-2

Обработка входов не прорисована, выведены состояния входов. После чтения происходит преобразование в бинарный код, он переворачивается, так как происходит передача старшим битом вперед, и выводится на экран. Выходы прорисованы в виде закрашиваемых ячеек таблицы.

Чтение входов и выходов происходит фоново - файл opros.php

Управление выходами происходит в основном скрипте файл - index.php. Кнопки под соответствующими индикаторами включения каналов запускают скрипт проверки состояния выходов на данный момент, изменения состояния соответствующего бита и отправки необходимого сочетания включенных и выключенных выходов в виде числа. При изменении состояния происходит перезагрузка страницы. Можно заморочиться и сделать нажатия кнопок без перезагрузки страницы, но здесь заморачиваться не стал

Ячейки с чекбоксами формируют необходимую комбинацию и отправляют команду на прибор, без учета текущего состояния.

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

Таким образом получилось управлять модулем дискретных вводов-выводов через Ethernet порт. Это уже дает возможность сделать контроллер управления каким либо устройством с одноплатных компьютеров вроде Raspberry Pi. При этом основную программу создавать без дополнительных программ типа CodeSys, Beremiz. Вообще, конечно же у Raspberry Pi есть свои GPIO выходы и можно управлять с них. Но гораздо надежней использовать модули ввода-вывода. А если использовать программируемые реле, то одноплатник можно использовать как устройство верхнего уровня. Распределенными тех процессами будут управлять программируемые реле, функцию согласования, сбора данных, интерфейса пользователя будет выполнять одноплатный компьютер с сенсорным дисплеем.