PDA

Просмотр полной версии : SysLibCom



ribamuka
11.07.2017, 01:44
Существует библиотека SysLibCom для CodeSys 3.5 ?

Если да, то где ее скачать?

Евгений Кислов
11.07.2017, 06:54
Существует библиотека SysLibCom для CodeSys 3.5 ?

Если да, то где ее скачать?

В состав CODESYS 3.5 входит несколько библиотек для работы с COM-портом - в частности, SysCom (аналог SysLibCom c приблизительно тем же набором функций/ФБ) и CAA SerialCom. Скачивать ничего не надо, просто добавьте их в Менеджере библиотек.

Пример работы с CAA SerialCom приведен в документе СПК. Реализация нестандартных протоколов:
http://ftp.owen.ru/index.html/CoDeSys3/11_Documentation/01_SPK/SPK_NonstandardProtocols_v.1.0.pdf

ribamuka
11.07.2017, 08:42
Спасибо за подсказку

ВладОвен
11.08.2022, 17:12
Здравствуйте.
А подскажите, как работать с дескриптором открываемого порта на языке ST? (библиотека CAA SerialCom).

При открытии порта мы должны получить дескриптор:
myComOpen(usiListLength := SIZEOF(arrParams)/SIZEOF(COM.PARAMETER), pParameterList := ADR(arrParams));

А при отправке в порт дескриптор использовать:
myComWrite(xExecute := TRUE, udiTimeOut := 1000, hCom := myComOpen.hCom, pBuffer := ADR(arrMassive), szSize := 5);

Правильно ли я его использую? В порт ничего не пишется.
Что я делаю не так?

UP: Почему этот hCom всегда равен 0? Пробовал разные порты.
Скрин:
62107

Евгений Кислов
11.08.2022, 17:51
Потому что вы не дожидаетесь открытия порта (myComOpen.xDone).

Изучите этот документ:
https://ftp.owen.ru/CoDeSys3/11_Documentation/03_3.5.11.5/CDSv3.5_UserProtocols_v.3.0.pdf

ВладОвен
12.08.2022, 09:35
Потому что вы не дожидаетесь открытия порта (myComOpen.xDone).

Хм... Странно.


Декларация:

PROGRAM PLC_PRG
VAR
xOpen: BOOL := FALSE;
myHandle : COM.CAA.HANDLE;
myError : ERROR;
xError: BOOL := FALSE;
xSucces: BOOL := FALSE;
myComOpen : COM.Open;
arrParams : ARRAY [1..7] OF COM.PARAMETER := [
(udiParameterId := COM.CAA_Parameter_Constants.udiPort, udiValue := 1),
(udiParameterId := COM.CAA_Parameter_Constants.udiBaudrate, udiValue := 115200),
(udiParameterId := COM.CAA_Parameter_Constants.udiParity, udiValue := 2), // no parity
(udiParameterId := COM.CAA_Parameter_Constants.udiStopBits, udiValue := 0), // 1 stop
(udiParameterId := COM.CAA_Parameter_Constants.udiTimeout, udiValue := 0),
(udiParameterId := COM.CAA_Parameter_Constants.udiByteSize, udiValue := 8),
(udiParameterId := COM.CAA_Parameter_Constants.udiBinary, udiValue := 1)
];
END_VAR

Реализация:


IF xOpen THEN
xOpen := FALSE;
myComOpen(usiListLength := SIZEOF(arrParams)/SIZEOF(COM.PARAMETER), pParameterList := ADR(arrParams));
END_IF

myHandle := myComOpen.hCom;
xError := myComOpen.xError;
myError := myComopen.eError;
xSucces := myComOpen.xDone;

Я нажимаю на клавишу на экране визуализации, которая устанавливает флаг xOpen.
А далее долго-долго наблюдаю за 4-я параметрами. И они не меняются...
Скрин:

62112

Но ничего так и не происходит...
Пробовал перебирать порты - результата нет.
Может есть проект на ST для образца?

Евгений Кислов
12.08.2022, 09:42
Может есть проект на ST для образца?

См. ссылку в моем прошлом посте.

ВладОвен
12.08.2022, 11:56
В общем тестировал библиотеку CAA SerialCom, перебирал порты, курил доки Овена.
Попытка открыть порт приводит к состоянию флагов:

62118

Что мы видим в этом окне:
xDone - никогда не устанавливается,
xError - никогда не устанавливается,
xBusy - всегда установлен.

Какой мы вывод делаем:
Открытие порта не заканчивается
Ошибок не возникает
Процесс идет бесконечно долго.

Евгений Кислов
12.08.2022, 12:01
Я могу порекомендовать только внимательнее "курить доки".



IF xOpen THEN
xOpen := FALSE;
myComOpen(usiListLength := SIZEOF(arrParams)/SIZEOF(COM.PARAMETER), pParameterList := ADR(arrParams));
END_IF


У вас xOpen взводится на один цикл и myComOpen тоже вызывается только один цикл.
За один цикл порт не успевает открыться, и блок зависает в xBusy.

Обычно делают так:



myComOpen(xExecute := xOpen, usiListLength := SIZEOF(arrParams)/SIZEOF(COM.PARAMETER), pParameterList := ADR(arrParams));

IF myComOpen.xDone THEN
myHandle := myComOpen.hCom;
END_IF


Или можно использовать USR_COM_CONTROL из документа - это обертка над COM.Open / COM.Close, которая будет существенно более проста в использовании для начинающих программистов, чем эти блоки.

ВладОвен
12.08.2022, 12:09
Спасибо за помощь.
Но:

Обычно делают так:
Это далеко не обычно!

Грёбаные циклы, которых не хватает за один проход! Кто-бы мог подумать!

Это не объясняется в документации к библиотеке.

ВладОвен
12.08.2022, 16:02
Ну да ладно. Отправка байтов налажена. Теперь есть проблемы с приемником. Пишем в программе:


myComRead(xExecute := TRUE, hCom := myComOpen.hCom, pBuffer := ADR(arrMassiveReceive), szBuffer := 10, udiTimeOut := 1000);


Сую в порт одиночные символы / не сую в порт одиночные символы.

xDone всегда отключен. xBusy всегда включен. Что можете посоветовать начинающему программисту?

Евгений Кислов
12.08.2022, 16:08
Что можете посоветовать начинающему программисту?

Как и раньше - внимательно изучить документ по ссылке из поста #5 (https://owen.ru/forum/showthread.php?t=27053&p=386678&viewfull=1#post386678).

ВладОвен
12.08.2022, 16:42
Как и раньше - внимательно изучить документ по ссылке из поста #5 (https://owen.ru/forum/showthread.php?t=27053&p=386678&viewfull=1#post386678).
Нет.

У меня вопрос!
В блоке Read есть параметр udiTimeOut. Он определяет время (толи в mS, толи в uS) через которое произойдет таймаут по приему.
Я записал туда число 10 000 000.

Что произойдет через этих 10 миллионов попугаев? Какой флаг должен установиться через это время? Что должно измениться?

Евгений Кислов
12.08.2022, 17:04
В блоке Read есть параметр udiTimeOut. Он определяет время (толи в mS, толи в uS) через которое произойдет таймаут по приему.
?

Это не так. Это таймаут доступа к буферу COM-порта.



Что произойдет через этих 10 миллионов попугаев? Какой флаг должен установиться через это время? Что должно измениться?

Если за это время не случится xDone или какая-то другая ошибка, то:

xError - TRUE
eError - COM.ERROR.TIME_OUT

ВладОвен
12.08.2022, 17:29
Правильно ли я понимаю, что функциональные блоки Write и Read реализованы по разному (что затрудняет их понимание и читаемость кода)?

1. Ф-блок Write не отдаёт xDone до тех пор, пока физически не отдаст последний байт линию COM-порта. Я пробовал на скорости 1200 отдать 255 байтов. Ф-блок Write блокирует программу более 2-х секунд. Реализовано хорошо: исключается наложение отдаваемых пакетов (потому-что блокируется программа).

2. Ф-блок Read отдаёт xDone сразу же, как только физически добрался до буфера. Придется сталкиваться с пустыми массивами, закольцованными массивами (придется проверять это). Параметр udiTimeOut выполняет непонятную своим смыслом функцию. Этот параметр должен был блокировать программу на указанное время, а после отдавать xDone, размер принятых байт (szSize) и принятый буфер (arrBuffer)! И ненужно было бы вводить свои кастомные таймера для таймаута, код был бы понятнее.

Ну а если нельзя блокировать программу, то зачем это сделано в ф-блоке Write? Он тоже мог бы тупо перекидывать в буфер и сразу же отдавать xDone? Пусть байты вылетают из порта своим ходом (хардовым способом).

В общем: Write блочит прогу, Read не блочит прогу.

PS: А еще обратите внимание, что параметр szSize отдает не количество принятых байт, а указывает на последний байт в кольцевом (!) буфере приема (arrBuffer). И если принятая посылка будет больше буфера, то вы получите недостоверное значение.

Евгений Кислов
12.08.2022, 19:42
Придется сталкиваться с пустыми массивами, закольцованными массивами (придется проверять это).

Можно, наверное, и так.
Или можно почитать документ, посмотреть пример из него - и обойтись без всех этих столкновений.
Впрочем, я понимаю, что вы не ищите легких путей.


Этот параметр должен был блокировать программу на указанное время, а после отдавать xDone, размер принятых байт (szSize) и принятый буфер (arrBuffer)!

Должен кому?
Библиотека CAA SerialCom включает в себя асинхронные ФБ, которые не блокируют задачу, в которой вызываются.
В этом их преимущество - сохранение стабильного времени цикла без лишних джиттеров.

Для любителей "блокировать программу" - есть библиотека SysCom.


Он тоже мог бы тупо перекидывать в буфер и сразу же отдавать xDone? Пусть байты вылетают из порта своим ходом (хардовым способом).

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


И если принятая посылка будет больше буфера, то вы получите недостоверное значение.

А если читать документацию и разумно подходить к написанию кода - то таких проблем не будет.

ВладОвен
12.08.2022, 20:59
Ок. Спасибо за разъяснения.
Получается, что эта библиотека асинхронная. По задумке не блокирует программу.
Но отправка пакета реализована с блокировкой из-за того, что-бы не ловить свои-же байты.

ВладОвен
17.08.2022, 13:56
Евгений, здравствуйте.
А можете объяснить почему не срабатывает такая конструкция при открытии порта?


WHILE NOT myComOpen.xDone DO
myComOpen(xExecute := TRUE, usiListLength := SIZEOF(arrParams)/SIZEOF(COM.PARAMETER), pParameterList := ADR(arrParams));
END_WHILE

Правильно ли я понимаю, что из-за того, что я блокирую программу?

capzap
17.08.2022, 13:58
Евгений, здравствуйте.
А можете объяснить почему не срабатывает такая конструкция при открытии порта?


WHILE NOT myComOpen.xDone DO
myComOpen(xExecute := TRUE, usiListLength := SIZEOF(arrParams)/SIZEOF(COM.PARAMETER), pParameterList := ADR(arrParams));
END_WHILE

Правильно ли я понимаю, что из-за того, что я блокирую программу?

потому что while выполняется в рамках одного цикла, а необходимо несколько циклов плк, чтоб получить обмен с аппаратным сом-портом

ВладОвен
26.08.2022, 18:05
Привет.
Помогите решить такую проблему:
Мне нужно получить посылку длинной 39 байт. Посылка должная прийти асинхронно. Т.е. чёрт знает когда.
Мне приходится постоянно циклически слушать порт:


CASE bStep OF
00: ...
01: // Принимаем пакет
myComRead(xExecute := TRUE, hcom := hCom, pBuffer := ADR(arrReceive), szBuffer := 255, udiTimeOut := 0);
IF myComRead.xDone THEN
bStep : = 2;
END_IF
02: // Проверяем длину принятого пакета
IF myComRead.szSize = 0 THEN // Нулевая длина: уходим в начало
myComRead(xExecute := FALSE);
bStep := 1;
ELSE
bStep := 4;
END_IF
04: ...
END_CASE

Пакет принимается, но иногда поломанный. Я записывал длину каждого принятого пакета в массив и увидел вот что:
arrBufferLen[] = 0, 0, 29, 10, 0, 0, 0, 0, 0, 0, 0
Т.е. принимаемые 39 байт разбились на отдельные пакеты длиной 29 и 10 байт.
Очевидно, что это происходит из-за рассинхронизации процессов.

Как этого избежать? При этом длина входного пакета всегда разная.

Cs-Cs
26.08.2022, 18:59
ВладОвен Мне Евгений Кислов помогал с подобным примером.
Судя по этому примеру (и реальной жизни) такой принцип работы - норма (а я тогда как глупый как раз и думал, что все мои байты придут за один раз, и из-за мой код не хотел работать).
В примере Евгения Кислова был такой алгоритм-принцип: сколько байт получили - столько и склеиваем в один общий массив байт, пока не наберём нужную длину посылки.
После этого посылка идёт на обработку (проверка корректности и прочего).
Если посылка верная - то что-то с ней делаем.
Если ошибочная (или в течение таймаута не пришло заданное число байт) - обнуляем буфер, счётчик принятых байт, и начинаем всё сначала.

Добавил: если там длина неизвестна - то так по байтам и клеить и парсить на лету (искать заголовок или какую-то инфу, которая покажет о том, что началась новая посылка данных). Скажем, так: приняли байт - запустили таймер TOF. Если были байты, пока он ещё считает - то значит это наша посылка. А если байтов не было - то посылка кончилась.

ВладОвен
29.08.2022, 11:21
Привет.
Решил эту задачу. Пока работает нормально.
Я просто каждый раз после полученного пакета N1 (длинна не равна 0) сразу же принимаю второй пакет и если его длинна N2 не равна 0 , то я их склеиваю:



CASE bStep OF
01: ...
02: // Ожидаем пакет (N1)
myComRead(xExecute := TRUE, hcom := hCom, pBuffer := ADR(arrBufferN1), szBuffer := 255, udiTimeOut := 0);
IF myComRead.xDone THEN
bStep := 3;
END_IF
03: // Проверяем длину принятого пакета (N1)
IF myComRead.szSize = 0 THEN // Нулевая длина
myComRead(xExecute := FALSE);
bStep := 2; // Повторно ожидаем пакет (N1)
END_IF
ELSE
udiSizeN1 := myComRead.szSize; // Длинна пакета (N1) была не нулевой
myComRead(xExecute := FALSE);
bStep := 04;
END_IF
04: // Принимаем пакет (N2)
myComRead(xExecute := TRUE, hcom := hCom, pBuffer := ADR(arrBufferN2), szBuffer := 255, udiTimeOut := 0);
IF myComRead.xDone THEN
bStep := 5;
END_IF
06: // Проверяем длину принятого пакета (N2)
IF myComRead.szSize <> 0 THEN // Длина не нулевая. Значит пакет был разбил на два отдельных. Склеиваем их.
udiSizeN2 := myComRead.szSize;
MEM.MemMove(ADR(arrBufferN2), ADR(arrBufferN1) + udiSizeN1, UDINT_TO_UINT(udiSizeN2));
END_IF
myComRead(xExecute := FALSE);
bStep := 5;
05: ...
END_CASE

Cs-Cs
29.08.2022, 18:11
ВладОвен Приятно посмотреть на код: везде комментарии и, если со стороны читать, то всё понятно. Я такое люблю.
Ты не занимаешься уходом от магических чисел (это программистский термин (https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D 0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_(%D0%BF% D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1 %80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)))? Не хочу навязывать, но я все шаги именую через константы, то есть:

VAR_CONSTANT
wStep_Wait : WORD := 0;
wStep_Recieve : WORD := 1;
wStep_Process : WORD := 2;
...
END_VAR
Так код и Case выглядят лучше, чем цифирки: с цифирками легко запутаться, когда добавляешь или удаляешь шаги.

А ещё хотел спросить: у тебя в коде есть защита от ухода за границы буфера?
Вот в этом месте

ADR(arrBufferN1) + udiSizeN1
у тебя есть защита от того, чтобы этот адрес не ушёл за границы длины arrBufferN1?
Про такие вещи надо думать, иначе потом они могут вызывать сбой программы.

1exan
30.08.2022, 07:42
ВладОвен Приятно посмотреть на код: везде комментарии и, если со стороны читать, то всё понятно. Я такое люблю.
Ты не занимаешься уходом от магических чисел (это программистский термин (https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D 0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_(%D0%BF% D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1 %80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)))? Не хочу навязывать, но я все шаги именую через константы, то есть:

VAR_CONSTANT
wStep_Wait : WORD := 0;
wStep_Recieve : WORD := 1;
wStep_Process : WORD := 2;
...
END_VAR
Так код и Case выглядят лучше, чем цифирки: с цифирками легко запутаться, когда добавляешь или удаляешь шаги.



Ещё удобно использовать перечисления (создать пользовательский тип данных) например:


TYPE enStateMotor : (
gc_iMotorStopped := 0 ,
gc_iMotorStopping := 1 ,
gc_iMotorBlocked := 2 ,
gc_iMotorErrStart := 3 ,
gc_iMotorWork := 4 ,
gc_iMotorStarting := 5 ,
gc_iMotorNoFeedback := 6
);
END_TYPE


При этом с типом enStateMotor можно работать как с INT

Cs-Cs
30.08.2022, 08:10
1exan Ага, я про перечисления знаю, но не хочу их использовать, так как перечисления внутри FB не объявишь, а у меня чаще всего автоматы состояний находятся и работают в FB. Мне хочется, чтобы FB был максимально самодостаточен и при копировании его по другим проектам не надо было ещё и DUT тащить.
Поэтому внутри FB мне удобнее константы сделать.
Если я не прав и внутри FB можно перечисление объявить - прошу меня поправить.

Евгений Кислов
30.08.2022, 08:14
Если я не прав и внутри FB можно перечисление объявить - прошу меня поправить.

Есть такая недокументированная (на данный момент) фича:
https://owen.ru/forum/showthread.php?t=28167&p=369251&viewfull=1#post369251

1exan
30.08.2022, 08:18
1exan Ага, я про перечисления знаю, но не хочу их использовать, так как перечисления внутри FB не объявишь, а у меня чаще всего автоматы состояний находятся и работают в FB. Мне хочется, чтобы FB был максимально самодостаточен и при копировании его по другим проектам не надо было ещё и DUT тащить.
Поэтому внутри FB мне удобнее константы сделать.
Если я не прав и внутри FB можно перечисление объявить - прошу меня поправить.

Можно, это же получается такой-же тип данных как BOOL, WORD - можно использовать и внутри блоков.
Но тут надо не забывать если переносишь блок в другую программу, то и перечисление, используемое внутри тоже надо переносить. (если через импорт-экспорт надо выделить и блок и свой тип данных при экспорте).

UPD:
Можно - это я конечно имел в виду использование, а не объявление перечисления. Про фичу не знал.

Перечисления удобны, если переменная состояния FB используется и снаружи FB.

Cs-Cs
30.08.2022, 08:28
1exan Вот, сначала пишем, потом читаем =) Я говорил о FB, так как снаружи это наоборот - не должно быть доступно.

Евгений Кислов О! СПАСИБО!
Хм... как бы уже придумать то, как этот FAQ распечатать со всех страниц сразу в PDF. Там сведений куча, а не все упомнишь!
Сделал пока себе скриншот ответа!

ВладОвен
30.08.2022, 10:30
ВладОвен, ... Ты не занимаешься уходом от магических чисел (это программистский термин (https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D 0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_(%D0%BF% D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1 %80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)))? Не хочу навязывать, но я все шаги именую через константы ...

Да. Этот способ тоже хорош. Но в этом проекте я решил пока от этого отказаться.
Потому что последовательность очень длинная - на 100 шагов. Я просто боюсь, что потом запутаюсь в последовательности действий.
Всё таки: числа дают последовательность перечисления, а слова - нет.

Т.е. мы всегда знаем, что после шага 56 идет шаг 57, а потом и шаг 58.
И наоборот, если со словами: после startZeroOperation идет waitCountOffset? Или waitCoeffView? Или, может быть, waitJeater? А, вспомнил! Потом идет goStableFlow! (но это не точно...).
Но с числами есть недостаток: если понадобится вставить доп.промежуточный шаг в будущем, то придется сдвигать все числа вручную. И это неудобно.

Наверное, оптимально делать всё же перечисление, но такого формата:
10_startZeroOperation,
20_waitCountOffset,
30_waitCoeffView,
40_waitJeater,
50_goStableFlow.
В этом случае и понятна последовательность шагов (за счет чисел), и смысл шага (за счет слов), и вставить доп.промежуточный шаг можно за счет предварительного пропуска чисел (например, 35_smokeDocsOwen).

1exan
30.08.2022, 11:03
Да. Этот способ тоже хорош. Но в этом проекте я решил пока от этого отказаться.
Потому, что последовательность очень длинная - на 100 шагов. Я просто боюсь, что потом запутаюсь в последовательности действий.
Всё таки: числа дают последовательность перечисления, а слова - нет.

Т.е. мы всегда знаем, что после шага 56 идет шаг 57, а потом и шаг 58.
И наоборот, если со словами: после startZeroOperation идет waitCountOffset? Или waitCoeffView? Или, может быть, waitJeater? А, вспомнил! Потом идет goStableFlow! (но это не точно...).
Но с числами есть недостаток: если понадобится вставить доп.промежуточный шаг в будущем, то придется сдвигать все числа вручную. И это неудобно.

Наверное, оптимально делать всё же перечисление, но такого формата:
10_startZeroOperation,
20_waitCountOffset,
30_waitCoeffView,
40_waitJeater,
50_goStableFlow.
В этом случае и понятна последовательность шагов (за счет чисел), и смысл шага (за счет слов), и вставить доп.промежуточный шаг можно за счет предварительного пропуска чисел (например, 35_waitSmokeDocsOwen).

Я конечно не знаю как у вас организована программа, но я в таких случаях делаю так:
Если мне надо добавить шаг, я просто вставляю его в нужное место перечисления и перенумеровываю значения заново (в екселе - делается за 1 сек если разделители - табуляция):
Например:


Было

TYPE enStateMotor : (
gc_iMotorStopped := 0 ,
gc_iMotorStopping := 1 ,
gc_iMotorBlocked := 2 ,
gc_iMotorErrStart := 3 ,
gc_iMotorWork := 4 ,
gc_iMotorStarting := 5 ,
gc_iMotorNoFeedback := 6
);
END_TYPE

Стало:

TYPE enStateMotor : (
gc_iMotorStopped := 0 ,
gc_iMotorStopping := 1 ,
gc_iMotorBlocked := 2 ,

gc_iMotor_NEW_STATE := 3 ,

gc_iMotorErrStart := 4 ,
gc_iMotorWork := 5 ,
gc_iMotorStarting := 6 ,
gc_iMotorNoFeedback := 7

);
END_TYPE

При этом оператор

CASE State OF
gc_iMotorStopped..gc_iMotorWork, gc_iMotorNoFeedback:
...

и конструкции типа

State > gc_iMotorStopped AND State < gc_iMotorNoFeedback

ну и т.д. не перестают работать

Cs-Cs
30.08.2022, 11:25
ВладОвен, я имел ввиду что и в CASE шаги тоже называются по имени. Ща, сделаю скриншот, покажу как у меня в FB окучено.

62361 62362

А если ты хочешь прикалываться, то так тебе надо не под каждый пакет свой шаг мутить, а, ИМХО, в этом конечном автомате ловить сам пакет, а потом отсылать его на какую-нить функцию типа "ProcessData()", которая и будет соображать, что там за данные пришли и что с ними сделать.
В случае чего можно даже очередь пакетов сделать =)

ВладОвен
03.10.2022, 09:52
Привет.
Скажите, а как будут работать два устройства, которые висят на одном порту, но одно из них работает на ModBus-Slave, а другое - по нестандартному протоколу (библиотека SysLibCom)?
Будут ли конфликты?

Евгений Кислов
03.10.2022, 09:56
Привет.
Скажите, а как будут работать два устройства, которые висят на одном порту, но одно из них работает на ModBus-Slave, а другое - по нестандартному протоколу (библиотека SysLibCom)?
Будут ли конфликты?

Добрый день.
Если опрос полностью реализован в вашем коде - то конфликтов не будет (если, конечно, вы сами их не создадите).

ВладОвен
03.10.2022, 16:16
Если опрос полностью реализован в вашем коде - то конфликтов не будет.


Вы имеете ввиду, что и ModBus и SysLibCom я реализую программно в коде?

Обмен через SysLibCom я реализовал в программе, а ModBus реализуется внутренним автоматом CodeSys.

Евгений Кислов
03.10.2022, 16:21
Вы имеете ввиду, что и ModBus и SysLibCom я реализую программно в коде?

Обмен через SysLibCom я реализовал в программе, а ModBus реализуется внутренним автоматом CodeSys.

Не думаю, что это получится - стандартный компонент Modbus (который вы называете "внутренним автоматом") займет COM-порт, и вы уже не сможете открыть его с помощью SysComOpen.

ВладОвен
03.10.2022, 16:38
Так и есть: порт не может быть открыт.

ВладОвен
05.10.2022, 11:48
Привет.
Можно ли организовать обмен информацией с двумя устройствами на одной шине RS485, НО меняя частоту обмена на лету: 115200 и 9600 ?
Так получается, потому что у меня есть один датчик, и у него частота только 9600, а все другие устройства работают на максимальной - 115200.

а) Для стандартного компонента ModBus.
б) Для нестандартного протокола.

Евгений Кислов
05.10.2022, 11:52
Привет.
Можно ли организовать обмен информацией с двумя устройствами на одной шине RS485, НО меняя частоту обмена на лету: 115200 и 9600 ?
Так получается, потому что у меня есть один датчик, и у него частота только 9600, а все другие устройства работают на максимальной - 115200.

а) Для стандартного компонента ModBus.
б) Для нестандартного протокола.



Добрый день.
Уточните - у вас на одной шине устройство с Modbus и устройство с нестандартным протоколом?

ВладОвен
05.10.2022, 12:36
Добрый день.
Уточните - у вас на одной шине устройство с Modbus и устройство с нестандартным протоколом?

Нет.
Имеется ввиду: устройства с протоколом ModBus на одной шине, но один тип устройств (8шт.) работает только на скорости 9600, а другой тип устройств (16шт.) - на скорости 115200.

Но, давайте еще рассмотрим аналогичный вопрос: устройства с нестандартным протоколом на одной шине, но один тип устройств (8шт.) работает только на скорости 9600, а другой тип устройств (16шт.) - на скорости 115200.

Евгений Кислов
05.10.2022, 12:39
Нет.
Имеется ввиду: устройства с протоколом ModBus на одной шине, но один тип устройств (8шт.) работает только на скорости 9600, а другой тип устройств (16шт.) - на скорости 115200.

Но, давайте еще рассмотрим аналогичный вопрос: устройства с нестандартным протоколом на одной шине, но один тип устройств (8шт.) работает только на скорости 9600, а другой тип устройств (16шт.) - на скорости 115200.

a) Можно
б) Можно

ВладОвен
05.10.2022, 14:14
a) Можно
б) Можно

Супер!
Так а как скорости-то переключать на ходу?

Евгений Кислов
05.10.2022, 14:18
Супер!
Так а как скорости-то переключать на ходу?

a) Переводите все каналы опроса в режим Передний фронт или Приложение.
Когда нужно переключить скорости - останавливаете опрос каналов.
Изменяете настройки COM-порта согласно рисунку 4.6.6 и информации рядом с ним: https://ftp.owen.ru/CoDeSys3/11_Documentation/03_3.5.11.5/CDSv3.5_Modbus_v3.0.pdf

б) В этом случае обмен настраивается через библиотечные ФБ. Соответственно, в нужный момент времени останавливаете опрос, закрываете COM-порт, открываете его с новыми настройками и продолжаете опрос.

ВладОвен
05.10.2022, 16:22
Спасибо. За разъяснения.

ВладОвен
23.12.2022, 17:51
Привет. Попробовал построить обмен через Com-порт но на языке CFC.
1. Как вам идея реализации на этом языке?
2. Правильно ли использовал элемент move для перехода на второй шаг автомата и для копирования указателя hCom?
См. рисунок:
64783

Почему я об этом спросил? Просто я заметил, что элемент с EN-ENO имеет определенное "западло". Оказывается, что при отсутствующем сигнале EN элемент не обнуляется, а тупо фиксирует свои выходы в последнем состоянии (т.е. работает по спаду на входе EN).

Валенок
23.12.2022, 17:54
Вилка для супа

Cs-Cs
23.12.2022, 18:01
А зачем так делать? Чем ST не подходит?

ВладОвен
23.12.2022, 18:08
Ну для понимания возможностей этого языка. Надо же попробовать.
В конце концов в обучающих видео от Овена часто используют этот язык. (Видели? Там блондинка сидит и пикает сканером штрих-кода :))

Cs-Cs
24.12.2022, 11:25
Ну для понимания возможностей этого языка. Надо же попробовать.
В конце концов в обучающих видео от Овена часто используют этот язык. (Видели? Там блондинка сидит и пикает сканером штрих-кода :))
Да ну... на ST удобнее. Мне Евгений Кислов помогал с примером, а я сам - бывший СИшный программист. Вот на ST втянулся.
Блондинка? Неа... Мне всегда нравился фетиш- и готик стайл и брюнетки =)

ВладОвен
02.03.2023, 15:53
Привет.
Подскажите, а можно ли принять пакет из порта не в массив, а в строку?
Т.е.
Не так:

myComRead(xExecute:=TRUE, hcom:=myhCom, pBuffer:=ADR(arrReceive1), szBuffer:=255, udiTimeOut:=0);
А так:

myComRead(xExecute:=TRUE, hcom:=myhCom, pBuffer:=ADR(sReceive1), szBuffer:=SIZEOF(81), udiTimeOut:=0);
У меня так не получается.
В массив принимает данные, а в строку - не принимает.
Спасибо.

Евгений Кислов
02.03.2023, 15:55
Добрый день.

Да, можно.


szBuffer:=SIZEOF(81)

^Здесь, очевидно, ошибка.

Нужно так:


szBuffer:=SIZEOF(sReceive1)

ВладОвен
02.03.2023, 16:26
Хм. Исправил, но приема нет.
Если принимать в буфер, то принимает норм.
См.рисунок.
66266

ВладОвен
02.03.2023, 16:33
Походу разобрался.
Нужно делать так:


sReceive2 := sReceive1;
myComRead(xExecute := FALSE);

Потому как при eXecute:=FALSE эта строка обнуляется и мы ее не видим.

ВладОвен
02.03.2023, 21:04
А подскажите, как добавить в конец строки спец.символ?
Пробую так:

sSend := concat(sSend, CHR_TO_STRING(16#0D))

При этом нужно подключить библиотеку BASIC(OSCAT)
А потом возникает ошибка 'Неоднозначное пространство имен 'STANDARD' задано библиотекой 'Standard, 3.5.17.0 (System)'
Как это побороть?

Евгений Кислов
02.03.2023, 21:26
sSend := CONCAT(sSend, '$0D');