В стандартной поставке: PRU_DIV_DW_DW
Вид для печати
А оператор CASE в Hardella есть ?
Ну, да.
Например, PRU_STEPPER на CASE построен:
Вложение 30045
А почему нельзя вставить комментарий напротив строки текста программы ?
При объявлении переменных комментарий на против строки ставится, а в тексте программы нет.
Добрый день!
Столкнулся с проблемой. Проект, созданный в Харделла 1.6.1 работал нормально. После обновления до 1.6.2, т.е. после разделения процедур чтения и записи из\в PRU проект перестал работать.
При онлайне с ПЛК переменная lastWriteOk в состоянии FALSE, постоянно растет счетчик writeFails, хотя переменная running в TRUE. Естественно, никакие данные не пишутся и не поступают с\в PRU-блоки.
Непонятно назначение POU Hardella_SimulationDetector.
Созданный в 1.6.1 проект без изменений перекомпилирован в 1.6.2, и все нужные файлы перенесены в КДС как положено.
Что я не так делаю?
---------------
Обратил внимание, что в коде *.exp компиляции 1.6.1 присутствует вызов FB_GetParametr, а в компиляции 1.6.2 такого вызова нет.
А на каком софте основана сама Hardella IDE? Есть возможность компилировать ST в код IL (все описание самого кода есть). Интересна возможность запилить поддержку Delta PLc. На которых нет ST.
Hardella IDE написана на JetBrains MPS.
Да, сделать компиляцию ST -> IL можно.
Delta на может IL в текстовом виде обрабатывать?
На DELTA PLC (для ПЛК DVP серии) в среде ISPSoft IL можно только копи пастом, есть импорт и экспорт (но формат там не текстовый)
Да, в 1.6.2 не работает обмен.
Если других дополнений нет, то выложу обновление с таким составом:
Статистика времени выполнения выводится в MemoryRead следующим образом.Цитата:
Сообщение от Hardella 1.7.0
Фактическая длительность PRU цикла. Т.е. время от одной записи выходов до следующей.
Например, если указать "min cycle: 1µs", и PRU программа очень простая (всегда укладывается в 1мкс), то OutputWriteTimeMicros будут равны 1.0Код:maxOutputWriteTimeMicros : REAL; (* макс. длительность цикла за всё время работы ПЛК, мкс *)
lastOutputWriteTimeMicros : REAL; (* последняя длительность цикла, считанная из PRU, мкс *)
Ну, мы указали, что хотим 1 мкс цикл, его и получили.
Если же программа заняла дольше, то тут будет фактическое значение.
Разумеется, второй вопрос "а сколько реально занимает программа, без учёта ожиданий?"
Для этого выведены переменные про длительность полезного кода (это длительность программы + 2 опроса входов с фильтрацией + приём-передача)
Код:maxCycleTimeMicros : REAL; (* макс. длительность работы PRU программы за всё время работы ПЛК, мкс *)
lastCycleTimeMicros : REAL; (* последняя длительность работы PRU программы, считанная из PRU, мкс *)
Владимир Ситников
Спасибо! Протестирую и сообщу о результатах.
Кстати, на следующей неделе предстоит воплощение одного из проектов на реальном железе в реальной установке. Будет использоваться сокращенная версия моего проекта. Будет использоваться только PRU-энкодер с детектором машинного нуля.
Владимир, какое минимальное время допустимо между этим
SteppersConfig_Pru1MemoryTransfer(STEPPER1_PRU1_st epper_enable := FALSE);
и этим
SteppersConfig_Pru1MemoryTransfer(STEPPER1_PRU1_st epper_enable := TRUE);
операторами ?
Если цикл PRU 1 мкс, то 2...3 мкс ?
А обмен между ЦП и PRU постоянно идет ? Когда начинается и когда заканчивается обмен между ЦП и PRU ? Или как прошло это
SteppersConfig_Pru0Init();
SteppersConfig_Pru1Init();
так и пошел обмен ?
Или надо постоянно делать это иначе обмена не будет?
SteppersConfig_Pru0MemoryTransfer();
SteppersConfig_Pru1MemoryTransfer();
Да.
PRU программа выполняет следующее:
Иначе говоря, большую часть времени PRU ядро ждёт от КДС программы команд на чтение-запись PRU данных.Код:t0 := засекаем_время();
WHITE TRUE
USER_PROGRAM(); (* вызываем программу, указанную в pru configuration *)
REPEAT
обрабатываем_обмен_данными_с_host();
читаем_входы();
UNTIL время < t0 + мин_ц
END_REPEAT;
t0 := засекаем_время();
записываем_выходы();
читаем_входы();
END_WHILE;
Но эти данные PRU программа сможет использовать только на следующем PRU цикле.
Возвращаясь к исходному вопросу "когда можно перезапускать stepper". После перевода enable в false нужно выполнять memoryread и ждать когда блок сменит состояние. В целом, за одну-две микросекунды это может и случиться, т.е. можно это выполнять и в рамках одного цикла ПЛК (while stepper.state<>... memory read ...).
Нет. После Init запускается только "ответная" сторона в PRU. Сами данные идут только по управлению КДС программы.
Чтобы данные реально ходили нужно вызывать MemoryTransfer или MemoryRead или MemoryWrite.
При каждом вызове Memory* будет новый обмен.
У меня в прерывающей программе, которая вызывается с периодом 200 мкс записано
SteppersConfig_Pru1MemoryTransfer();
Допустим в основной программе ПЛК однажды записано так
SteppersConfig_Pru1MemoryTransfer(
STEPPER1_PRU1_dir := Dir,
STEPPER1_PRU1_stepper_accel_ramp := Accel,
STEPPER1_PRU1_stepper_decel_ramp := 200000000,
STEPPER1_PRU1_stepper_max_speed := 200000,
STEPPER1_PRU1_stepper_min_speed := 0,
STEPPER1_PRU1_stepper_quantity := Quantity,
STEPPER1_PRU1_stepper_enable := TRUE
);
Правильно ли я понимаю, что каждые 200 мкс между программой PRU и основной программой будут передаваться указанные выше значения ?
Если MemoryTransfer() вызывается в 200мкс таймере, то в основной программе достаточно просто менять-читать значения переменных:
Либо просто в 200мкс таймере вызывать MemoryTransfer со всеми параметрами.Код:SteppersConfig_Pru1MemoryTransfer.STEPPER1_PRU1_dir := Dir;
SteppersConfig_Pru1MemoryTransfer.STEPPER1_PRU1_stepper_accel_ramp := Accel;
...
Уточняю вопрос. Достаточно ли однократно вызвать
SteppersConfig_Pru1MemoryTransfer(
STEPPER1_PRU1_dir := Dir,
STEPPER1_PRU1_stepper_accel_ramp := Accel,
STEPPER1_PRU1_stepper_decel_ramp := 200000000,
STEPPER1_PRU1_stepper_max_speed := 200000,
STEPPER1_PRU1_stepper_min_speed := 0,
STEPPER1_PRU1_stepper_quantity := Quantity,
STEPPER1_PRU1_stepper_enable := TRUE
);
чтобы эти значения постоянно передавались посредством вызова SteppersConfig_Pru1MemoryTransfer(); в прерывающей программе ?
Что значит однажды?
При вызове SteppersConfig_Pru1MemoryTransfer(), в PRU передаются значения переменных блока SteppersConfig_Pru1MemoryTransfer.
Запись
Это абсолютно то же самое, что иКод:SteppersConfig_Pru1MemoryTransfer(
STEPPER1_PRU1_dir := Dir,
STEPPER1_PRU1_stepper_accel_ramp := Accel,...
Иными словами, запись SteppersConfig_Pru1MemoryTransfer(STEPPER1_PRU1_di r := Dir,) не несёт в себе какого-то магического "отныне STEPPER1_PRU1_dir будет отслеживать значение переменной Dir". STEPPER1_PRU1_dir и Dir это независимые переменные, поэтому, если нужно передавать новое значение Dir в PRU, то нужно и выполнять присваивание в переменную STEPPER1_PRU1_dir.Код:SteppersConfig_Pru1MemoryTransfer.STEPPER1_PRU1_dir := Dir;
SteppersConfig_Pru1MemoryTransfer.STEPPER1_PRU1_stepper_accel_ramp := Accel;
SteppersConfig_Pru1MemoryTransfer();
Вот так например
CASE N OF
10:
SteppersConfig_Pru1MemoryTransfer(
STEPPER1_PRU1_dir := Dir,
STEPPER1_PRU1_stepper_accel_ramp := Accel,
STEPPER1_PRU1_stepper_decel_ramp := 200000000,
STEPPER1_PRU1_stepper_max_speed := 200000,
STEPPER1_PRU1_stepper_min_speed := 0,
STEPPER1_PRU1_stepper_quantity := Quantity,
STEPPER1_PRU1_stepper_enable := TRUE
);
N := 20;
20:
;
END_CASE
Владимир Ситников
Отчитываюсь по своему проекту.
Произведен монтаж ПЛК в шкаф машины, компиляция кода использована версией 1.7.0, код работает отлично, сбоев за двое суток непрерывной работы не зафиксировано.
Есть небольшой вопросик. При выполнении в КДС Проект>Контроль>Неиспользуемые переменные выводит вот такую табличку:
Вложение 30216
В принципе это не критично, но хотелось бы знать детали.
Здорово.
Идею с Hardella_SimulationDetector'ом подсказал Валенок: http://www.owen.ru/forum/showthread....l=1#post233794
Решаемая проблема в том, что программы MemoryRead/Write/Transfer не работают в режиме симуляции (КДС не симулирует работу PRU), поэтому чтобы проект не падал в запуске этой самой симуляции в коде нужно как-то определять выполняется ли код на реальном ПЛК или нет.
Там действительно переменные объявлены и не используются. Можно, наверное, сделать их "используемыми", чтобы не вызывали предупреждений.
В MemoryTransfer действительно неиспользуемые переменные. Надо убрать.
Я логику в Read/Write перенёс, а переменные остались.
У меня такое подозрение, что если принудительно остановить работу ФБ Steper
SteppersConfig_Pru1MemoryTransfer.STEPPER1_PRU1_st epper_enable := FALSE;
без предварительной проверки
IF SteppersConfig_Pru1MemoryTransfer.STEPPER1_PRU1_st epper_state = STOP_STEPPER_RUN_STATE
то после этого ФБ перестает нормально работать.
CASE R200 OF
0: (* *)
Stop_Motor();
SSP_Y := FALSE; (* Нет исходного положения *)
TON3(IN := FALSE, PT:= T#0s);
R200 := 10;
10: (* Вперед или стоп *)
IF (D1) THEN
SteppersConfig_Pru1MemoryTransfer(
STEPPER1_PRU1_dir := FALSE,
STEPPER1_PRU1_stepper_accel_ramp := 5000,
STEPPER1_PRU1_stepper_decel_ramp := 50000,
STEPPER1_PRU1_stepper_max_speed := 10000,
STEPPER1_PRU1_stepper_min_speed := 0,
STEPPER1_PRU1_stepper_quantity := 1000000,
STEPPER1_PRU1_stepper_enable := TRUE
);
ELSE SteppersConfig_Pru1MemoryTransfer(STEPPER1_PRU1_st epper_enable := FALSE); R200 := 15; END_IF
15: (* Пауза *)
TON3(IN := TRUE, PT:= UT_500ms); (* Запустили таймер *)
IF (TON3.Q = TRUE) THEN TON3(IN := FALSE, PT:= T#0s); R200 := 20; END_IF
20: (* Назад *)
IF (NOT D1) THEN
SteppersConfig_Pru1MemoryTransfer(
STEPPER1_PRU1_dir := TRUE,
STEPPER1_PRU1_stepper_accel_ramp := 5000,
STEPPER1_PRU1_stepper_decel_ramp := 50000,
STEPPER1_PRU1_stepper_max_speed := 10000,
STEPPER1_PRU1_stepper_min_speed := 0,
STEPPER1_PRU1_stepper_quantity := 1000000,
STEPPER1_PRU1_stepper_enable := TRUE
);
ELSE R200 := 30; END_IF
30: (* Стоп *)
SteppersConfig_Pru1MemoryTransfer(STEPPER1_PRU1_st epper_enable := FALSE);
SSP_Y := TRUE;
END_CASE
В этом ФБ происходит затык на шаге 20, вал ШД вращается, но очень медленно. Т.е. частота вращения не соответствует заданию.
D1 = FALSE, следовательно выполняется это
SteppersConfig_Pru1MemoryTransfer(
STEPPER1_PRU1_dir := TRUE,
STEPPER1_PRU1_stepper_accel_ramp := 5000,
STEPPER1_PRU1_stepper_decel_ramp := 50000,
STEPPER1_PRU1_stepper_max_speed := 10000,
STEPPER1_PRU1_stepper_min_speed := 0,
STEPPER1_PRU1_stepper_quantity := 1000000,
STEPPER1_PRU1_stepper_enable := TRUE
);
Да еще каждые 200 мкс исполняется это
SteppersConfig_Pru1MemoryTransfer();
Может это наложение все портит ?
В онлайне все правильно показывает.
Описанное "вал ШД вращается, но очень медленно. Т.е. частота вращения не соответствует заданию" больше похоже на проблему самого блока.
Вроде, такое уже исправлялось как-то.
"Лишние" вызовы SteppersConfig_Pru1MemoryTransfer, на мой взгляд, портить ничего не должны. Их же легко убрать и проверить, влияют ли они на что-нибудь. В обозначенной выше программе они не нужны.
В том то и дело, что SteppersConfig_Pru1MemoryTransfer.STEPPER_PRU1_ste pper_state в ФБ не анализируется.
Останов Steper делается по срабатыванию датчика.