Rotary encoder with Flowcode?

For Flowcode users to discuss projects, flowcharts, and any other issues related to Flowcode 2 and 3.

Moderators: Benj, Mods

Promitheus
Posts: 3
Joined: Mon Feb 06, 2006 10:35 am
Contact:

Rotary encoder with Flowcode?

Postby Promitheus » Mon Feb 06, 2006 10:39 am

Does anybody know how I can make a rotary encoder as a macro or where can I find it as an object to insert in flowcode?

thanks in advance

User avatar
Steve
Matrix Staff
Posts: 3073
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 87 times
Been thanked: 387 times
Contact:

Postby Steve » Mon Feb 06, 2006 11:59 am

We do not currently have an encoder component or macro code available, so you will need to make one yourself. Creating your own components can be done but is quite tricky, so I suggest you create suitable macros instead.

Certain PICmicros have inbuilt quaderature encoder support, but these are 18F devices which are not supported in FlowCode (yet!). Other PICmicros (including 16F ones) have an external timer/counter input which may be useful.

If the encoder signal you are monitoring is not too fast, you could trap it using the interrupt on RB0 (or trap multiple encoder signals using the high-nibble port B interrupt).

Promitheus
Posts: 3
Joined: Mon Feb 06, 2006 10:35 am
Contact:

Postby Promitheus » Mon Feb 06, 2006 12:38 pm

No its not too fast at all.
I want to use a knob controller to adjust a volume control and select input with a second one.

User avatar
Steve
Matrix Staff
Posts: 3073
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 87 times
Been thanked: 387 times
Contact:

Postby Steve » Mon Feb 06, 2006 1:01 pm

If the input is that slow, you may be able to write your code so that its main loop constantly checks for changes in both encoder inputs. I'm not sure how you would handle direction, though.

Gizmo
Posts: 8
Joined: Wed Jan 18, 2006 3:23 am
Contact:

Postby Gizmo » Wed Feb 08, 2006 11:25 pm

Promitheus, if you get this figured out I'd like to hear about it. I've been wondering how to use an encoder for user input myself.

jimhumphries
Posts: 112
Joined: Wed Oct 12, 2005 6:29 pm
Location: USA
Been thanked: 1 time
Contact:

Postby jimhumphries » Mon Feb 13, 2006 12:52 am

Guys:

This might be a good start. I’m sure there are other more streamlined/elegant approaches and I’m sorry that this is just a description and not actual Flowcode (I haven’t actually coded and tested it yet).

The encoder you’re probably going to use is a quadrature type that generates a two bit gray code where the A and B outputs are staggered by 90 degrees. For the encoder I have, both outputs are zero (open) when the encoder is in a mechanical detent (I happen to have a Bourns ECW style encoder so that’s my model for this pseudo-code - to look at a data sheet search [url]digikey.com[/url] for part number ECW1DB24BC0024-ND). When the encoder is between detents (in motion) the A and B outputs will generate a binary coded decimal (BCD) sequence that changes with the direction of rotation. For mine in clockwise (CW) rotation the sequence is 0 (detent), 1, 3, 2, 0 (next detent) and for counter-clockwise (CCW) rotation the sequence is 0 (detent), 2, 3, 1, 0 (next detent). Any port can be used to interface the encoder. This example assumes that that BCD values 0, 1, 2 and 3 are the possible return values for a port read so port bits 0 and 1 are used as inputs and they are pulled low (4.7K Ohm resistors to ground should work). The encoder common is assumed to be connected either to Vcc or to another port bit (so that you can enable or disable the encoder when you want to).

The routine employs tests to determine the numerical sequence and, hence, the direction of rotation. That done, “up” events (presume clockwise) and “down” events (presume counter-clockwise) are generated. The value of the variable UP is the running total of “up” events and the value of the variable DOWN is the running total of “down” events. Anything you may want to do about an event (other than incrementing the value of UP or DOWN) can be done at the time an event is generated or later in the main loop, based on a reading of the value of UP or DOWN.

You may want to add code to limit the minimum UP/DOWN totals to zero and the maximum totals to 255 to prevent the variable values from under-flowing or over-flowing and/or you may want to add code to keep track of the running numerical difference between “up” and “down” events.

Up and down events are not generated and the UP/DOWN totals are left unchanged if the current port value (VALUE) is determined to be the same as the port value on the previous pass (PREVAL).

This is a “polled” approach (no interrupts) and it assumes that the main-loop-time is short enough to catch the encoder in motion. In principal it may not matter much if some of the events are missed so long as the User has some form of feedback like the volume level changing, changing menu items, etc. to guide his/her actions while using the “control”. In an application where I currently use an “up” switch, a “down” switch and an “enter” switch (and where I may want to use an encoder instead) things are pretty simple in that I jump out of the main loop and into a control-only loop for User input - then back out into the main loop after User adjustments have been made.

Note that whether the numerical sequence is a CW or a CCW sequence, the direction can be determined simply by looking at the value of PREVAL when and only when VALUE = 0. For CW rotation that would be PREVAL = 2 and for CCW rotation that would be PREVAL = 1. For any other values of VALUE or when VALUE = PREVAL (nothing has changed), I think you should be able to leave the encoder loop and go do things in the main loop for awhile (that is if VALUE = 1, 2, or 3, I don’t think that you need to stay in the encoder loop until a sequence has completed to be able to jump back into the main loop – I may be wrong about that).

Well, here goes. I think this will work - hope you can make sense and use of it (I tried to indent to make it clearer but the indents were gone when I previewed the post). If I actually get this translated into Flowcode and running I’ll report the results. Comments are in ().

Create variables:
ELOOP (encoder loop control, variable tested at end of encoder loop to exit)
UP (cumulative number of “up” events)
DOWN (cumulative number of “down” events)
VALUE (the BCD value of port x, bits 0 and 1)
TEMPVAL (temporary value)
PREVAL (previous value)
(Connect encoder channel A output to portx, bit 0. In Flowcode, attach switch to portx,0)
(Connect encoder channel B output to portx, bit 1. In Flowcode, attach switch to portx,1)
(Make VALUE the value of Port x, b0 and b1. In Flowcode, read the two-bit value of portx and return the variable VALUE)

Start
(Initialize UP, DOWN and PREVAL)
UP = 0
DOWN = 0
PREVAL = 0
(Enter main loop)
Loop while 1 = 1
(Enter encoder loop)
ELOOP = 0 (Re-zero ELOOP each time through the encoder loop)
(Enter de-bounce loop)
Read portx (update VALUE)
TEMPVAL = VALUE
Delay (try 20 ms)
Read portx (update VALUE)
Loop while VALUE <> TEMPVAL (exit de-bounce loop when VALUE = TEMPVAL)
(End of de-bounce loop. Either loop again or exit to encoder loop)
(Re-enter encoder loop)
VALUE = PREVAL? (Has the encoder moved since the last time through the encoder loop? Remember, the first time through PREVAL will have been arbitrarily preset to 0)
Yes
ELOOP = 1 (Encoder hasn’t moved. Skip everything and exit to the main loop. Structure your test “yes” branch this way in Flowcode by “nesting” other tests or instructions under the “no” branch of this test)
No (Continue)
VALUE = 0?
Yes
PREVAL = 1?
Yes
DOWN = DOWN + 1 (Do something now in response to a “down” event or check the value of DOWN later and decide whether or not to do something then)
ELOOP = 1
No (Continue)
PREVAL = 2?
Yes
UP = UP + 1 (Do something now in response to an “up” event or check the value of UP later and decide whether or not to do something then)
ELOOP = 1
No (Continue)
No (Continue)
PREVAL = VALUE
ELOOP = 1
Loop while ELOOP = 0 (Exit encoder loop if ELOOP is anything other than 0)
(End of encoder loop. Either loop again or exit to main loop)
(Re-inter main loop)
(Do other stuff you may want to do within the main loop before returning to the top of the main loop)
End (never!)

jimhumphries
Posts: 112
Joined: Wed Oct 12, 2005 6:29 pm
Location: USA
Been thanked: 1 time
Contact:

Postby jimhumphries » Wed Feb 15, 2006 4:10 am

Hey - I'm testing this thing and it's a dud. Don't waste time on it yet. When I finish testing and it's running (for real), I'll post the corrected pseudo-code.

Jim

jimhumphries
Posts: 112
Joined: Wed Oct 12, 2005 6:29 pm
Location: USA
Been thanked: 1 time
Contact:

Postby jimhumphries » Wed Feb 15, 2006 9:30 pm

OK, it works (I had some fun with it last night).

I have to tell you that getting it into Flowcode made it much easier to look at and edit. If anyone is interested in the actual code, send me an Email and I will reply with the Flocode file attached (it’s very sparse).

After working with the actual code and the actual encoder I can suggest three changes:

Don’t use a 24 cycle/revolution encoder - it’s too darn fast (this is why I thought the approach was a dud). When I used the ECW1DB24BC0024 encoder I wasn’t able to support (even simple) other tasks within the main loop without missing a lot of up/down events (and I’m running at 20 MHz). Use a 6 or 12 cycle/revolution encoder. I tried a Bourns 3315-006 and it worked great with LCD routines also running in the main loop. I don’t think it ever missed a beat.

Drop the UP and DOWN variables in favor of a single variable - NUMBER. I did this to display the difference between up and down events on the LCD and it was easier to deal with and cleaner, code-wise.

Drop the encoder loop and run the encoder code in-line directly within the main loop (the encoder loop is redundant). You can also drop the variable ELOOP and any reference to it within the code.

Here is the cleaned up pseudo-code with the changes:

Create variables:
NUMBER (the difference between up events and down events)
VALUE (the BCD value of port x, bits 0 and 1)
TEMPVAL (temporary value)
PREVAL (previous value)

Start
NUMBER = 0
PREVAL = 0
(Enter main loop)
Loop while 1 = 1
(Enter de-bounce loop)
Read portx (update VALUE)
TEMPVAL = VALUE
Delay (try 10 ms)
Read portx (update VALUE)
Loop while VALUE <> TEMPVAL (exit de-bounce loop when VALUE = TEMPVAL)
(End of de-bounce loop. Either loop again or exit to main loop)
(Re-enter main loop)
VALUE = 0?
Yes
PREVAL = 1?
Yes
NUMBER = NUMBER - 1 (Do something now in response to a “down” event or check the value of NUMBER later and decide whether or not to do something then)
No (Continue)
PREVAL = 2?
Yes
NUMBER = NUMBER + 1 (Do something now in response to an “up” event or check the value of NUMBER later and decide whether or not to do something then)
No (Continue)
No (Continue)
PREVAL = VALUE
(Do other stuff you may want to do within the main loop before returning to the top of the main loop)
End (never!)

Promitheus
Posts: 3
Joined: Mon Feb 06, 2006 10:35 am
Contact:

Postby Promitheus » Wed Feb 15, 2006 10:24 pm

hey that looks great!
thanks for the info.