My rotary encoder adventures


+ Reply to Thread
Results 1 to 17 of 17

Hybrid View

  1. #1
    Join Date
    Jan 2005
    Location
    Montreal, Quebec, Canada
    Posts
    3,154


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    Henrik, inspired by your code. I got down to 6.4 - 8.6us:

    Goes in initialization section:

    Code:
        Enc1_previous = %11111111
        Enc1_Current = %00000000
        Enc1_counter = 0
    MainLoop:

    Code:
    MyLogic:
    
        Enc1_Current = (Enc1_WiperA << 1) + Enc1_WiperB
    
        IF Enc1_Current != Enc1_Previous THEN
            IF Enc1_Current = %00000011 THEN
                IF Enc1_Previous = %00000010 THEN
                    Enc1_counter = Enc1_counter + 1
                ELSE
                    IF Enc1_Previous = %00000001 THEN
                        Enc1_counter = Enc1_counter - 1
                    ENDIF
                ENDIF
            ELSE
                IF Enc1_Current = %00000000 THEN
                    IF Enc1_Previous = %00000001 THEN
                        Enc1_counter = Enc1_counter + 1
                    ELSE
                        IF Enc1_Previous = %00000010 THEN
                            Enc1_counter = Enc1_counter - 1
                        ENDIF
                    ENDIF
                ENDIF
            ENDIF
        ENDIF
        
        Enc1_Previous = Enc1_Current
    
        BlinkLED1 = 0                       ' Bottom of IFs on Logic 2 probe
    
        GOSUB LCDoutput
        
        goto mainloop

    Since my encoder doesn't stop on 01 or 10, I only need to check 11 and 00. Already 3 times faster than my original.


    EDIT: Updated times

    Name:  Encoder probe f.png
Views: 1792
Size:  104.6 KB
    Last edited by Demon; - 20th August 2024 at 01:36.
    My Creality Ender 3 S1 Plus is a giant paperweight that can't even be used as a boat anchor, cause I'd be fined for polluting our waterways with electronic devices.

    Not as dumb as yesterday, but stupider than tomorrow!

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    I use that code with an optical encoder to convert from quartature to up/down pulses and it tracks the encoder perfectly to >200k edges per second. I modified it to incorporate your counter but I might have messed something up.

    Since my encoder doesn't stop on 01 or 10, I only need to check 11 and 00. Already 3 times faster than my original.
    It might not have a detent at every quadrature state but it sure must "go thru" them.
    If you are at 00 and go to 11, which direction did it turn? There's no way to know unless also decoding the 10/01 states in between the detents - and you are doing that.

    Also, don't forget that your LCDoutput subroutine takes considerable amount of time, you can not allow the encoder to pass thru two (or more) states without reading it or it WILL miss pulses or even count backwards.

    Take your logic analyzer capture and measure the time between the rising edges of channel A and B respectively.
    The pulsewidth of channel A is 11ms but the time between the edges on A and B is much shorter than 5.5ms due to the fact that the phase shift is far from 90° on your encoder. Lets say it's 2ms... How long does your LCDoutput subroutine take?

  3. #3
    Join Date
    Jan 2005
    Location
    Montreal, Quebec, Canada
    Posts
    3,154


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    I use that code with an optical encoder to convert from quartature to up/down pulses and it tracks the encoder perfectly to >200k edges per second.
    Yeah, that's what I thought. We're not using the exact same device. I noticed such irregularities when I was switching between my own encoders (2 different batches).


    It might not have a detent at every quadrature state but it sure must "go thru" them.
    Oh definitely. I even see them display on the LCD when I turn my encoder REAL slow.


    If you are at 00 and go to 11, which direction did it turn? There's no way to know unless also decoding the 10/01 states in between the detents - and you are doing that.
    Yup, that's why I check the Current state against the Previous state. I only increase/decrease my counter on 00 and 11, cause that's where the encoder has a physical detent. A user turning the knob doesn't care about intermediate steps; only that the device actuates by one position when the knob goes click.


    Take your logic analyzer capture and measure the time between the rising edges of channel A and B respectively.
    The pulsewidth of channel A is 11ms but the time between the edges on A and B is much shorter than 5.5ms due to the fact that the phase shift is far from 90° on your encoder. Lets say it's 2ms...
    The fastest interval between wiper A and B is on a drop, and it's 3.88ms


    How long does your LCDoutput subroutine take?
    ~1.92ms


    Note that the final product will use a dedicated PIC to display data on LCDs, and a separate PIC to process incoming encoder signals.

    I'm only using the LCD alongside the encoder to help me understand how the encoder is behaving.
    My Creality Ender 3 S1 Plus is a giant paperweight that can't even be used as a boat anchor, cause I'd be fined for polluting our waterways with electronic devices.

    Not as dumb as yesterday, but stupider than tomorrow!

  4. #4
    Join Date
    Jan 2005
    Location
    Montreal, Quebec, Canada
    Posts
    3,154


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    It might not have a detent at every quadrature state but it sure must "go thru" them.
    Oh definitely. I even see them display on the LCD when I turn my encoder REAL slow.

    That's why I had put this comment in my code, to show the CW/CCW progression through the wiper states:

    Code:
    '  Wiper Chart:
    '  ============
    '     A   B
    '    --- ---
    '     0   0
    '     1   0  /\ CCW
    '     1   1
    '     0   1  \/ CW
    '     0   0
    '
    ' Careful, EC11 30 detents 15 pulses will move from 00 to 11
    '          EC11 20 detents can move from 00 back to 00 in one click

    No wonder my older EC11 were causing me so much grief in my initial testing.
    My Creality Ender 3 S1 Plus is a giant paperweight that can't even be used as a boat anchor, cause I'd be fined for polluting our waterways with electronic devices.

    Not as dumb as yesterday, but stupider than tomorrow!

  5. #5
    Join Date
    Jan 2005
    Location
    Montreal, Quebec, Canada
    Posts
    3,154


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    Here's one of my faster ones:

    A is 15.22ms duration
    Difference between rise of A and B is 3.50ms
    I nearly had time to send LCDOUT twice.

    Name:  Encoder probe g.png
Views: 1158
Size:  73.1 KB


    I'm more than satisfied with what I have so far as encoder logic. When I remove LCDOUT, this is how many times the encoder logic can cycle during a fast pulse; a gazillion.

    Name:  Encoder probe h.png
Views: 1257
Size:  41.1 KB


    I'm thrilled actually; with a big smile on my face as I type this.
    My Creality Ender 3 S1 Plus is a giant paperweight that can't even be used as a boat anchor, cause I'd be fined for polluting our waterways with electronic devices.

    Not as dumb as yesterday, but stupider than tomorrow!

  6. #6
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    Very good, then there's plenty of margin.
    Next challenge: Velocity sensing, ie a way to detect that the user wants the value to change by a lot and not have to turn the knob 600 turns. Getting that just right seems to be tricky, even the big boys don't always... (I've never tried).

    How will you transfer the count from one PIC to the other? Keep track of your timing, you might be able to do it all with a single PIC. If needed, divide the LCDOutput routine in two (or more) parts if needed.

  7. #7
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,132


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    You can experiment with

    DEFINE LCD_COMMANDUS 2500

    And

    DEFINE LCD_DATAUS 50

    parameters in order to match your LCD module. Maybe you are lucky and have a faster one. But be carefull as these might not work with all modules.

    The Velocity sensing is a really good one. Indeed, if the user has to to change values in a broad range it is very handy. Maybe if Timer is involved can make things simpler.

    Ioannis
    Last edited by Ioannis; - 21st August 2024 at 07:22.

  8. #8
    Join Date
    Jan 2005
    Location
    Montreal, Quebec, Canada
    Posts
    3,154


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    Quote Originally Posted by HenrikOlsson View Post
    Very good, then there's plenty of margin.
    Next challenge: Velocity sensing, ie a way to detect that the user wants the value to change by a lot and not have to turn the knob 600 turns. Getting that just right seems to be tricky, even the big boys don't always... (I've never tried). ...
    That's exactly why I started looking up Elapsed Timer last night. I already have an idea in mind; rotate the encoder at 3 speeds, record the time elapsed between pulses, and then use that to determine if I increment/decrement by ones, fives or tens. I figure with some tweaking I can generate a decent compromise.

    I've already adjusted my logic this morning to fall down to 359 when it goes below 0; to better simulate a heading gauge in flight sim, and inverse, flip up to 0 after moving up past 359.


    Quote Originally Posted by HenrikOlsson View Post
    ... How will you transfer the count from one PIC to the other? ...
    HSEROUT, that's why I had it in my early tests. It compares somewhat with LCDOUT timewise, maybe a tad slower.

    I have a lot of R&D to go on that subject (like protocol and such).


    Quote Originally Posted by HenrikOlsson View Post
    ... If needed, divide the LCDOutput routine in two (or more) parts if needed.
    Nah, I have a LOT of controls to manage. I'm putting encoders as priority on a PIC, then switches and pots separately (ADC probably takes forever in comparison), and 4 LCDs wherever I have room and time available.

    This is a preliminary layout; 3 enclosures: left, center and right . The right side has the most encoders with:

    - 4 dual encoders
    - 7 single encoders
    - 1 mouse wheel (essentially a single encoder)

    Those Custom Keys in the middle are just a reminder for a 4th optional enclosure at far left.

    Name:  Layout.png
Views: 1433
Size:  89.2 KB



    The thin red stripes are LED stripes; shielded towards the controls to simulate a red glow, like this:

    Name:  Cockpit 50pct.png
Views: 1460
Size:  726.5 KB
    My Creality Ender 3 S1 Plus is a giant paperweight that can't even be used as a boat anchor, cause I'd be fined for polluting our waterways with electronic devices.

    Not as dumb as yesterday, but stupider than tomorrow!

  9. #9
    Join Date
    Dec 2010
    Location
    Melbourne Australia
    Posts
    169


    Did you find this post helpful? Yes | No

    Default Re: My rotary encoder adventures

    Quote Originally Posted by HenrikOlsson View Post
    Very good, then there's plenty of margin.
    Next challenge: Velocity sensing, ie a way to detect that the user wants the value to change by a lot and not have to turn the knob 600 turns. Getting that just right seems to be tricky, even the big boys don't always... (I've never tried).
    I'm in the middle of a project requiring a rotary encoder to set a weight target for a loadcell. I plan on using Richard's graphical LCD driver for a dot matrix display (not superfast update refreshing), so I actually needed something like what you've described there Henrik. Using Demon's code, I twiddled it a bit to utilise (elapsed) Timer0 on an 18F26K22 to provide the screen refreshing. This is what I basically came up with (which I'm happy with):

    Code:
    'REMOVED ALL THE INIALIZATION STUFF FOR THIS PASTING
    
    Enc1_counter = 1000
    
    SETFONT FONT5x7
    'SETFONT bignum5
    LATC.4 = 0 'using a pic pin output as a temporary ground rail for the rotary encoder
    gosub grf_clr
    
    T0CON.7 = 1 'enable timer 0
    T0CON.6 = 0 'timer 0 in 16 bit mode
    T0CON.5 = 0 'timer 0 clock source = internal instruction clock
    'T0CON.4 
    T0CON.3 = 0 'timer prescaler assigned
    T0CON.2 = 0 ' prescaler assigned to 1:4
    T0CON.1 = 0 ' "
    T0CON.0 = 1 ' "
    
    Timer_Counter = 0
    Change = 0
    
    MainLoop:
        Timer_Counter.lowbyte = TMR0L
        Timer_Counter.highbyte = TMR0H    
        New_Encoder = (PortB.4 << 1) + PortB.5
    
        IF New_Encoder != Old_Encoder THEN
            IF New_Encoder = %00000011 THEN
                IF Old_Encoder = %00000010 THEN
                    Change = Change+1
                    Enc1_counter = Enc1_counter + Change 
                ELSE
                    IF Old_Encoder = %00000001 THEN
                        Change = Change+1
                        Enc1_counter = Enc1_counter - Change      
                    ENDIF
                ENDIF
            ELSE
                IF New_Encoder = %00000000 THEN
                    IF Old_Encoder = %00000001 THEN
                        Change = Change+1
                        Enc1_counter = Enc1_counter + Change  
                    ELSE
                        IF Old_Encoder = %00000010 THEN
                            Change = Change+1
                            Enc1_counter = Enc1_counter - Change    
                        ENDIF
                    ENDIF
                ENDIF
            ENDIF
        ENDIF
        
        if change >= 1 and Timer_Counter>60000 then
            TMR0H=0
            TMR0L=0 
            ARRAYWRITE BUFF,[sdec Enc1_counter,0]
            gosub grf_clr
            'DMDSTR 10,10, BUFFp,1
            DMDSTR 10,10, BUFF,1
            gosub show
            Change = 0
      else
            pause 5
        endif
        
        Old_Encoder = New_Encoder
    
    goto MainLoop:
    Troy
    Last edited by rocket_troy; - 4th October 2024 at 07:18.

Similar Threads

  1. Rotary encoder with DT interrupts
    By louislouis in forum mel PIC BASIC Pro
    Replies: 33
    Last Post: - 21st March 2021, 15:45
  2. Rotary encoder subroutine
    By Fanias in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 10th October 2018, 13:13
  3. Using an incremental rotary encoder?
    By keithv in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 12th January 2016, 22:23
  4. New approach to Rotary Encoder
    By Ioannis in forum Code Examples
    Replies: 90
    Last Post: - 11th July 2013, 21:05

Members who have read this thread : 11

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts