CODESYS 边缘检测问题(反弹)

CODESYS problems with edge detection (bounce)

我的 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)

我会以更面向对象的方式实现整个逻辑。

首先,我们定义一个Button。

声明部分:

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

该按钮有四个属性:


第一 属性:

声明部分:

 PROPERTY getValue : String

实现部分:

getValue := sValue;

第二 属性:

声明部分:

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

处理程序有两个方法:


第一种方法:

声明部分:

METHOD onPush 
VAR_INPUT
    sValue : STRING;
END_VAR

实现部分:

floorstorage := concat(floorstorage,sValue);

第二种方法:

声明部分:

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 将其分配给另一个变量。

这样做比将其声明为 global.

可以为您的变量提供更强大的封装和数据保护

我在这里没有看到任何边缘检测

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 会在每个 PLC 循环中更改其状态。这意味着如果当您释放按钮时 PLC 进行了偶数次循环,则什么都不会改变,如果是奇数次 f 循环,它将发生变化。以下是检测上升沿的方法。

VAR
    xSignal, xSignalM: BOOL;
END_VAR

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

这样的条件只会在一个PLC周期起作用,一切都会好起来的。所以你的代码看起来像这样。

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

您需要实施边缘检测。这是您可以使用的代码模板:

//  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;