1. Обязательно представиться на русском языке кириллицей (заполнить поле "Имя").
  2. Фиктивные имена мы не приветствуем. Ивановых и Пупкиных здесь уже достаточно.
  3. Не писать свой вопрос в первую попавшуюся тему - вместо этого создать новую тему.
  4. За поиск, предложение и обсуждение пиратского ПО и средств взлома - бан без предупреждения.
  5. Рекламу и частные объявления "куплю/продам/есть халтура" мы не размещаем ни на каких условиях.
  6. Перед тем как что-то написать - читать здесь и здесь, а студентам - обязательно здесь.
  7. Не надо писать в ЛС администраторам свои технические вопросы. Администраторы форума отлично знают как работает форум, а не все-все контроллеры, о которых тут пишут.

Подключение к modbus из службы

RS-485, ProfiBUS, 4-20 mA, Wi-Fi, GSM и так далее
Ответить

Автор темы
andrej35
Сообщения: 2
Зарегистрирован: 15 фев 2016, 10:37
Имя: Андрей
Благодарил (а): 2 раза

Подключение к modbus из службы

Сообщение andrej35 »

Добрый день.
Имеется компьютер с modbus slave, нужно написать службу (сервис) modbus master, которая будет запущена на другом пк и будет писать данные в базу. Использую класс ModbusTCP. Проблема заключается в том что при добавление соединения к modbus перестает отрабатывать таймер timer1_Elapsed. В данный момент в файл service и в бд, пишется дата и время. + Должен записываться данные из регистра в файл. Пробовал использовать try и catch но записывается только (Сервис стартовал и Сервис остановлен). Программа эмуляции слейва modbus slave. Подскажите в чем проблема. Спасибо.
[+] код C#
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Data.OracleClient;
using System.Text;
using System.Threading;
using ModbusTCP;

namespace WindowsService3
{

public partial class Service1 : ServiceBase
{
private ModbusTCP.Master MBmaster;
private byte[] data;
string res=" ";
private StreamWriter file;
private System.Timers.Timer timer1;

OracleConnection connnection = new OracleConnection("Соединение с бд");

public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
file = new StreamWriter(new FileStream(@"c:\Service.txt", System.IO.FileMode.Append));
this.file.WriteLine("Сервис стартовал" +" "+ DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"));
this.file.Flush();
this.timer1 = new System.Timers.Timer();
this.timer1.Enabled = true;
this.timer1.Interval = 10000;
this.timer1.Elapsed +=new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
this.timer1.AutoReset = true;
this.timer1.Start();
}

private bool SaveDateTime(DateTime dt)
{
OracleCommand ocmn = new OracleCommand();
OracleDataAdapter oda = new OracleDataAdapter();
DataSet ds = new DataSet();
ocmn.CommandText = "test.mod1";
ocmn.CommandType = CommandType.StoredProcedure;
ocmn.Connection = connnection;
oda.SelectCommand = ocmn;
ocmn.Parameters.Add("dt", OracleType.DateTime);
ocmn.Parameters["dt"].Value = dt;
if (connnection.State != ConnectionState.Open)
connnection.Open();
try
{
ocmn.ExecuteNonQuery();
return true;
}
catch (Exception e)
{
return false;
}
finally
{
connnection.Close();
}
}

private void ShowAs(object sender, System.EventArgs e)
{
double[] iword = new double[1];
string[] word = new string[1];
if (data.Length < 2) return;
iword = new double[data.Length / 2];
word = new string[data.Length / 2];
for (int x = 0; x < data.Length; x = x + 2)
{
iword[x / 2] = data[x] * 256 + data[x + 1];
word[x / 2] = iword[x / 2].ToString();
}
res = word[0].ToString();
}

private void MBmaster_OnResponseData(ushort ID, byte unit, byte function, byte[] values)
{
data = values;
ShowAs(null, null);
}

private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
MBmaster = new Master("127.0.0.1", 502);
MBmaster.OnResponseData += new ModbusTCP.Master.ResponseData(MBmaster_OnResponseData);
MBmaster.ReadHoldingRegister(3, 1, 0, 1);

bool check = SaveDateTime(DateTime.Now);

if (check == true)
{

this.file.WriteLine(res,DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") + " OK!!! ");
}
else
{
this.file.WriteLine(res,DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") + " NET!!! ");
}
this.file.Flush();
}

protected override void OnStop()
{
this.timer1.Stop();
this.file.WriteLine("Сервис остановлен" + " " + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"));
this.file.Flush();
this.file.Close();

}
}
}
Аватара пользователя

Jackson
администратор
администратор
Сообщения: 17481
Зарегистрирован: 17 июн 2008, 16:01
Имя: Евгений свет Брониславович
Страна: Россия
город/регион: Санкт-Петербург
Благодарил (а): 749 раз
Поблагодарили: 1281 раз

Подключение к modbus из службы

Сообщение Jackson »

Зайду глобально.

Можно же просто взять для этого СКАДА и настроить только опрос и запись в БД.
А разработка займёт время, то есть денег тоже стоит, и потом никакой техподдержки.
По вопросам работы Форума можно обратиться по этим контактам.
Аватара пользователя

VADR
администратор
администратор
Сообщения: 4712
Зарегистрирован: 25 июл 2008, 07:12
Имя: Диев Александр Васильевич
Страна: Россия
город/регион: г. Сегежа, Карелия
Благодарил (а): 192 раза
Поблагодарили: 336 раз

Подключение к modbus из службы

Сообщение VADR »

В ту же корзину: можно взять готовый OPC-сервер для modbus (каковых существует более одной штуки) и готовую систему хранения данных, умеющую забирать данные по OPC (таких тоже более одной). На первый взгляд это может показаться дороже, чем собственная разработка, но в дальнейшем, когда источников данных станет больше, а список требований - длиннее...
Повторное использование кода не отменяет повторного использования мозга при его повторном использовании.

Автор темы
andrej35
Сообщения: 2
Зарегистрирован: 15 фев 2016, 10:37
Имя: Андрей
Благодарил (а): 2 раза

Подключение к modbus из службы

Сообщение andrej35 »

Спасибо за ответы.
Если бы была возможность, то конечно же поставил OPC- сервер, но в данном случае такой возможности нету.
Нужно просто данные из регистров в базу писать по таймеру. Буду дальше разбираться.
Аватара пользователя

MuadDib
частый гость
частый гость
Сообщения: 462
Зарегистрирован: 31 июл 2010, 09:12
Имя: Павел
Страна: РФ
Благодарил (а): 8 раз
Поблагодарили: 13 раз

Подключение к modbus из службы

Сообщение MuadDib »

А откуда вы знаете, что у вас перестал отрабатывать таймер? Чтобы в этом убедиться, нужно написать что-нибудь в файл в самом начале метода обработчика.

Далее. Поле res вы используете неправильно. Обработчик OnResponseData должен что-то с ним делать, но код file.WriteLine() обращается к содержимому поля сразу же, не дожидаясь реакции обработчика. Ну и создание нового объекта Master на каждом событии таймера без последующей очистки - явный косяк.

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

И еще один момент. Не стоит юзать Timer таким образом. Лучше создайте в методе OnStart() поток и работайте в нем. Вам же проще будет.

SaNNy
освоился
освоился
Сообщения: 230
Зарегистрирован: 01 фев 2010, 10:37
Имя: Александр
Страна: Россия
город/регион: Брянск
Благодарил (а): 9 раз
Поблагодарили: 26 раз

Подключение к modbus из службы

Сообщение SaNNy »

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

Некоторые комментарии по коду:
1. Создание объекта Modbus Master на каждом интервале таймера оборачивается ненужной фрагментацией памяти и в конце концов перестает работать.
2. Обработка ошибок практически отсутствует. Для логирования лучше использовать готовые инструменты, например NLog, System.Diagnostic.Trace и др.
3. Создание подключения к базе данных на каждом интервале таймера, зачем так неэкономно тратить ресурсы компьютера?
4. Запись в бд и в файл в обработчике timer1_Elapsed плохо. Лучше в нем запускать отдельный поток и в нем выполнять эти действия.
5. Для конкатенции строк лучше использовать StringBuilder
6. Переменным лучше давать осмысленные имена и придерживаться General Naming Conventions (https://msdn.microsoft.com/en-us/librar ... 10%29.aspx)
7. Параметры сервиса, такие как ip адрес, порт и пр. лучше выносить в отдельный кофигурационный файл.
Ответить

Вернуться в «Интерфейсы, протоколы, связь»