Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 03:37 26 Nov 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : My bounce-busting bullet proof Rotary Encoder code

Author Message
apalert
Newbie

Joined: 06/07/2023
Location: Australia
Posts: 15
Posted: 05:25am 03 Feb 2024
Copy link to clipboard 
Print this post

No pullups and no capacitors!

Peter Mather's RE code is fantastic, it just works. But I'm a newbie and can't understand it.

Mulling it over coffee I wondered if it could be simpler. Maybe only read the first pulse of switch noise, call it the data and ignore the rest using a flag, preset true but made false as soon as the first pulse of noise is received.

Maybe both inputs need a flag system. Maybe the interrupt on one resets the flag for the other. Put down my coffee and coded it up in minutes. And it worked...mostly. I did spend rather a lot of time tweaking polishing embellishing and commenting :)

One thing I learned while testing is that it's very easy to exceed the speed these rotary encoders can cope with which causes missed pulses.

The data sheet for my encoder gives maximum rotary speed of 100 rpm. It has 20 indents per full turn so that calculates down to 33 clicks per second, a bit over 1 1/2 turns, 30mS per click. You can easily exceed that in short bursts. I setup a timing loop and with a finger twirl on the knob for 1/4 turn some pulses were as low as 6mS apart, 5 times the maximum speed recommended. Little wonder it missed a few pulses!

One tweak was to grab the direction data on the first clock pin interrupt but not finalize it until the data pin interrupt. This means the user can overshoot 49% of the way to the next indent and back off without a miscount.  

Anyway, in case there is interest I'll attach the code:

'Code for rotary encoder interpretation by Malcolm Young
'Rotating the encoder prints incremental numbers as appropriate
' eg 0 1 2 3 4 3 2 1 0 -1 -2 etc as well as a direction flag
'in the form of 1 and -1. Developed on Picomite

OPTION ExPLICIT
OPTION DEFAULT NONE

dim float pre_action = 0 'temporarily holds data from new encoder movement
dim float dir_action = 0 'makes "public" the new directional data
dim float inc_action = 0 'makes "public" the new incremental data
dim float old_inc_action = 1 'used to decide if data has changed
dim float clock_enable = 1 'flag to control  clock pin interrupt process
dim float reset_enable = 0 'flag to control data pin interrupt process
dim float clk = 20 'use to name clock pin
dim float dat = 19 'use to name data pin

setpin clk, intl  , clock_interrupt,pullup 'clock pin (encoder pin a)
setpin dat, intb, reset_clock_enable,pullup 'data pin (encoder pin b)

print
print "inc_action", "dir_action"
do
 If inc_action <> old_inc_action then
   print inc_action,, dir_action
   'cls: text 96,60, str$(inc_action),RB,6          'LCD panel output
   old_inc_action = inc_action
 end if
loop

sub clock_interrupt
 if clock_enable = 1 then
   clock_enable=0 'prevents any further "noise" pulses being processed
   if pin(dat) = 1 then 'direction was clockwise
     pre_action = 1
   else                  'direction was counter-clockwise
     pre_action = -1
   endif
   reset_enable=1 'makes reset_clock_enable ready to accept data
 endif
end sub

sub reset_clock_enable
 if reset_enable = 1 then
   reset_enable = 0 'prevents any further "noise" pulses being processed
   if pin(clk) = 0 then 'prevents processing if RE position reverted to origin
      dir_action = pre_action            'directional output
      inc_action=inc_action + pre_action 'incremental output
   endif
   clock_enable = 1 'enables data pin again, even if reverted to origin
 endif  
end sub
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3194
Posted: 06:09am 03 Feb 2024
Copy link to clipboard 
Print this post

Well done!
That should go in the New Fruit of the Shed.

Geoff
Geoff Graham - http://geoffg.net
 
apalert
Newbie

Joined: 06/07/2023
Location: Australia
Posts: 15
Posted: 12:12pm 03 Feb 2024
Copy link to clipboard 
Print this post

  Geoffg said  Well done!
That should go in the New Fruit of the Shed.

Geoff


Thanks Geoff, happy for that to happen. Maybe edit out the jokey introduction and I'd be happy add a bit more about rotary encoder theory, a few diagrams perhaps.

Mal
 
PhenixRising
Guru

Joined: 07/11/2023
Location: United Kingdom
Posts: 858
Posted: 01:54pm 04 Feb 2024
Copy link to clipboard 
Print this post

Would be cool if one of our PIO wizards could figure out quad decode where MMBasic could read/set/reset the high-speed counter. The Python guys appear to have it.
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 6786
Posted: 04:37pm 04 Feb 2024
Copy link to clipboard 
Print this post

Do you mean the count inputs defined with OPTION COUNTER? Their operation is configured by SETPIN CIN?
They are inputs that count into variables, aren't they? Just zero the variable.

IIRC the RP2040 doesn't have any on-chip counters. It has timers, which can have various input sources.


EDIT:
Ah.... do you mean TIMER? You can just use TIMER=0 to reset that.
.
Edited 2024-02-05 02:53 by Mixtel90
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
PhenixRising
Guru

Joined: 07/11/2023
Location: United Kingdom
Posts: 858
Posted: 08:10pm 04 Feb 2024
Copy link to clipboard 
Print this post

Ah, maybe I shouldn't have used the word "counter". I was meaning a var.

Don't really understand how this stuff works.

Back in my DOS days, I was using Quickbasic (well, PDS 7.1).

I needed millisecond determinism that couldn't be interrupted.
I hijacked the clock interrupt and reprogrammed it to ~1ms (from 55ms).
I included code to compensate so that the clock maintained correct time.
Anyway, I was able to share variables with QB and as things changed in the (MASM) background task, the vars in Basic were updated.
So I am imagining a PIO quad decoder/counter that would simply update a variable that MMBasic has access to (?)
 
PhenixRising
Guru

Joined: 07/11/2023
Location: United Kingdom
Posts: 858
Posted: 08:10pm 04 Feb 2024
Copy link to clipboard 
Print this post

Duplicate
Edited 2024-02-05 06:12 by PhenixRising
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 6786
Posted: 11:04pm 04 Feb 2024
Copy link to clipboard 
Print this post

When you use a counter on the PicoMite:

OPTION COUNT countpin1 [,countpin2] [,countpin3] [,countpin4]
SETPIN GPx, CNT 'etc. for various options

to read it:
a = pin(GPx)

To zero it
pin(GPx) = 0
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
PhenixRising
Guru

Joined: 07/11/2023
Location: United Kingdom
Posts: 858
Posted: 12:49am 05 Feb 2024
Copy link to clipboard 
Print this post

Quad decode doesn't work with regular counters. How would you differentiate between up/down and how would you achieve X4 resolution.
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 6786
Posted: 09:40am 05 Feb 2024
Copy link to clipboard 
Print this post

The obvious way is to use interrupts. You can trigger on just a rising edge, just a falling edge or both.

If you are after *very* fast response from a rotary encoder then you need to reduce the resolution. For most purposes (turning an encoder by hand) interrupts are plenty fast enough.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
PhenixRising
Guru

Joined: 07/11/2023
Location: United Kingdom
Posts: 858
Posted: 08:04am 15 Mar 2024
Copy link to clipboard 
Print this post

MIKROE 1917




Sub zci 'zero count on index
 Pin(85)=0
 spi write 1,&h88
 spi write 1,&h63
 Pin(85)=1
end Sub
Sub nc 'normal quadrature count
 Pin(85)=0
 spi write 1,&h88
 spi write 1,&h43
 Pin(85)=1
end Sub
Sub lci 'load count on index
 Pin(85)=0
 spi write 1,&h88
 spi write 1,&h53
 Pin(85)=1
end Sub
Sub cc 'clear count
 Pin(85)=0
 spi write 1,&h20
 Pin(85)=1
end Sub
Sub es 'encoder status
 pin(85)=0
 spi write 1,&h70
 spi read 1,status()
 pin(85)=1
 print bin$(status(0))
end Sub
Sub clearnc_status
 pin(85)=0
 spi write 1,&h30
 pin(85)=1
end Sub
Sub read_OTR
 pin(85)=0
 spi write 1,&h68
 spi read 4,Indx_latched()
 pin(85)=1
end Sub
Sub tp() 'tell position
 pin(85)=0
 spi write 1,&h60
 spi read 4,psns()
 pin(85)=1
 apos=(psns(1)<<24) or (psns(2)<<16) or (psns(3)<<8) or psns(4)
 if apos and &h80000000 then inc apos, - &hffffffff
 print apos
 print hex$(apos)
end Sub
Sub tp64() 'tell position 64
 pin(85)=0
 spi write 1,&h60
 spi read 4,psns()
 pin(85)=1
 apos=(psns(1)<<24) or (psns(2)<<16) or (psns(3)<<8) or psns(4)
 print apos
 print hex$(apos)
end Sub
Sub dp(cntv) 'define position
 pin(85)=0
 spi write 1,&h98
 spi write 1,(&hff and cntv >> 24)
 spi write 1,(&hff and cntv >> 16)
 spi write 1,(&hff and cntv >> 8)
 spi write 1,(&hff and cntv)
 pin(85)=1
 pin(85)=0
 spi write 1,&he0
 pin(85)=1
end Sub
Sub lc(cntv)'load counter
 pin(85)=0
 spi write 1,&h98
 spi write 1,(&hff and cntv >> 24)
 spi write 1,(&hff and cntv >> 16)
 spi write 1,(&hff and cntv >> 8)
 spi write 1,(&hff and cntv)
 pin(85)=1
end Sub

 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024