Проблемы CODESYS с обнаружением края (отскок) - PullRequest
0 голосов
/ 07 января 2020

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

КОД:

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)

Ответы [ 3 ]

0 голосов
/ 08 января 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 меняет свое состояние на каждом цикле PL C, пока вы удерживаете кнопку. Это означает, что если при отпускании кнопки PL C сделать четное количество циклов, ничего не изменится, а если нечетное число f циклов, то оно изменится. Вот как вы обнаружите нарастающий фронт.

VAR
    xSignal, xSignalM: BOOL;
END_VAR

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

Таким образом, условие будет работать только один цикл PL C, и все будет хорошо. Таким образом, ваш код будет выглядеть так:

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
0 голосов
/ 08 января 2020

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

//  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;
0 голосов
/ 08 января 2020

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

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

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

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 := '';

Сейчас нам нужно инициировать кнопки и вызывать их в основном.

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

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

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

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

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

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

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

...