diff options
author | pux <pux@pux.dom> | 2021-01-07 19:39:17 +0100 |
---|---|---|
committer | pux <pux@pux.dom> | 2021-01-07 19:39:17 +0100 |
commit | 39765e002e71a2dd54e932469877acfc1b6fcb67 (patch) | |
tree | 83456425ad35e8c47894dee6660bd9ed574ebfdd /exp/FB_INC_DECODER.EXP | |
parent | bbbba6c698a73fc1a6bd00f7a07c89ba19ce38c5 (diff) | |
download | lib61131aux-39765e002e71a2dd54e932469877acfc1b6fcb67.tar.gz lib61131aux-39765e002e71a2dd54e932469877acfc1b6fcb67.tar.bz2 lib61131aux-39765e002e71a2dd54e932469877acfc1b6fcb67.zip |
Diffstat (limited to 'exp/FB_INC_DECODER.EXP')
-rw-r--r-- | exp/FB_INC_DECODER.EXP | 133 |
1 files changed, 133 insertions, 0 deletions
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:
+
+ <OSCAT>
+ 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;
+ </OSCAT>
+
+=> 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
|