Если информация была полезной для вас, вы можете поблагодарить за труды Юmoney: 41001164449086

Работаем с COM портом RS-232 напрямую из PHP для Peacefair pzem-004t

Иногда встречаются экзотические ситуации, когда приходиться работать напрямую с оборудованием используя языки программирования, совсем не предназначенные для этого, как например взаимодействие c COM портом в PHP. Некоторые скажут, что это невозможно, более продвинутые будут использовать посредников, эстеты предпочтут стороннюю библиотеку.

На самом деле всё не так страшно, и я опишу как взаимодействовать c COM RS-232 из PHP без сторонних библиотек и посредников в Linux, на примере вольтметра-амперметра Peacefair pzem-004t.

Сразу оговорюсь, что использовать PHP для работы с оборудованием по протоколу RS-232 далеко не самая лучшая затея, и для этого более предпочтительно использовать, например, C. Но если очень надо, то почему бы и нет?

Небольшое отступление касательно самого Peacefair pzem-004t, это вольтметр-амперметр для измерения параметров электрической сети 220В.


Рис. 1.

Обмен данными с устройством происходит по протоколу RS-232 TTL, это обычный COM порт, но только не с уровнями +12В -12В, а +5V либо +3.3В (чаще), в зависимости от реализации устройства.

В случае Peacefair pzem-004t TTL уровни +3.3В, однако доп питание +5В.


Рис.2

Для того чтобы подключить подобное устройство достаточно USB-TTL конвертора.


Рис. 3.

В системе такое устройство будет отображаться как обычный последовательный порт.


Рис. 4.

Ну да мы отвлеклись, работать я буду в консоли Linux на Raspberry Pi 3.

Собственно, простой код, который вы можете в последствии трансформировать в что-то более серьёзное.

 <?php
$dev = '/dev/ttyUSB0';

function dev($dev, $tx){
    exec("stty -F $dev 9600 raw -echo");
    if ($handle = fopen($dev, "r+")){
        fwrite($handle, $tx);
        $rx = fread($handle, 7 );
        fclose($handle);
        //echo bin2hex($rx).PHP_EOL;
        if (check($rx) === true)
            return $rx;
        else
            return false;
    }
    else
        return false;
}

function check($in){
    $arr = str_split(bin2hex($in),2);
    $summ = 0;
    for ($i = 0; $i <= 5; $i++)
        $summ += hexdec($arr[$i]); //hex to dec    
    if (substr(dechex($summ),-2) == $arr[6]) //last 2 chr. from hex
        return true;
    else
        return false;
}

//voltage
$arr = str_split(bin2hex(dev($dev,hex2bin('B0C0A80101001A'))),2);
$voltage = hexdec($arr[1].$arr[2]) + hexdec($arr[3])/10;
//current
$arr = str_split(bin2hex(dev($dev,hex2bin('B1C0A80101001B'))),2);
$current = hexdec($arr[2]) + hexdec($arr[3])/100;
//active
$arr = str_split(bin2hex(dev($dev,hex2bin('B2C0A80101001C'))),2);
$active = hexdec($arr[1].$arr[2]);
//energy
$arr = str_split(bin2hex(dev($dev,hex2bin('B3C0A80101001D'))),2);
$energy = hexdec($arr[1].$arr[2].$arr[3]);

echo 'Voltage:'.$voltage.PHP_EOL;
echo 'Current:'.$current.PHP_EOL;
echo 'Active:'.$active.PHP_EOL;
echo 'Energy:'.$energy.PHP_EOL;
?>


Разберём код по порядку:
/dev/ttyUSB0 – устройство с которым я буду работать,
dev($dev, $tx) – функция задачей которой будет принять аргументы: имя устройства и данные для отправки, после чего вернуть принятые данные.
exec("stty -F $dev 9600 raw -echo") – мы настраиваем работу порта, указывая 9600 – скорость , raw – входные и выходные данные передаются напрямую как есть, без обработки, -echo не пересылать себе переданные собой же данные.

Далее мы работаем с устройством как с обычным файлом
fwrite($handle, $tx) – передаём данные
fread($handle, 7 ) – принимаем данные, 7 – поскольку в моём случае на каждый посыл команды меня интересует ответ в 7-мь байт.

Дальнейший код больше относиться к особенностям pzem-004t.
Функйия check($in) – проверяет корректность принятых данных по контрольной сумме байтов с 0-6 которая должна быть равна 7-му. Особой необходимости в ней нет, но если производитель использует контроль целостности, то можно реализовать проверку.

Далее, я поочерёдно посылаю запросы (предварительно переведя их из hex в bin’арные данные) на устройство и принимаю данные для вычисления:
hex: B0C0A80101001A – запрос напряжения
hex: B1C0A80101001B – запрос тока
hex: B2C0A80101001C – запрос текущей потребляемой мощности
hex: B3C0A80101001D – запрос потреблённой электроэнергии

Более подробно узнать о запросах, ответах, и том как их интерпретировать можно в документации: Peacefair pzem-004t specification

Ну и собственно результат выполнения.


Рис.5.

Как видите нет ничего сложного. Все желающие могут использовать этот код, сославшись в случае публикации на первоисточник.

Добавить комментарий


Если информация была полезной для вас, вы можете поблагодарить за труды Юmoney: 41001164449086