Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 21.11.2014, 12:05
Jury_yamal Jury_yamal вне форума
Прохожий
 
Регистрация: 04.11.2014
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию описать класс ModbusRTU без реализации

Здравствуйте.
Подтолкните в правильном направлении для решения следующей задачи:
Есть некоторое устройство общающееся с PC посредством com-порта. Протокол у этого устройства ModbusRTU.
Написал тестовую программу обмена с этим устройством без использования классов. Данные принимаю и отправляю в виде массива Byte. Все работает (т.е. значения из регистров я получаю и вывожу на форму).
Теперь встала задача оформить это все в виде класса. Почитал книги по ООП , но до конца так и не понял как это реализовать. Из всего протокола Modbus RTU меня интересует пока только 2 функции это- 3 ( Read holding registers) и 6 (Preset Holding registers). Вот начало как я это вижу.
Родитель
Код:
TModbus =class (TObject)
 private
 FID:Byte;             // адрес устройства   используется при запросе и ответе
 FCodeFunction:Byte;   // номер функции используется при запросе и ответе
 FRegistr: Byte;       // адрес регистра используется при запросе
 FSizeDataField:Byte   // Размер поля данных используется при запросе и ответе
 FCRC: Word;           // Контрольная сумма используется при запросе и ответе
Дальше определить 2 наследника это класса TWriteModbusRTU и TReadModbusRTU и уже в них производить необходимые действия по заполнению массива байтов для чтения и запроса из, в ком порт. Что еще нужно учесть в базовом классе что будет общим для всех классов наследников? Может кто-то помочь кусочком кода без реализации класса TWriteModbusRTU?
Сейчас без класса обмен происходит так: для записи из edit_ов берется значение ID,функции (3 или 6), адрес регистра, размер поля и загоняется в глобальные переменные, а потом в процедуре собирается в массив array of byte к которому прикручиваются 2 байта CRC и отправляется в порт. Далее в отдельном потоке при приходе данных в буфер проверяется CRC пакета если рассчитанное значение совпадает с значением в пакете то передается в главный модуль. Далее они анализируется на ошибку следующим образом: проверяется адрес устройства, проверяется код функции в ответе если они совпадают с отправленными то пакет передается по ссылке в процедуру определения из какого регистра были получены данные ( сравнение по номеру запроса) эта процедура отправляет пакет еще в одну процедуру где происходит извлечения из пакета значения регистра, его расшифровка и выводится на форму в edit. Собственно почему и хочу переделать под класс из за наличия кучи глобальных переменных .
Заранее благодарен всем кто откликнется. С уважением Юрий.

Последний раз редактировалось Jury_yamal, 21.11.2014 в 14:00.
Ответить с цитированием
  #2  
Старый 21.11.2014, 16:13
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Этот набор бутово-вордных переменных больше похож на запись (TModbus = record)
Ответить с цитированием
  #3  
Старый 21.11.2014, 18:15
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Jury_yamal
берется значение ID,функции (3 или 6), адрес регистра, размер поля и загоняется в глобальные переменные, а потом в процедуре собирается в массив array of byte к которому прикручиваются 2 байта CRC и отправляется в порт.
Тут всё зависит от того, меняются ли команды, могут ли они задаваться пользователем? На каком уровне вы их хотите абстрагировать? Если разные команды требуют разных входных данных (или по-разному формируемых), их можно сделать отдельными классами, реализовав всю обвязку методами и свойствами.

Из текущего же описания я пока увидел лишь общую функцию отправки данных с несколькими параметрами. То есть, можно обойтись и без класса, но только если тело функции не представляет один большой case или набор if-ов, под каждую команду делающих свою обработку.
__________________
Не стоит путать форумы с богадельнями. © Bargest
Ответить с цитированием
  #4  
Старый 24.11.2014, 10:17
Jury_yamal Jury_yamal вне форума
Прохожий
 
Регистрация: 04.11.2014
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Вот пример того что я пытаюсь сделать.
И да тело функций приема и отправки выглядят как большой case.Если не считать запись в регистры (что в основ используется только в начале), то циклы запроса и ответа выглядят так:
1. Послать запрос на чтение из регистра текущего напряжения на канале 1 (значение Float32). запрос выглядит как (const Channel: array of byte, ReguestN:byte) где Reguest - номер запроса (используется в case для определения номера запроса), увеличивается на 1 при отправке.
2. Запустить таймер (если за отведеное время нет ответа от ком порта повторить 10 раз эту же команду после чего отключить ком порт и выдать ошибку в окно ).
3 При приеме проверяется СRC в принятом пакете и код функции если рассчитанное СRC не совпадает с значение в пакете или код функции =80 (последняя цифра это сообщение какая именно ошибка) то повторяется пункт 2.
4. Если принятый пакет (read: array of byte, ReguestN:byte) проходит соответствующую проверку то он отправляется в процедуру получения значения в (по номеру Reguest в case) свою переменную Single и вывода на форму.
5. То же самое проходит для 3 других каналов и цикл повторяется.
Дело в том что в протоколе Modbus не передается значение из какого регистра были получены данные поэтому использую Reguest (номер запроса ни как не меняется в потоке опроса порта). Т.е. например если Reguest=1 в принятом пакете то это значение 1 канала в Flaot32, если 2 то соответственно 2 и т.д.
Вложения
Тип файла: rar MB110TD_Cfg.rar (213.4 Кбайт, 11 просмотров)

Последний раз редактировалось Jury_yamal, 24.11.2014 в 10:57.
Ответить с цитированием
  #5  
Старый 24.11.2014, 15:13
AlexSku AlexSku вне форума
Специалист
 
Регистрация: 07.05.2007
Адрес: Москва
Сообщения: 884
Репутация: 21699
По умолчанию

Если по простому, то приведу пример, как мы работали с сетью CAN. У библиотеки dll были функции. Для отправки сообщения создайте функцию Write (или SendMessage). Если приходит сообщение к вам, то вызывается ваш обработчик. Предварительно вы указываете эту функцию, а она вызывается асинхронно. Как только она вызовется, внутри надо прочитать сообщение какой-нибудь функцией Read (а может, уже в обработчик будет доставлены байты сообщения). Если нужно данные от прочтения визуализировать, то нужна будет синхронизация с главным процессом.
Ответить с цитированием
  #6  
Старый 24.11.2014, 17:17
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Jury_yamal
И да тело функций приема и отправки выглядят как большой case.
Ну вот, ОО-абстракция над case -- набор наследников с виртуальными методами, и тогда case выполняется на этапе компиляции при формировании VMT.

А в архиве оказались не исходники.
__________________
Не стоит путать форумы с богадельнями. © Bargest
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 00:47.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025