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

Delphi Sources



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

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 29.12.2021, 13:37
Serje88 Serje88 вне форума
Прохожий
 
Регистрация: 29.12.2021
Сообщения: 2
Версия Delphi: Delphi 10.4
Репутация: 10
По умолчанию Работа с COM портом на Delphi

Добрый день, прошу помочь людей с опытом работы с COM портом на Delphi.

Разрабатываю программу на Delphi 10.4 для связи с цифровым манометром через протокол RS-232.
Физически связь осуществляется ПК - USB преобразователь RS-232 - витая пара UTP 4P - цифровой манометр.
скорость обмена данными 9600 б/с
количество бит данных 8
без проверки на четность
количество стоп-бит – 1
Программа через таймер каждую секунду шлёт запрос, на что цифровой манометр отвечает, отправляя значение одного параметра (давления) формируя ответ согласно своего протокола, пример байт в HEX формате:

FF 00 FF FF 86 FF FF FF FF 04 01 05 00 00 01 3D 6E 7F 28 83

из них самый последний байт является контрольной суммой сообщения, а перед ним 4 байта - значение в формате IEEE754(Float)

Для работы с COM портом использую библиотеку ComPort Library v4.11, сообщение через COM порт приходит не сразу, а частями (причём длина частей не постоянна), поэтому перед запросом я очищаю буфер, а по мере прихода частей собираю пакет (буфер) через глобальную переменную

проблема заключается в следующем, в результате получения ответов и сборки их в пакет (буфер) я получаю неправильный результат (неправильное значение параметра (давления) и неверную контрольную сумму), но только стоит мне добавить лишнее ненужное действие (например вывод промежуточных результатов в Memo1) происходит следующее, при добавлении строк в Memo1 происходить прокручивание Memo1 вниз (через ScrollBars) и обратное поднятие вверх, программа как бы замедляется и в результате я получаю правильный пакет (буфер), у которого верное значение и контрольная сумма.

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

у меня есть несколько вариантов (возможно вы предложите свой, более правильный):

0) другой алгоритм сборки пакета (может быть ошибка в нём)
1) специальное замедление программы (выполнение каких-то лишних действий)
2) замедление программы через функции Sleep, Delay (подскажите как правильно сделать? какое значение задержки? или пример кода)
3) формирование пакета (буфера) не в ручную, а через TComDataPacket, как только его правильно настроить?
есть параметр StartString, но мне нужно начало пакета определять не по стартовой строке, а по 4-ом стартовым байтам (пакет начинается с FF 00 FF FF, просто FF может повторяться в сообщении)
4) выставление временных задержек COM-port'а, сейчас значения стоят по умолчанию

Timeouts.ReadIntervalTimeout:=-1;
Timeouts.ReadTotalTimeoutConstant:=0;
Timeouts.ReadTotalTimeoutMultiplier:=0;
Timeouts.WriteTotalTimeoutConstant:=1000;
Timeouts.WriteTotalTimeoutMultiplier:=100;

пробовал выставить следующие значения:

Timeouts.ReadIntervalTimeout:=50;
Timeouts.ReadTotalTimeoutConstant:=100;
Timeouts.ReadTotalTimeoutMultiplier:=70;
Timeouts.WriteTotalTimeoutConstant:=100;
Timeouts.WriteTotalTimeoutMultiplier:=60;

результат тот же, приходит не верный ответ

так же есть родная программа от манометра, в которой заданы временные интервалы (смотреть прилагаемые картинки), но какие задать мне значения Timeouts исходя из параметров родной программы (может кто-то подскажет верные)?

так же в целом прошу проверить код, может опытные люди найдут ошибки или предложат оптимизировать процедуру?

код получения и сборки пакета:
Код:
var
  CPdata:array[0..25] of byte; //переменная для сборки пакета из ком порта
  CPcount:integer=0; //количество собранных бит

procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer);
var
data:array[0..18] of Byte; //полученная информация с COM порта
src:array[0..3] of Byte;  //переменная для вытаскивания значения давления
vali:integer; //значение давления в integer
i:integer;    //i - счётчик
str:string; //str - для консоли
vals:single absolute src;  //конвертирование из IEEE754 в single
begin
ComPort.Read(data,Count); //читаем данные из COM порта
for i := 0 to Count do CPdata[CPcount+i]:=data[i]; //добавляем инф-ию к пакету
for i := 0 to Count do Memo1.Lines.Add('i: '+IntToStr(i)+' CPdata['+IntToStr(CPcount+i)+']:='+IntToHex(data[i])+' CPcount:'+IntToStr(CPcount)); //эта строчка не нужна, но даёт правильный результат
CPcount:=CPcount+count+1; //количество собранных бит
if CPcount<20 then exit; //если не набрали 20 байт в пакете - выходим из процедуры
//
src[0]:=CPdata[18]; //value 4
src[1]:=CPdata[17]; //value 3
src[2]:=CPdata[16]; //value 2
src[3]:=CPdata[15]; //value 1
//
vali:=Round(vals); //округляем из single в integer
Memo1.Lines.Add('Значение: '+IntToStr(vali)+' ('+format('%10.5F',[vals])+') ['+IntToHex(src[0])+' '+IntToHex(src[1])+' '+IntToHex(src[2])+' '+IntToHex(src[3])+']'); //выводим в консоль значение
end;
Изображения
Тип файла: jpg 1 — small.jpg (72.1 Кбайт, 6 просмотров)
Тип файла: jpg 2 — small.jpg (76.7 Кбайт, 6 просмотров)

Последний раз редактировалось Serje88, 29.12.2021 в 13:59.
Ответить с цитированием
  #2  
Старый 30.12.2021, 00:41
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,056
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну, без железок отладить трудно, но пару идей подкину.
Похоже, затык происходит либо в компоненте (COMPort), либо где-то в самой VCL. Т.е. если происходят доп. действия (которые, как мне кажется, обрабатывают очередь сообщений) и все работает, то тут скорее дело в том, что работа основной программы (твоего кода) просто блокирует получение данных.
Что можно попробовать.
1. Вставить Aplication.ProcessMessages (кажется так) в цикл работы твоей программы, что принудительно вызовет обработку сообщений в очереди.
2. Вынести работу с железкой в отдельный поток. Там посылать запросы, вычитывать ответ и по получению полного пакеты передавать результат в основной поток программы для отображения.
Ответить с цитированием
  #3  
Старый 08.01.2022, 11:24
Serje88 Serje88 вне форума
Прохожий
 
Регистрация: 29.12.2021
Сообщения: 2
Версия Delphi: Delphi 10.4
Репутация: 10
По умолчанию

спасибо за помощь, ошибка была элементарная, вместо "for i:=0 to Count" должно быть "for i:=0 to Count-1", всё работает отлично с таймаутами по умолчанию
Ответить с цитированием
Ответ


Delphi Sources

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

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

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

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


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


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

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

ВКонтакте   Facebook   Twitter