PDA

Просмотр полной версии : Чтение битовой маски в коде c#



k119_55524
24.04.2024, 18:50
Подключил через конвертер АС4(usb<->rs485) МУ110-32Р к компьютеру.
75396

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



using System;
using Modbus.Device;
using System.IO.Ports;
using System.Threading;
using System.Diagnostics;

namespace Experience
{
internal class Program
{
static void Main(string[] args)
{
string[] portNames = SerialPort.GetPortNames();

if (portNames.Length > 0)
{
SerialPort port = new SerialPort(portNames[0], 9600, Parity.None, 8, StopBits.One);

// Установка параметров порта
port.Handshake = Handshake.None;
port.ReadTimeout = 500; // Таймаут чтения (ms)
port.WriteTimeout = 500; // Таймаут записи (ms)

const byte addrDevice_MU110_32 = 1;
const ushort countReg = 32;
const ushort valReg = 1000;
ushort[] data = new ushort[countReg];
try
{
port.Open();
ModbusSerialMaster modbusMaster = ModbusSerialMaster.CreateRtu(port);

for (ushort i = 0; i < countReg; i += 2)
{
data[i] = valReg;
data[i + 1] = 0;
}

modbusMaster.WriteMultipleRegisters(addrDevice_MU1 10_32, 0, data);

ushort startAddress = 0;
Stopwatch stopwatch = new Stopwatch();
while (true)
{
Thread.Sleep(1000);

stopwatch.Restart();
stopwatch.Start();
data = modbusMaster.ReadHoldingRegisters(addrDevice_MU110 _32, startAddress, countReg);
stopwatch.Stop();
Console.WriteLine("<<<<< Время получения данных: " + stopwatch.Elapsed.TotalSeconds + "(sec).");

for (ushort i = 0; i < data.Length; i++)
{
data[i] = (ushort)(valReg - data[i]);
}

bool[] values = modbusMaster.ReadCoils(addrDevice_MU110_32, 0, countReg);

stopwatch.Restart();
stopwatch.Start();
modbusMaster.WriteMultipleRegisters(addrDevice_MU1 10_32, 0, data);
stopwatch.Stop();
Console.WriteLine(">>>>> Время отправки данных: " + stopwatch.Elapsed.TotalSeconds + "(sec).\n");
}
}
catch (Exception ex)
{
Console.WriteLine(">>>>> Error: " + ex.Message);
Console.ReadKey();
}
finally
{
if (port.IsOpen)
port.Close();
}
}
}
}
}


По сути программа бесконечно, с задержкой переключает выхода из включенного в выключенное, при этом чётные выхода в своем состоянии противоположны нечётным(смысл только в тестировании управления выходами).

https://youtu.be/dGfufG-3w-U

Используемые пакеты NUGET:
75394

Всё работает, проблем нет, за исключением:
попытка прочитать/записать битовую маску выходов приводит к exeptions по превышению времени ожидания запроса.
75397

Команда запроса(в примере кода присутствует):


bool[] values = modbusMaster.ReadCoils(addrDevice_MU110_32, 0, countReg);


Варианты проблемы:
1. Код NeGet пакетов нормально не поддерживает команду чтения маски.
2. Я не правильно чтото делаю в коде.

Что я понимаю под битовой маской:
75395

Вопрос: как мне, при моей схеме, в коде c# получить битовую маску?

Cs-Cs
24.04.2024, 20:55
Я могу быть не прав, но почему Coils-то?
Новые модули HW 2.0 эту команду НЕ поддерживают. Только регистры.

k119_55524
24.04.2024, 21:43
Уточняю.
Конфигуратор позволяет получить маску:
75399

В коде можно её получить?
Другим путём?
Судя по поведению конфигуратора маска и регистры имеют "не зависимые" значения.

Cs-Cs
24.04.2024, 22:00
Так маска этим модулем всегда же отдаётся в виде двух 16-битных регистров. А у тебя Coils упоминаются, которые им не поддерживаются.

k119_55524
24.04.2024, 22:09
Так маска этим модулем всегда же отдаётся в виде двух 16-битных регистров.
- как получить эти 2 слова в коде(пример, ссылка)?

Cs-Cs
24.04.2024, 22:25
Я не умею на C#. Ну так через Modbus и получить. Командой чтения двух регистров (слов).
Чтобы ответ был более точным - скажи хоть то, насколько ты уверенно знаешь:
* Продукцию ОВЕН
* Протокол Modbus и его команды

melky
24.04.2024, 23:02
Автор, вы должны читать регистры так, как того требует документация прибора.

Битовая маска это всего лишь абстракция. Это только значит, что в определенном регистре значение, представляет собой эту самую битовую маску, но это не означает, что надо пытаться прочитать каждый бит какими-то другими средствами протокола.


// Возвращает бит n значения val.
public double GetBit(double val, int n)
{
ulong ulVal = (ulong)val;
return (ulVal >> n) & 1ul;
}

допилите по необходимости

k119_55524
25.04.2024, 06:09
Пользуюсь всем этим пол дня. Никогда ничем подобным не занимался. Или по другому - впервые.

Чтобы прочитать состояние регистров использую:
data = modbusMaster.ReadHoldingRegisters(addrDevice_MU110 _32, startAddress, countReg);
и оно работает.

Для чтения маски использую ReadCoils и оно не работает. Вы указали что 2 версия приборов её не поддерживает. Спасибо за помощь.

Повторю в очередной раз вопрос как мне получить маску с помощью кода?
Просьба помочь конкретным советом)

k119_55524
25.04.2024, 06:15
Спасибо что уделили время. С абстракциями и манипуляциями битами у меня проблем нет, тут мне всё ясно.

У меня не получается прочитать регистры, а точнее я не знаю как это сделать(в итоге у меня нет исходных данных для работы с битами). Это то что меня интересует и о чем я прошу помощи.
У Вас есть возможность подсказать?

1exan
25.04.2024, 06:59
Уточняю.
Конфигуратор позволяет получить маску:
75399

В коде можно её получить?
Другим путём?
Судя по поведению конфигуратора маска и регистры имеют "не зависимые" значения.

Что значит независимые? 32 битная переменная (два регистра по 16 бит) и есть "маска"


Пользуюсь всем этим пол дня. Никогда ничем подобным не занимался. Или по другому - впервые.

Чтобы прочитать состояние регистров использую:
data = modbusMaster.ReadHoldingRegisters(addrDevice_MU110 _32, startAddress, countReg);
и оно работает.

Для чтения маски использую ReadCoils и оно не работает. Вы указали что 2 версия приборов её не поддерживает. Спасибо за помощь.

Повторю в очередной раз вопрос как мне получить маску с помощью кода?
Просьба помочь конкретным советом)

Ну так data - это и есть маска в виде массива байт (два прочитанных 16 битных регистра)

k119_55524
25.04.2024, 07:20
Что значит независимые? 32 битная переменная (два регистра по 16 бит) и есть "маска"



Ну так data - это и есть маска в виде массива байт (два прочитанных 16 битных регистра)

1. Если в конфигураторе отправить 1000(максимум) в коэффициент заполнения шим, то вход(ожидаемо) включится. Но при чтении из устройства бит маски регистра в 1 не переключается(скрин прилагаю). Подобную ситуацию можно назвать - не связаны, хотя по сути оба эти параметра управляют включением/отключением одного и тогоже физического выхода но разными путями. Тоесть я могу пользоваться управлением через параметры шим(вариант ReadHoldingRegisters). Понятно, что битовая маска более логична в использовании для простого управления выходами(шим какбы для другого)(вариант ReadCoils, но он как выше писали не поддерживается).
Конфигуратор позволяет читать маску. Значит такая возможность есть, надеюсь она не секретная.
75404

2. В моём случае(и других, рабочих, вариантов в интерфейсе библиотеки доступа к rs485 я не нашёл) ReadHoldingRegisters возвращает массив ushort размерностью 32(по количеству выходов на приборе). Это 16 х 32 = ..., тоесть больше чем 2 слова. И в массиве явно хранятся не битовые состояния маски а коэффициенты заполнения шим. Конечно, в итоге, можно интерпретировать этот массив в битовую маску но сдаётся мне что это не правильно. Правильно - прочитать битовую маску как есть. Я не знаю как это сделать. И в этом я прошу помощи.

1exan
25.04.2024, 08:09
1. Если в конфигураторе отправить 1000(максимум) в коэффициент заполнения шим, то вход(ожидаемо) включится. Но при чтении из устройства бит маски регистра в 1 не переключается(скрин прилагаю). Подобную ситуацию можно назвать - не связаны, хотя по сути оба эти параметра управляют включением/отключением одного и тогоже физического выхода но разными путями. Тоесть я могу пользоваться управлением через параметры шим(вариант ReadHoldingRegisters). Понятно, что битовая маска более логична в использовании для простого управления выходами(шим какбы для другого)(вариант ReadCoils, но он как выше писали не поддерживается).
Конфигуратор позволяет читать маску. Значит такая возможность есть, надеюсь она не секретная.
75404

2. В моём случае(и других, рабочих, вариантов в интерфейсе библиотеки доступа к rs485 я не нашёл) ReadHoldingRegisters возвращает массив ushort размерностью 32(по количеству выходов на приборе). Это 16 х 32 = ..., тоесть больше чем 2 слова. И в массиве явно хранятся не битовые состояния маски а коэффициенты заполнения шим. Конечно, в итоге, можно интерпретировать этот массив в битовую маску но сдаётся мне что это не правильно. Правильно - прочитать битовую маску как есть. Я не знаю как это сделать. И в этом я прошу помощи.

1. Насчет регистров параметров ШИМ - да, наверное они не связаны с регистром маски выходов.
2. В запросе data = modbusMaster.ReadHoldingRegisters(addrDevice_MU110 _32, startAddress, countReg); вы что вообще указываете? Нужно указать startAddress = 50 (если я не ошибаюсь, это адрес 1-го регистра маски выходов) и countReg = 2 (два 16-битных регистра). Тогда вы получите data размером 4 со значением маски (тут не уверен, возможно будет размер 2 - надо смотреть библиотеку)

Валенок
25.04.2024, 08:28
стартадрес 97
(32Р)

Cs-Cs
25.04.2024, 08:29
Я же спрашивал: КАКОВ УРОВЕНЬ ЗНАНИЙ?!
Нужно скачать самую свежую инструкцию на этот модуль и почитать её.
Из этого узнаем, что:
а) Если выставлено значение ШИМ - то управление по битовой маске не работает. Так сделано специально. Или ШИМ или Выкл-Выкл по маске, потому что это - разные действия.
б) Модуль понимает команды протокола Modbus: Read Holding Registers (0x04) или Write Multiple Registers (0x16)
в) Какие регистры модуля что означают (битовая маска - это регистры 97, 98 в десятичной системе счисления)

Дальше надо реализовать это на нужном языке программирования. Всё.
И вот тут не надо на меня за грубость ругаться. Я сначала спросил уровень знаний. Раз ничего явно не было сказано - то тогда уже получай ругань по полной. RTFM.

melky
25.04.2024, 08:46
k119_55524 иногда в приборах для работы через Coil надо посчитать под каким номером окажется bit в определенном регистре (применимо например в ПР). Но в плане модуля ввода/вывода скорее всего так нельзя, если маску положили в HoldingRegister то только так и можно прочитать. Дальше кодом сами уже гребете биты или записываете, и потом собранное отправляете в тот же Holding.

поддержу Валенка, не надо строить гопника из себя, независимо от уровня знания. К тому же у человека нет проблем с C#, а есть непонимание других вещей.

k119_55524
25.04.2024, 10:57
Уважаемое сообщество - огромная благодарность Вам за помощь.

1. История с чтением(записью) по адресам 97,98 работает. Там нашлась маска) Это то что я хотел получить и эти ответы максимально содержательны.
2. Ни в коем случае не принижаю важность чтения документации. Тут вопрос целесообразности текущей ситуации. Думаю что вариант с форумом получился продуктивнее.
3. Постараюсь оформить библиотеку для c# и выложить сюда ссылку на гит. Надеюсь наши знания пригодятся многим)

Всем спасибо!!!

Валенок
25.04.2024, 11:50
Ни в коем случае не принижаю важность чтения документации. Тут вопрос целесообразности текущей ситуации.
Причем в РЭ четко - 97..


Думаю что вариант с форумом получился продуктивнее.
Почти сутки ушли, продуктивнее...

Cs-Cs
25.04.2024, 13:23
k119_55524 Всё, что надо было - ЧЁТКО сформулировать вопрос и свой уровень знаний!
Жаль, что на это ушло так много времени, но хорошо, что понимание пришло!
Так держать!