【问题标题】:CODESYS problems with edge detection (bounce)CODESYS 边缘检测问题(反弹)
【发布时间】:2020-01-09 16:23:27
【问题描述】:

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

【问题讨论】:

    标签: edge-detection codesys


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      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
      

      【讨论】:

        【解决方案3】:

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

        首先,我们定义一个按钮。

        声明部分:

        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;
        

        第三个属性:

        声明部分:

        PROPERTY setPushHandler : I_ButtonHandler
        

        实现部分:

        IButtonHandler := setPushHandler;
        

        第四个属性:

        声明部分:

        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 方法仅在 50ms 后被调用一次。

        当您想要访问 floorstorage 的值时,只需调用 fbButtonHandler.floorstorage 将其分配给另一个 var。

        与将变量声明为全局相比,这样做可以为您的变量提供更强大的封装和数据保护。

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-10-04
        • 2011-12-08
        • 2013-10-20
        • 2014-03-30
        • 1970-01-01
        • 2013-06-14
        • 2021-03-01
        相关资源
        最近更新 更多