Проблемы CODESYS с определением границ (отскока)

У меня проблема с моей программой CODESYS. У меня есть три кнопки, которые определены как ввод. Для каждой кнопки хранится номер. Например, число 1. Теперь я создал программу, которая распознает край кнопки и сохраняет числовое значение (2) кнопки в массиве. Если теперь вы нажмете другую кнопку со значением (3), значение также снова будет сохранено в переменной. Две переменные должны быть сложены вместе. 2 + 3 = 23. У меня в программе такая проблема, что если я нажимаю кнопку тестер со значением 2, то получаю 22. Это неправильно. Я думаю проблема из-за помятости кнопки. Обнаружено несколько краев. Вот и хотел решить этот софт технически с опозданием. Ты хоть представляешь, как я могу это запрограммировать?

КОД:

IF (PLC_PRG.calls[5].gpio = TRUE) THEN // edge detection on gpio
    IF (counter = 0) THEN // counter for the first value
        floorstorage2[0] := PLC_PRG.calls[5].message.floorstore[5]; // save button value in the array to calculate the total
        counter := 1;
    ELSE
        floorstorage2[1] := PLC_PRG.calls[5].message.floorstore[5]; // save button value in the array to calculate the total
        counter := 0;
    END_IF
END_IF

IF (PLC_PRG.calls[6].gpio = TRUE) THEN // edge detection on gpio
    IF (counter = 0) THEN // counter for the first value
        floorstorage2[0] := PLC_PRG.calls[6].message.floorstore[6]; // save button value in the array to calculate the total
        counter := 1;
    ELSE
        floorstorage2[1] := PLC_PRG.calls[6].message.floorstore[6]; // save button value in the array to calculate the total
        counter := 0;
    END_IF
END_IF

IF (PLC_PRG.calls[7].gpio = TRUE) THEN // edge detection on gpio
    IF (counter = 0) THEN // counter for the first value
        floorstorage2[0] := PLC_PRG.calls[7].message.floorstore[7]; // save button value in the array to calculate the total
        counter := 1;
    ELSE
        floorstorage2[1] := PLC_PRG.calls[7].message.floorstore[7]; // save button value in the array to calculate the total
        counter := 0;
    END_IF
END_IF


GlobalVar.floorstorage := concat(floorstorage2[0],floorstorage2[1]); // Total of value 1 and value 2 (1 + 2 = 12)

person lorex04    schedule 07.01.2020    source источник


Ответы (3)


Вам нужно реализовать обнаружение границ. Вот шаблон кода, который вы можете использовать:

//  Generate Oneshot Signal 

VAR_INPUT
    SIGNAL : BOOL; // Input
END_VAR

VAR
    LATCH_SIGNAL : BOOL; // Latch
END_VAR

VAR_TEMP
    OS_P_SIGNAL : BOOL; // Oneshot - Rising edge detection
    OS_N_SIGNAL : BOOL; // Oneshot - Falling edge detection
END_VAR

//Code - Rising edge detection
OS_P_SIGNAL := SIGNAL AND NOT LATCH_SIGNAL;
LATCH_SIGNAL := SIGNAL;

//Code - Falling edge detection
OS_N_SIGNAL := NOT SIGNAL AND NOT LATCH_SIGNAL;
LATCH_SIGNAL := NOT SIGNAL;
person dergroncki    schedule 08.01.2020

Я не вижу здесь никакого определения края

IF (PLC_PRG.calls[5].gpio = TRUE) THEN // edge detection on gpio
    IF (counter = 0) THEN // counter for the first value
        floorstorage2[0] := PLC_PRG.calls[5].message.floorstore[5]; // save button value in the array to calculate the total
        counter := 1;
    ELSE
        floorstorage2[1] := PLC_PRG.calls[5].message.floorstore[5]; // save button value in the array to calculate the total
        counter := 0;
    END_IF
END_IF

Вы проверяете, нажата ли кнопка. Это означает, что пока вы держите эту кнопку, это условие выполняется. Это означает, что counter меняет свое состояние в каждом цикле ПЛК, пока вы удерживаете кнопку. Это означает, что если при отпускании кнопки ПЛК сделал четное число циклов, ничего не изменится, а если нечетное число f циклов, то изменится. Вот как вы обнаруживаете нарастающий фронт.

VAR
    xSignal, xSignalM: BOOL;
END_VAR

IF xSignal AND NOT xSignalM THEN
    // Raising edge is here
END_IF
xSignalM := xSignal;

В этом случае условие будет работать только один цикл ПЛК, и все будет в порядке. Таким образом, ваш код будет выглядеть так.

VAR
    M1, M1, M3: BOOL;
END_VAR

IF (PLC_PRG.calls[5].gpio AND NOT M1) THEN // edge detection on gpio
    IF (counter = 0) THEN // counter for the first value
        floorstorage2[0] := PLC_PRG.calls[5].message.floorstore[5]; // save button value in the array to calculate the total
        counter := 1;
    ELSE
        floorstorage2[1] := PLC_PRG.calls[5].message.floorstore[5]; // save button value in the array to calculate the total
        counter := 0;
    END_IF
END_IF
M1 = PLC_PRG.calls[5].gpio;

IF (PLC_PRG.calls[6].gpio  AND NOT M2) THEN // edge detection on gpio
    IF (counter = 0) THEN // counter for the first value
        floorstorage2[0] := PLC_PRG.calls[6].message.floorstore[6]; // save button value in the array to calculate the total
        counter := 1;
    ELSE
        floorstorage2[1] := PLC_PRG.calls[6].message.floorstore[6]; // save button value in the array to calculate the total
        counter := 0;
    END_IF
END_IF
M2 = PLC_PRG.calls[6].gpio;

IF (PLC_PRG.calls[7].gpio  AND NOT M3) THEN // edge detection on gpio
    IF (counter = 0) THEN // counter for the first value
        floorstorage2[0] := PLC_PRG.calls[7].message.floorstore[7]; // save button value in the array to calculate the total
        counter := 1;
    ELSE
        floorstorage2[1] := PLC_PRG.calls[7].message.floorstore[7]; // save button value in the array to calculate the total
        counter := 0;
    END_IF
END_IF
M3 = PLC_PRG.calls[7].gpio;

Или вы можете использовать R_TRIG

VAR
    RT1:R_TRIG;
END_VAR

R1(CLK := PLC_PRG.calls[5].gpio);
IF (R1.Q) THEN
    IF (counter = 0) THEN
        floorstorage2[0] := PLC_PRG.calls[5].message.floorstore[5];
        counter := 1;
    ELSE
        floorstorage2[1] := PLC_PRG.calls[5].message.floorstore[5];
        counter := 0;
    END_IF
END_IF
person Sergey Romanov    schedule 08.01.2020

Я бы реализовал всю логику более объектно-ориентированным способом.

Сначала мы определяем кнопку.

Часть декларации:

FUNCTION_BLOCK FB_Button
VAR
    bSignal   AT%I* : BOOL;
    IButtonHandler : I_ButtonHandler;

    fbPushTimer : TON;
    fbTrig : R_TRIG;

    sValue : STRING;
END_VAR

Часть реализации:

IF IButtonHandler = 0
THEN
    RETURN;
END_IF

fbPushTimer(IN:= bSignal, PT:=T#50MS);
fbTrig(CLK:=fbPushTimer.Q);

IF fbTrig.Q
THEN
    IButtonHandler.onPush(sValue);  
END_IF

Кнопка имеет четыре свойства:


1-е свойство:

Часть декларации:

 PROPERTY getValue : String

Часть реализации:

getValue := sValue;

2-е свойство:

Часть декларации:

PROPERTY isPushed : BOOL

Часть реализации:

isPushed := bSignal;

3-е свойство:

Часть декларации:

PROPERTY setPushHandler : I_ButtonHandler

Часть реализации:

IButtonHandler := setPushHandler;

4-е свойство:

Часть декларации:

PROPERTY setValue : String

Часть реализации:

sValue := setValue;

Затем мы определяем интерфейс.

INTERFACE I_ButtonHandler

и добавьте метод интерфейса:

METHOD onPush 
VAR_INPUT
    sValue : STRING;
END_VAR

Наконец мы определяем обработчик.

Часть декларации:

FUNCTION_BLOCK FB_ButtonHandler IMPLEMENTS I_ButtonHandler
VAR_OUTPUT
    floorstorage : STRING;
END_VAR

Обработчик имеет два метода:


1-й метод:

Часть декларации:

METHOD onPush 
VAR_INPUT
    sValue : STRING;
END_VAR

Часть реализации:

floorstorage := concat(floorstorage,sValue);

2-й метод:

Часть декларации:

METHOD reset 

Часть реализации:

floorstorage := '';

Теперь нам нужно инициализировать кнопки и вызвать их в main.

Основная часть объявления:

PROGRAM MAIN
VAR 
    aButtons : ARRAY[1..10] OF FB_Button;
    fbButtonHandler : FB_ButtonHandler;
    i : UINT;
    bInit : BOOL;
END_VAR

Часть реализации:

IF NOT bInit
THEN
    FOR i := 1 TO 10 DO
        aButtons[i].setPushHandler := fbButtonHandler;
        aButtons[i].setValue := UINT_TO_STRING(i);
    END_FOR
    bInit := TRUE;
END_IF

FOR i := 1 TO 10 DO
    aButtons[i]();
END_FOR

Вы можете выбрать собственное значение кнопки в зависимости от кнопки.

Для простоты я присвоил индексу цикла значение кнопки.

При каждом нажатии кнопки метод onPush вызывается только один раз через 50 мс.

Если вы хотите получить доступ к значению floorstorage, вы просто вызываете fbButtonHandler.floorstorage, чтобы назначить его другой переменной.

Поступая таким образом, вы достигаете более надежной инкапсуляции и защиты данных для вашей переменной, чем при объявлении ее как глобальной.

person Filippo Boido    schedule 07.01.2020
comment
Где я должен определить интерфейс? - person lorex04; 08.01.2020
comment
Вы используете Codesys 2 или 3? - person Filippo Boido; 08.01.2020
comment
help.codesys.com/api-content/2 /codesys/3.5.12.0/ru/ - person Filippo Boido; 08.01.2020
comment
Интерфейсы и объектно-ориентированное программирование в целом работают только с Codesys 3. - person Filippo Boido; 08.01.2020
comment
У меня есть версия 3.5 Sp15 Patch 2. - person lorex04; 08.01.2020
comment
Я добавил свойство getValue в кнопку FB. Но я получаю сообщение об ошибке со свойством getValule: ';, :=, REF=, ( или [' ожидается вместо 'getValue' - person lorex04; 08.01.2020
comment
Вы поместили PROPERTY getValue : String в часть объявления и getValue := sValue; в части реализации? (дважды щелкните, чтобы открыть часть реализации). - person Filippo Boido; 08.01.2020
comment
Нет, но теперь я знаю, как это сделать. Свойство isPushed — это Get или Set? - person lorex04; 08.01.2020
comment
Get, вы можете удалить часть набора после того, как вы определили isPushed как свойство. - person Filippo Boido; 08.01.2020
comment
Хорошо, я создал свойства. И теперь я должен определить интерфейс? - person lorex04; 08.01.2020
comment
Посмотрите на ссылку, которую я дал вам в разделе «Реализация интерфейса в новом функциональном блоке». - person Filippo Boido; 08.01.2020
comment
Вы должны добавить метод интерфейса после того, как вы создали интерфейс. - person Filippo Boido; 08.01.2020
comment
Итак, я создал Кодекс. Но я получаю 10 одинаковых ошибок: Нет VAR_CONFIG для «PLC_PRG.aButtons[1-10].bSignal». Когда я создаю программу, я не получаю никаких ошибок. Но когда я хочу войти, я получаю эти 10 ошибок. - person lorex04; 08.01.2020
comment
Вам необходимо сопоставить переменные с картой процесса:help.codesys.com/api-content/2/codesys/3.5.12.0/en/ - person Filippo Boido; 08.01.2020
comment
Если в вашем проекте нет реального оборудования, замените bSignal AT%I* : BOOL; с bSignal: BOOL; - person Filippo Boido; 08.01.2020