// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Rotary encoders 1 // This version does not use interrupts and culd be easily // used as a library for other projects. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // REQUIRES: // #URL-lib "http://pin1.org/forthlib/flb/General/pinsel.flb" // CONSTANTS: // define the three wires used for the encoder 25 constant line1 26 constant line2 6 constant pushb // variable oldRa variable oldRb variable detent variable temp // A rotary encoder presents two switches that are alternatively // switched on and off. There is a DETENT period when the switches // are either both on or both off, i.e the same. What happens after // this determines the direction of rotation. If follows from this // description that this is dynamic, the state of the switches must // be read only AFTER the detent state. // // Looking at two outputs A and B // time1 Aon + Bon = detent+ // time2 Aoff + Bon = clockwise // // time1 Aoff + Boff = detent- // time2 Aon + Boff = clockwise // // The reading is therfore a two stage process, the detent stage and // the read stage, only one channel needs to be read as follows: // After detent: // detent+ and Aoff = clocwise, detenet+ and Aon = CCW // detent- and Aon = clockwise, detent- and Aoff = CCW // // We have therfore 3 states of detent 0, + and -, + and - where // both A and B are on and 0 where either A to B is off. // // Set up rotary encoder lines A and B : r-set line1 io-in line2 io-in pushb io-in // push switch ; // return 1 if the values are different // from last time // ( --- 1|0) : ra@? // detect change line1 p@ 1+ oldRa @ 1 and xor ; // ( --- 1|0) : rb@? // detect change line2 p@ 1+ oldRb @ 1 and xor ; // this is a pin detect with switch debounce // returns 1 when off 0 when on // ( --- 1/0) : Ra@ ra@? // changed if 1 ms ra@? if // still different line1 p@ 1+ oldRa ! then then oldRa @ 1- ; : Rb@ rb@? // changed if 1 ms rb@? if // still different line2 p@ 1+ oldRb ! then then oldRb @ 1- ; // push switch // ( value ---) : Rc@ pushb p@ ; // At the switch detent both A and B are either high or // low, this is noted and saved in DETENT as a value of either // -1 or 1. *This can only be done when DETANT is = to 0 // When the switch is not at detent, *if detent does not = 0 a // -1 or +1 is left depending on the combined value of Ra and DETENT // When the value is left *DETENT is cleared. // * The variable DETENT is used for saving the previous state of the coincedent // switches and also as a flag to prevent re-triggering. // ( --- value, -1 |0) : r-rot ra@ rb@ 2dup xor // NOT detent if // NOT detent drop // drop Rb detent @ // get saved ?dup if // should be > 0 if valid 0 detent ! // clear detent xor // detent+Ra 0< if 1 else -1 then // leave value -1 // and indicator else drop 0 // drop Rb and leave 0 then else detent @ 0= // should be 0 if + 1+ // add Ra+Rb+1 gives -1 or 1 detent ! // save for NOT detent 0 // leave 0 else 2drop 0 // drop Ra+Rb and leave 0 then then ; : r-test r-set 0 temp ! begin r-rot if temp +! temp @ . then key? until ;