PropBASIC routine for quadrature encoder reading....FAST and worked first time! :)
Mickster
Posts: 2,698
Posted this a while ago in another quadrature encoder thread as an alternative to using pure PASM.
Well I just got around to testing it and it required no debug at all (a FIRST for me)!!!
From what I can tell of the generated PASM code, this method appears to be using less than 10 instructions at any time.
Regards,
Mickster
Well I just got around to testing it and it required no debug at all (a FIRST for me)!!!
From what I can tell of the generated PASM code, this method appears to be using less than 10 instructions at any time.
DEVICE P8X32A, XTAL1, PLL16X FREQ 80_000_000 Chan_A PIN 0 INPUT Chan_B PIN 1 INPUT Chan_Z PIN 2 INPUT Counter VAR LONG = 0 Idx_Monitor VAR LONG = 0 Idx_Count VAR LONG = 0 Count_Error VAR LONG = 0 PROGRAM Start Start: Watch Counter ' This is for ViewPort 'Decide where to start If Chan_A = 1 And Chan_B = 1 Then Goto A1B1 Endif If Chan_A = 0 And Chan_B = 0 Then Goto A0B0 Endif If Chan_A = 1 And Chan_B = 0 Then Goto A1B0 Endif If Chan_A = 0 And Chan_B = 1 Then Goto A0B1 Endif 'Should keep hopping between these labels unless an illegal 'condition crops up. A1B1: If Chan_A = 0 Then Dec Counter Goto A0B1 Elseif Chan_B = 0 Then Inc Counter Goto A1B0 Endif Goto A1B1 A0B0: If Chan_A = 1 Then Dec Counter Goto A1B0 Elseif Chan_B = 1 Then Inc Counter Goto A0B1 Endif Goto A0B0 A1B0: If Chan_A = 0 Then Inc Counter Goto A0B0 Elseif Chan_B = 1 Then Dec Counter Goto A1B1 Endif Goto A1B0 A0B1: If Chan_A = 1 Then Inc Counter Goto A1B1 Elseif Chan_B = 0 Then Dec Counter Goto A0B0 Endif Goto A0B1 End
Regards,
Mickster
Comments
Hopefully soon I will find time for quadrature play, and now here is a great starting point.
Another cool trick, assuming the application involves full rotations of the encoder, is to employ the index pulse as a means of checking the integrity of the count. The differnce between one "Idx_Count", below and the next, should always be a multiple of the encoder's quadrature count resolution (2000 in my case). Typically the index pulse goes low when ChA and ChB are low, so:
Cheers.
Mickster
I may still add a few lines to monitor for switch presses and set a hub variable.
Disclaimer: Have yet to try FlexBASIC though (time constraints)
I don't know it there is a case in BASIC
But where is Heater???
He would have a fit!!!
all those goto's -argh!
call yourselves a programmers....
Dave
The thing is that; the goto translates directly to a PASM jmp.
My objective was to see how few clock cycles I could get away with.
Yes, BASIC has case but the above SPIN example, even if it was written in 'c' uses too many clock cycles (for me).
And how consice the spin version. Would love to see the clock counts of all of these versions compared.
Client: Hey, this machine is way too slow...this production rate is gonna kill me!
Me: Yeah, I know but the code is really pretty.
However, I experienced intolerable failures. Counting would go the wrong way about 10% of the time due to switch noise. My rest of my code relied on the encoder coming to rest in the detent position (1,1), but sometimes the encoder did not.
My original application was just tuning an antique-style radio. So, having to fiddle with the knob to get it to tune is a real touch of authenticity. This wasn't a feature that I was hoping for in future applications.
Oh absolutely. It might seem a ridiculous waste to dedicate a cog to a single axis but I really do have many hundreds of 6,000 RPM motors out there with 4096 line (16384 quad count) encoders.
At some point, these machines will require a new control system and so I have been experimenting with various possible solutions.
I have yet to experience the detented encoders but I have heard of glich/debouce issues, elsewhere. I need to grab some to have a play with
He already did have a fit.
A couple years ago I challenged him on four lines of BASIC quadrature code. He turned it into a page of GOTO-less C that ran twice as low.
But my hilarious favorite has always been this one: The 'Jeopardy' switch. Basically, if one contestant hits the button first, it has to lock out the other contestant's buttons.
This could be done with 2 to 4 logic gates, or four lines of BASIC. Instead, someone tried to do it in 1.5 pages of Blockly, and I think STILL COULDN'T GET IT TO WORK:
https://forums.parallax.com/discussion/168171/jeopardy-style-game-control
I have a pile of the encoders (CS-CO043), but it would have been easier to use the KY-040 modules that are readily available. When Goldmine Electronics had some encoders that appear to be Alps EC11E, I loaded up on more. I ended up with a lifetime supply of encoders (and laid out 2 PCBs to play with them).
There are opportunities to optimize the TASK for my purpose - perhaps some version of Tracy Allen's boolean example that frees up the cog to also monitor switch state. For HMI applications, I would struggle to get more than 25 detent clicks (100 state changes) in a second. So, checking the switch, updating hub variables, etc. could certainly be done even with LMM code in a TASK.
Something like this could be added to what you have(?)
Edit: Even using LMM, we are still looking at a worst-case of four million instructions/second, right?
Hi Frank. This is pretty much what's happening at any one time. I don't have my PASM reference
but I believe that we need to allow 22 clocks for the hub write(?)
Jeff Martin's Quadrature Encoder.spin (pasm cog) uses the boolean logic method, extended to up to 16 encoders in parallel.
Indeed!
This is a very nice piece of work and I have a project in mind for it. The only downside to using it with one or two encoders is that it has a fixed overhead of 150 clocks.