To use this file copy and paste this:    // #URL-lib "http://pin1.org/forthlib/flb/Examples/rotary.fth"   into BV Terminal 3 or here to download.

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


Full Contents of File

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