Разработка методики кроссплатформенной библиотеки для интеграции устройств на основе протокола Modbus TCP в состав приложений систем управления
Класс Master содержит в себе список контроллеров, за которыми осуществляется наблюдение. Функции AddPLC() и DeletePLС() позволяют редактировать список этих контроллеров. Контроллеры описываются классом PLC. Поле Name содержит имя контроллера, поле State отображает наличие связи с ПЛК, а поле IPAdress хранит его сетевой адрес. Связь с контроллером осуществляется средствами класса TCPConnection, который содержит в себе функции для работы с коммуникационным каналом. Классы Configuration, Spindle, Tool, Coolant содержат в себе информацию о выполнении технологических команд получаемую от ПЛК. Класс Spindle используется для описания работы шпинделя станка. Поле Speed содержит в себе скорость вращение шпинделя, поле Rotation направление его вращения. Поле InterpolationMode показывает, является ли шпиндель в данный момент осью интерполяции. Поле State отображает, вращается или остановлен шпиндель в данный момент. Поле Type помогает определить принадлежность экземпляра классу. Поле ID содержит в себе порядковый номер шпинделя. Класс Tool используется для описания работы магазина инструментов. Поле Number содержит номер инструмента, который должен быть установлен в зажиме. Поле State отображает ход выполнения операции смены инструмента. Поле Type помогает определить принадлежность экземпляра классу. Поле ID содержит в себе порядковый номер магазина инструментов. Класс Coolant используется для описания работы подачи СОЖ. Поле State отображает, идет ли подача охлаждающей жидкости в зоне обработки. Поле Type помогает определить принадлежность экземпляра классу. Поле ID содержит в себе порядковый номер вывода подачи СОЖ. Класс Configuration содержит в себе информацию необходимую для получения диагностических данных от ПЛК. Поле Spindle содержит в себе число экземпляров функционального блока шпинделя хранящихся в памяти контроллера. Поле Tool содержит число экземпляров функционального блока магазина инструментов. Поле Coolant содержит число экземпляров функционального блока подачи СОЖ. Поле DataSize содержит размер диагностической информации хранящейся в памяти ПЛК. Схема взаимодействия объектов для создания клиент-серверного соединения Взаимодействие объектов представлено на диаграмме последовательности. После старта приложения Маster осуществляет попытку установки соединения с ПЛК и запрашивает конфигурационную информацию. В соответствии с полученными конфигурационными данными формируется отправляется запрос для получения информации о состоянии параметров выполнения технологических команд. После анализа полученных данных, в приложении выводится информации о ходе выполнения технологических операций на станке с ЧПУ. Приложение
Исходный код. Библиотека функциональных блоков: FUNCTION_BLOCK Config VAR_INPUT:POINTER TO INT;:INT;:INT;:INT;_VAR_OUTPUT: INT:=0;: INT;_VAR_VAR:=spindle*12+tool*8+coolant*6;[0]:=FbType;[1]:=spindle;[2]:=tool;[3]:=coolant;[4]:=DataSize;_BLOCK Spindle_INPUT:INT;:INT;: INT;:POINTER TO INT;: INT;_VAR_OUTPUT: INT:=1;:INT;: INT;:INT;: INT;_VAR_VAR[0]:=FbType;[1]:=id;[2]:=state;[3]:=speed;[4]:=rotation;[5]:=interpolationMode;_BLOCK Tool_INPUT:INT;:POINTER TO INT;: INT;_VAR_OUTPUT: INT:= 2;:INT;:INT; _VAR_VAR[0]:=FbType;[1]:=id;[2]:=state;[3]:=number;_BLOCK Coolant_INPUT:POINTER TO INT;: INT; _VAR_OUTPUT: INT:= 3;:INT;_VAR_VAR[0]:=FbType;[1]:=id; address[2]:=state; Функция установки соединения с ПЛК: public void connect (string ip, ushort port) { {_ip;(IPAddress. TryParse (ip, out _ip) == false) {hst = Dns. GetHostEntry(ip);= hst. AddressList[0].ToString(); } // Connect asynchronous client= new Socket (IPAddress. Parse(ip).AddressFamily, SocketType. Stream, ProtocolType. Tcp);. Connect (new IPEndPoint (IPAddress. Parse(ip), port));. SetSocketOption (SocketOptionLevel. Socket, SocketOptionName. SendTimeout, _timeout);. SetSocketOption (SocketOptionLevel. Socket, SocketOptionName. ReceiveTimeout, _timeout);. SetSocketOption (SocketOptionLevel. Socket, SocketOptionName. NoDelay, 1); // Connect synchronous client= new Socket (IPAddress. Parse(ip).AddressFamily, SocketType. Stream, ProtocolType. Tcp);. Connect (new IPEndPoint (IPAddress. Parse(ip), port));. SetSocketOption (SocketOptionLevel. Socket, SocketOptionName. SendTimeout, _timeout);. SetSocketOption (SocketOptionLevel. Socket, SocketOptionName. ReceiveTimeout, _timeout);. SetSocketOption (SocketOptionLevel. Socket, SocketOptionName. NoDelay, 1); _connected = true; }(System.IO.IOException error) { _connected = false;(error); } } Функция формирующая Modbus пакет:byte[] CreateReadHeader (ushort id, ushort startAddress, ushort length, byte function) {[] data = new byte[12];[] _id = BitConverter. GetBytes((short) id);[0] = _id[0]; // Slave id high byte[1] = _id[1]; // Slave id low byte[5] = 6; // Message size[6] = 0; // Slave address[7] = function; // Function code[] _adr = BitConverter. GetBytes((short) IPAddress. HostToNetworkOrder((short) startAddress));[8] = _adr[0]; // Start address[9] = _adr[1]; // Start address[] _length = BitConverter. GetBytes((short) IPAddress. HostToNetworkOrder((short) length));[10] = _length[0]; // Number of data to read[11] = _length[1]; // Number of data to read data; } Кроссплатфоменная библиотека на основе протокола Modbus #include <stdio.h> #include <conio.h> #include <iostream> #include <WinSock2.h> #include <WS2tcpip.h> #include «modbus.h»namespace std; #pragma comment (lib, «Ws2_32.lib») /* Пример общения с контроллером посредством протокола modbus Обмен данными идёт поверх протокола TCP на основе Windows Sockets 2 Код документирован, но для более полного понимания работы WinSock2 стоит обратиться к первоисточнику: http://msdn.microsoft.com/en-us/library/ms740673% 28VS.85% 29.aspx */ #define BUF_SIZE 256main(void) {wsaData;addrinfo * result = NULL;addrinfo * ptr = NULL;addrinfo hints;(LC_ALL, «Russian»); /* Инициализирует Windows Sockets. Такая инициализация требуется во всех windows-подобных системах, включая ReactOS. При портировании кода на UNIX-подобные системы подобная инициализация не требуется. */dResult = WSAStartup (MAKEWORD(2, 2), &wsaData); if (dResult!= 0) {<< «Не удалось инициализировать Winsock.»;1; } // Инициализируем структуру hints, предварительно обнулив её ZeroMemory (&hints, sizeof(hints));.ai_family = PF_INET;.ai_socktype = SOCK_STREAM;.ai_protocol = IPPROTO_TCP; // Записываем в hints адрес и порт контроллера в удобном для сокетов виде DWORD dwRetval = getaddrinfo («10.134.163.147», «502», &hints, &result); // 192.168.129.12(dwRetval!= 0) {(«getaddrinfo() отработала с ошибкой:%d», dwRetval);();1; }= result; // Неосредственно создаём сокет //SOCKET sSocket = INVALID_SOCKET;sSocket;= socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);(sSocket == INVALID_SOCKET) {(«Функция socket() отработала с ошибкой:%d», WSAGetLastError());(result);();1; } contin = true; // Подключаемся к контроллеру //dResult = bind (sSocket, ptr->ai_addr, (int) ptr->ai_addrlen);(sSocket, ptr->ai_addr, (int) ptr->ai_addrlen); /* dResult = connect (sSocket, ptr->ai_addr, (int) ptr->ai_addrlen);(dResult == SOCKET_ERROR) {(sSocket);(«Функция connect отработала с ошибкой:%d», WSAGetLastError());= INVALID_SOCKET; }*/ /* if (sSocket == INVALID_SOCKET) {(«Функция connect отработала с ошибкой:%d», WSAGetLastError()); WSACleanup();1; }*/len = 12; /* Составляем пакет записи данных регистров команда 0x10 */ /* len = 17; // НУ НА САМОМ ДЕЛЕ LEN БЫЛО 10 (А-0) там пишется 9 байтpacketForWriteSingleCoil[] = { /* Заголовок MDAP Это просто заголовок пакета */ // Transaction indentifier // Два байта представляют собой идентификационный номер процесса передачи пакета // 0x00, 0x00, // Protocol identifier // Описывает пакет // 0x00, 0x00, // Эти два байта должны быть равны 0. Они говорят о том, что это именно modbus-пакет // 0x00, 0x0A, // Эти два байта описывают размер передаваемого пакета // Unit identifier // Данный байт означает номер модуля, с которым идёт обмен данными // 0x01, // мб 2? /* Собственно, вот эти данные как раз таки и нужны для выполнения конкретных действий с контроллером */ // Functon code // Содержит номер функции, которую следует выполнить // 0x03, // Start address // Адрес начала, куда будем писать // 0x00, 0x6B, // адрес старшего-адресс младшего байта // Значения, которые будем писать с начала указанного адреса // 0x00, 0x03, // 0x02, // количество байт данных // 0x00, 0x0A, // данные старший байт данные младший байт // 0x01, 0x02 //CRC старший байт СRС младший байт // }; /* Составляем пакет чтение */= 12; // было 7packetForWriteSingleCoil2 [] = { /* Заголовок MDAP Это просто заголовок пакета */ // Transaction indentifier // Два байта представляют собой идентификационный номер процесса передачи пакета x00, 0x00, // Protocol identifier // Описывает пакет x00, 0x00, // Эти два байта должны быть равны 0. Они говорят о том, что это именно modbus-пакет x00, 0x05, // Эти два байта описывают размер передаваемого пакета // Unit identifier // Данный байт означает номер модуля, с которым идёт обмен данными x00, /* Собственно, вот эти данные как раз таки и нужны для выполнения конкретных действий с контроллером */ // Functon code // Содержит номер функции, которую следует выполнить x04, // Start address // Адрес начала, откуда будем читать x00, 0x02, // ЧИСЛО РЕГИСТРОВ ДЛЯ ЧТЕНИЯ x00, 0x02, }; // len надо определить т. к. эта переменная является параметром send() while(contin) { /* Обмениваемся данными */= send (sSocket, packetForWriteSingleCoil2, len, 0);(dResult == SOCKET_ERROR) {(«Ошибка передачи данных:%d», WSAGetLastError());(sSocket);();1; } /* Принимаем данные от контроллера */recvbuf [BUF_SIZE]; :ZeroMemory (recvbuf, BUF_SIZE);= recv (sSocket, recvbuf, BUF_SIZE, 0);(dResult > 0)(«\n Bytes received:%d\n», dResult);if (dResult == 0)(«Connection closed\n»);(«recv failed:%d\n», WSAGetLastError()); int i; // Выводим на экран заголовок MDAP, так как у него всегда фиксированный размер printf («MBAP: \n»);(i=0; i<11; i++) // было 7 printf («%x», recvbuf[i]); // Теперь выводим остальные данные, зная их длину по заголовку MDAP // Длина находится в двух байтах, расположенных по адресу recvbuf+4 printf («\nOur data: \n»);(; i < BUF_SIZE; i++) printf («%x», recvbuf[i]); // Ждём нажатия клавиши, чтобы успеть прочитать<< endl << «Нажмите любую клавишу для продолжения.»; char ch = _getch();(ch == (char) 32) contin = false; } // Говорим, что чтение закончено dResult = shutdown (sSocket, SD_SEND);(dResult == SOCKET_ERROR) {(«Функция shutdown() отработала с ошибкой:%d», WSAGetLastError());(sSocket);();1; } // Закрываем сокет(sSocket); // Деинициализируем WinSock();(result); return 0; } канал связь modbus коммуникационный
Популярное: Как выбрать специалиста по управлению гостиницей: Понятно, что управление гостиницей невозможно без специальных знаний. Соответственно, важна квалификация... Как построить свою речь (словесное оформление):
При подготовке публичного выступления перед оратором возникает вопрос, как лучше словесно оформить свою... Генезис конфликтологии как науки в древней Греции: Для уяснения предыстории конфликтологии существенное значение имеет обращение к античной... ©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (155)
|
Почему 1285321 студент выбрали МегаОбучалку... Система поиска информации Мобильная версия сайта Удобная навигация Нет шокирующей рекламы |