Форум программистов
 
Регистрация на форуме тут, о проблемах пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail, а тут можно восстановить пароль

Купить рекламу на форуме 15-35 тыс рублей в месяц

Вернуться   Форум программистов > Delphi программирование > Работа с сетью в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail


Оплата за обучение в Kata Academy только после твоего трудоустройства в IT, начни карьеру Middle Java-разработчика


Ответ
 
Опции темы Поиск в этой теме
Старый 29.12.2021, 13:47   #1
Serje88
Новичок
Джуниор
 
Регистрация: 29.12.2021
Сообщений: 2
По умолчанию Работа с COM портом

Добрый день, прошу помочь людей с опытом работы с 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.WriteTotalTimeoutMultiplie r:=100;

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

Timeouts.ReadIntervalTimeout:=50;
Timeouts.ReadTotalTimeoutConstant:= 100;
Timeouts.ReadTotalTimeoutMultiplier :=70;
Timeouts.WriteTotalTimeoutConstant: =100;
Timeouts.WriteTotalTimeoutMultiplie r:=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.jpg (99.7 Кб, 21 просмотров)
Тип файла: jpg 2.jpg (103.1 Кб, 0 просмотров)

Последний раз редактировалось Serje88; 29.12.2021 в 13:59.
Serje88 вне форума Ответить с цитированием
Старый 30.12.2021, 06:58   #2
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 636
По умолчанию

Serje88, для начала выведи в лог всё, что прочиталось из порта, и всё, что записалось в порт (с точностью до мс.)
(запись для лога необходимо формировать непосредственно сразу после функции записи/чтения, чтобы время в логе можно более точнее соответствовало реальности)
Алексей1153 вне форума Ответить с цитированием
Старый 08.01.2022, 11:23   #3
Serje88
Новичок
Джуниор
 
Регистрация: 29.12.2021
Сообщений: 2
По умолчанию

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

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Работа с com портом Shadowfirst Общие вопросы C/C++ 0 01.07.2016 15:51
Работа с COM портом SDevel C# (си шарп) 6 05.01.2013 11:16
Работа с com портом Валера777 Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 4 05.12.2009 00:06
Работа с COM портом hoba Общие вопросы Delphi 3 20.11.2008 03:39

Реклама для незарегистрированных, регистрация на форуме