From 39765e002e71a2dd54e932469877acfc1b6fcb67 Mon Sep 17 00:00:00 2001 From: pux Date: Thu, 7 Jan 2021 19:39:17 +0100 Subject: add *.exp; (this is redundant information, just to be able to diff later on) --- exp/FB_INC_DECODER.EXP | 133 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 exp/FB_INC_DECODER.EXP (limited to 'exp/FB_INC_DECODER.EXP') diff --git a/exp/FB_INC_DECODER.EXP b/exp/FB_INC_DECODER.EXP new file mode 100644 index 0000000..2433c18 --- /dev/null +++ b/exp/FB_INC_DECODER.EXP @@ -0,0 +1,133 @@ + +(* @NESTEDCOMMENTS := 'Yes' *) +(* @PATH := '' *) +(* @OBJECTFLAGS := '0, 8' *) +(* @SYMFILEFLAGS := '2048' *) +FUNCTION_BLOCK FB_INC_DECODER +VAR_INPUT + IN_xChA : BOOL; (* Channel A *) + IN_xChB : BOOL; (* Channel B, 90-degree rotated to Channel A *) + IN_xReset : BOOL; (* Reset counter to 0 *) + + IN_xEnPosWindow : BOOL; (* TRUE if you want to overflow the counting at min/max values below *) + IN_diMinVal : DINT; + IN_diMaxVal : DINT; +END_VAR +VAR_OUTPUT + OUT_diActVal : DINT; +END_VAR +VAR_OUTPUT PERSISTENT + OUT_pdiActVal : DINT; +END_VAR +VAR + rtChA : R_TRIG; + rtChB : R_TRIG; + ftChA : F_TRIG; + ftChB : F_TRIG; + xFirstCycle : BOOL; +END_VAR + +(* + +Incremental Encoder Decoder FB +Author: mo +Date: 2019-02 + + alternative OSCAT implementation (faulty!) below: + + + axb := cha XOR chb; + + (* create pulses for channel a *) + clka := cha XOR edgea; + edgea := cha; + + clkb := chb XOR edgeb; + edgeb := chb; + + (* create pulses for both channels *) + clk := clka OR clkb; + + (* set the direction output *) + IF axb AND clka THEN dir := TRUE; END_IF; + IF axb AND clkb THEN dir := FALSE; END_IF; + + (* increment or decrement the counter *) + IF clk AND dir THEN cnt := cnt + 1; END_IF; + IF clk AND NOT dir THEN cnt := cnt -1; END_IF; + + (* reset the counter if rst active *) + IF rst THEN cnt := 0; END_IF; + + +=> problem here is: if your first pulse is e.g. a rising edge on CHb + with a high signal on CHa, it will increment cnt, but in the FALSE + direction instead of the TRUE direction. so your first pulse might count + into the wrong direction! + + +This implementation accounts for all possible transitions. +You can use OUT_diActVal or the persistent Version OUT_pdiActVal if your hardware +is not moving while powered off to avoid reference runs at each restart of the PLC. + + 1 |----| |----| |- +A 0 _| |____| |____| + + 1 |----| |----| |- +B 0 _| |____| |____| + +*) + +(* @END_DECLARATION := '0' *) +rtChA(clk:=IN_xChA); +rtChB(clk:=IN_xChB); +ftChA(clk:=IN_xChA); +ftChB(clk:=IN_xChB); + +(* don't evaluate the changing edges when PLC starts up *) +IF xFirstCycle THEN + IF (rtChA.Q AND NOT IN_xChB) + OR (ftChA.Q AND IN_xChB) + OR (rtChB.Q AND IN_xChA) + OR (ftChB.Q AND NOT IN_xChA) + THEN + OUT_diActVal := OUT_diActVal + 1; + OUT_pdiActVal := OUT_pdiActVal + 1; + END_IF + + IF (rtChA.Q AND IN_xChB) + OR (ftChA.Q AND NOT IN_xChB) + OR (rtChB.Q AND NOT IN_xChA) + OR (ftChB.Q AND IN_xChA) + THEN + OUT_diActVal := OUT_diActVal - 1; + OUT_pdiActVal := OUT_pdiActVal - 1; + END_IF +END_IF + +IF IN_xReset THEN + OUT_diActVal := 0; + OUT_pdiActVal := 0; +END_IF + +IF IN_xEnPosWindow THEN + IF OUT_diActVal < IN_diMinVal THEN + OUT_diActVal := IN_diMaxVal - 1; + END_IF + + IF OUT_diActVal >= IN_diMaxVal THEN + OUT_diActVal := IN_diMinVal; + END_IF + + (* for persistent counter *) + IF OUT_pdiActVal < IN_diMinVal THEN + OUT_pdiActVal := IN_diMaxVal - 1; + END_IF + + IF OUT_pdiActVal >= IN_diMaxVal THEN + OUT_pdiActVal := IN_diMinVal; + END_IF +END_IF + +xFirstCycle := TRUE; +END_FUNCTION_BLOCK -- cgit v1.2.2-1-g5e49