Rotary encoder with DT interrupts


Closed Thread
Results 1 to 34 of 34

Hybrid View

  1. #1


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Cool, thanks. Both pbp,asm version works. Anyway, I tried two encoder types which I had on hand. Both works, but one count two counts to one detent, and the second count four to one detent.
    I tried set the IOCBP and IOCBN to trigger only on positive edge or only on negative edge or different comination but it doesn't hepl.
    Any trick to adjust this to one detent one count?

  2. #2
    Join Date
    May 2013
    Location
    australia
    Posts
    2,702


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    oneway to count detents divide the absolute raw cnt value by the number of edges/detent ,then restore the sign
    eg
    sb= cnt.15
    detents = abs(cnt)<<2; four edges
    if sb then detents= ~detents+1

    another is to just poll the rotation direction at an acceptable rate
    if clockwise add a count if anticlockwise subtract


    poll: ; call this sub say 5 times / sec or whatever
    if cnt>lastcnt then
    detent=detent+1
    elseif cnt<lastcnt
    detent=detent-1
    endif
    lastcnt=cnt
    return

    another way is to only inc/dec detent counter only when enca and encb both = 1 (ie at detent pos)
    in the re isr
    Warning I'm not a teacher

  3. #3


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Hi Richard, sorry for later response. Thanks for pointing me in to right way how to do it. Your first method not works for me, the second method polling works just fine but slows down the response time. The third method inc/dec detent counter only when enca and encb both = 1 works but count every second detent and also slowes down the reading.
    My encoder has 30.position and give 15.pulses/rew. My solution is simply divide the CNT by 2.
    Code:
    enc_isr:
    ev=ev<<2                ;shift last reading into position
    ev=ev|((portb&12)>>2)  ;read enc pins 2,3  mask off others then  combine this reading with last reading
    LOOKUP (ev&$f),[0,255, 1, 0, 1, 0, 0, 255, 255, 0, 0, 1, 0, 1, 255, 0],tmp ;lookup the decision matrix
    if tmp then             ; decide to inc , dec or ignore 
    	if tmp.1 then
    	  cnt=cnt+1
    	else
     	  cnt=cnt-1
    	endif
    endif
    detent=cnt
    detent=detent/2
    By the way, here is the nearly finished product where i used this solution and skills learned here.



    It's a stick welder controller with "advanced" functions like softstart, fan control, pulse welding, antistick, arcforce, hotstart, voltage and current measurement and so on.
    It's based on PIC16F1847, when I used sw multiplexing, multiple interrupts, direct register controls, mixed code ASM/PB and so on.


    Thanks for this great forum and helpful members, happy New Year to all.

  4. #4
    Join Date
    Jun 2005
    Location
    West Australia
    Posts
    116


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Hi Folks,

    I'm trying to get my head around what is happening with my attempt at using a Rotary Encoder... it is functional however something weird is happening periodically returning from the interrupt.

    My "I'm Alive" serial string is returned to and finds itself sprinkled among the debug terminal data. I'm sure it is staring at me but I can't see why. Any help appreciated.

    Thanks,
    Bill

    PS
    @ richard
    I persisted for hours trying your method (with appropriate pin changes) and had no joy so went with the Old vs New method. It would only count in one direction with either CW or CCW.

    Code:
    
    '****************************************************************************************************
    '*  Name    : RE test WJS.pbp                                                                       *                                      
    '*  Author  : WJ Sherwood                                                                           *
    '*  Notice  : Copyright (c) 2021  	                                                                *
    '*          : All Rights Reserved                                                                   *
    '*  Date    : 07/02/21                                                                              *
    '*  Device  : 16F1788                                                                               *
    '*  Version : 1    (PBP 3.0.10.4)                                                                   *
    '*  Notes   : Spurious "I'm Alive" serial traffic following RE action - what am I missing?          *
    '*          : REa portb.6, REb portb.5, REsw portb.4 all pulled up, active low.                     *
    '*          : 											                                            *
    '****************************************************************************************************
    '
    
    '=========================================================================================================
    '        CONFIGURE DEVICE 
    '=========================================================================================================
    #CONFIG ; 16F1788.
            __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON &  _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
            __config _CONFIG2, _WRT_OFF & _VCAPEN_OFF & _PLLEN_OFF & _LVP_OFF & _BORV_HI & _LPBOR_OFF
    #ENDCONFIG
    
    ' -----[ Initialization ]------------------------------------------------------------------------------------------------ 
        TRISA = %00000000       ' Set I/O.
        TRISB = %01111111       ' Set I/O.
        TRISC = %00000000       ' Set I/O.
    
    define  OSC  4
            OSCCON = %01101010   ' 4Mhz (F1788).
    'define  OSC  32
    '        OSCCON = %11110000   ; 32 MHz, 
    
        ANSELA = 0           ; all digital          
        ANSELB = 0           ; all digital 
    
    ' Define LCD connections       
        DEFINE  LCD_DREG        PORTA	' LCD Data Port
        DEFINE  LCD_DBIT        0		' Starting Data Bit
        DEFINE  LCD_RSREG       PORTA	' Register Select Port
        DEFINE  LCD_RSBIT       4		' Register Select Bit
        DEFINE  LCD_EREG        PORTA	' Enable Port
        DEFINE  LCD_EBIT        7		' Enable Bit
        DEFINE  LCD_BITS		4		' Data Bus Size
        DEFINE  LCD_LINES		2		' Number of Lines on LCD
    
    '=========================================================================================================
    '        PIN ASSIGNMENTS, SYSTEM CONSTANTS, TEMPORARY VARIABLES
    '=========================================================================================================
    ' Rotary Encoder stuff
    Old_Bits    VAR BYTE bank0  ' Encoder port bits before change.
    New_Bits    VAR BYTE bank0  ' Encoder port bits after change.
    RotEnc1_val VAR word bank0  ' Connected to PORTB<5:6>.
    MaxLimit    var word bank0  ' Used for setting upper limit for encoder counts.
    RotEncDir   VAR BIT  bank0  ' Direction of rotation bit.
    ButtPush    var bit  bank0  ' Flag shows button was pushed, allows quick exit from Int handler.
    
                        
        Include "MODEDEFS.BAS"      ' Include Shiftin/out modes.
        INCLUDE "DT_INTS-14.bas"    ' Needs to be assembled with MPASM **********
        INCLUDE "ReEnterPBP.bas"    ; Include if using PBP interrupts	
    
        OPTION_REG.6 = 0        ' INTEDG set to interrupt on falling edge.
    '    OPTION_REG.6 = 1        ' INTEDG set to interrupt on rising edge.
    
    '   IOCBP = %01110000        ; REa portb.6, REb portb.5  pos edge trigger
       IOCBN = %01110000        ; REa portb.6, REb portb.5, REsw portb.4  neg edge trigger - falling edge only.
       IOCBF = 0                ; Reset the PortB flag.
       INTCON = %11001000       ; GIE, PEIE, IOCIE.
       
    '    RotEnc1_val = 0         '
        pause 500               ' Let everything settle...
    
    'latc.6 = 0                  ' Prevent garbled serial - newer PICs, true.        
    latc.6 = 1                  ' Prevent garbled serial - newer PICs, inverted.        
    serout2 PORTC.6,16468,[13,10,"I'm Alive",13,10,10]
    
    ASM
    INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
            INT_Handler    IOC_INT,  _Rot_Encoder,   PBP,  yes  ; Newer PICs.
        endm
        INT_CREATE              ; Creates the interrupt processor .
    ENDASM
    
    @    INT_ENABLE   IOC_INT   ; Newer PICs.
    Old_Bits = PORTB & (%01100000)  ; RE uses B.6,B.5 - REa and REb.
    'Old_Bits = PORTB & (%01110000)  ; RE uses B.6,B.5,B.4 - includes RE push button.
    
    
    Main:   
    goto main                       ' endless loop waiting for INT. 
    
    
       
    '---[IOC - interrupt handler]---------------------------------------------------
    Rot_Encoder:
        if PortB.4 = 0 then             ' Check if Encoder pushbutton was pushed.
    serout2 PORTC.6,16468,[13,10,"ButtPush = 1, RE ",dec5 RotEnc1_val]
        ButtPush = 1                    ' Set the flag for a quick exit.
    goto DoneRotEnc                     ' Clean up and exit.
        endif
    
    ' Don't forget 4 counts per detent (Quadrature).
         New_Bits = PORTB & (%01110000)         ' Set port bits for Encoder's chosen A and B channels.
         IF (New_Bits & %01110000) = (Old_Bits & %01110000) then DoneRotEnc ' No change.
         RotEncDir = New_Bits.6 ^ Old_Bits.5    ' Bit XOR compare to get direction of rotation.
         if RotEncDir = 0 then                  ' CCW so decrement.
            if PORTB.6 and PORTB.5 = 1 then     ' Only when RE both pins high (convert quad counts to singles).
            RotEnc1_val = RotEnc1_val - 1       ' Decrement the count.
              if RotEnc1_val => 65530 then RotEnc1_val = 0  ' Limit the max.
              if RotEnc1_val <= 4 then RotEnc1_val = 0      ' Limit the min.
    serout2 PORTC.6,16468,[13,10,"RE_val ",dec5 RotEnc1_val]
            endif
         ELSE           ' RotEncDir = 1, CW so increment.
            if PORTB.6 and PORTB.5 = 1 then     ' Only when RE both pins high (convert quad counts to singles).
              RotEnc1_val = RotEnc1_val + 1     ' Increment the count.
              if RotEnc1_val >= MaxLimit then RotEnc1_val = MaxLimit ' Limit the count.
    serout2 PORTC.6,16468,[13,10,"RE_val ",dec5 RotEnc1_val]
            endif
         ENDIF
    
    
    DoneRotEnc:
         Old_Bits = New_Bits
        INTCON.0 = 0        ; Clean up and exit - clear IOCIF.
        IOCBF = 0           ; Reset the flag.
    @ INT_RETURN
    
    end

  5. #5
    Join Date
    May 2013
    Location
    australia
    Posts
    2,702


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    @ richard
    I persisted for hours trying your method (with appropriate pin changes) and had no joy
    all you have to do is post the code for your attempt and i will have a look


    hints

    serout2 PORTC.6,16468,[13,10,"RE_val ",dec5 RotEnc1_val] once in an isr is bad twice is just asking for trouble , use flags

    using a pin change int for a switch is a giant over kill
    Warning I'm not a teacher

  6. #6
    Join Date
    Jun 2005
    Location
    West Australia
    Posts
    116


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Hi Richard,

    Thanks for your help and guidance, as always.

    I took your hints and made appropriate adjustments (see below) but the rogue serial persists... With your preferred method I'd like to crack this existing problem before exploring your offer if that's okay.

    Stay safe,
    Bill

    Code:
    
    
    '****************************************************************************************************
    '*  Name    : RE test WJS.pbp                                                                       *                                      
    '*  Author  : WJ Sherwood                                                                           *
    '*  Notice  : Copyright (c) 2021  	                                                                *
    '*          : All Rights Reserved                                                                   *
    '*  Date    : 07/02/21                                                                              *
    '*  Device  : 16F1788                                                                               *
    '*  Version : 1    (PBP 3.0.10.4)                                                                   *
    '*  Notes   : Spurious "I'm Alive" serial traffic following RE action (still) and corrupt chars if  *
    '*          : Pause at line 75 (following MaxLimit = 60) removed - what am I missing?               *
    '*          : 											                                                                *
    '*          : REa portb.6, REb portb.5, REsw portb.4 all pulled up, active low.                     *
    '*          : 											                                                                *
    '****************************************************************************************************
    
    '=========================================================================================================
    '        CONFIGURE DEVICE 
    '=========================================================================================================
    #CONFIG ; 16F1788.
            __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON &  _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
            __config _CONFIG2, _WRT_OFF & _VCAPEN_OFF & _PLLEN_OFF & _LVP_OFF & _BORV_HI & _LPBOR_OFF
    #ENDCONFIG
    
    ' -----[ Initialization ]--------------------------------------------------------------------------------- 
        TRISA = %00000000       ' Set I/O.
        TRISB = %01111111       ' Set I/O.
        TRISC = %00000000       ' Set I/O.
    
    define  OSC  4
            OSCCON = %01101010   ' 4Mhz (F1788).
    'define  OSC  32
    '        OSCCON = %11110000   ; 32 MHz, 
    
        ANSELA = 0           ; all digital          
        ANSELB = 0           ; all digital 
    
    ' Define LCD connections       
        DEFINE  LCD_DREG        PORTA  ' LCD Data Port
        DEFINE  LCD_DBIT        0		   ' Starting Data Bit
        DEFINE  LCD_RSREG       PORTA  ' Register Select Port
        DEFINE  LCD_RSBIT       4		   ' Register Select Bit
        DEFINE  LCD_EREG        PORTA  ' Enable Port
        DEFINE  LCD_EBIT        7		   ' Enable Bit
        DEFINE  LCD_BITS		    4		   ' Data Bus Size
        DEFINE  LCD_LINES       2		   ' Number of Lines on LCD
    
    '=========================================================================================================
    '        PIN ASSIGNMENTS, SYSTEM CONSTANTS, TEMPORARY VARIABLES
    '=========================================================================================================
    ' Rotary Encoder stuff
    Old_Bits    VAR BYTE bank0  ' Encoder port bits before change.
    New_Bits    VAR BYTE bank0  ' Encoder port bits after change.
    RotEnc1_val VAR word bank0  ' Connected to PORTB<6:5>.
    MaxLimit    var word bank0  ' Used for setting upper limit for encoder counts.
    RotEncDir   VAR BIT  bank0  ' Direction of rotation bit.
    ButtPush    var bit  bank0  ' Flag shows button was pushed, allows quick exit from Int handler.
    REdec       var bit  bank0  ' Flag shows RE decrement, allows quick exit from Int handler.
    REinc       var bit  bank0  ' Flag shows RE increment, allows quick exit from Int handler.
                        
        Include "MODEDEFS.BAS"      ' Include Shiftin/out modes.
        INCLUDE "DT_INTS-14.bas"    ' Needs to be assembled with MPASM **********
        INCLUDE "ReEnterPBP.bas"    ; Include if using PBP interrupts	
    
        OPTION_REG.6 = 0        ' INTEDG set to interrupt on falling edge.
    '    OPTION_REG.6 = 1        ' INTEDG set to interrupt on rising edge.
    
    '   IOCBP = %01110000        ; REa portb.6, REb portb.5  pos edge trigger
       IOCBN = %01110000        ; REa portb.6, REb portb.5, REsw portb.4  neg edge trigger - falling edge only.
       IOCBF = 0                ; Reset the PortB flag.
       INTCON = %11001000       ; GIE, PEIE, IOCIE.
       
      MaxLimit = 60           ' Menu value limit.  
    '  pause 100               ' Let everything settle...
    
    latc.6 = 1                  ' Prevent garbled serial - newer PICs, inverted.        
    serout2 PORTC.6,16468,[13,10,"I'm Alive",13,10,10]
    
    ASM
    INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
            INT_Handler    IOC_INT,  _Rot_Encoder,   PBP,  yes  ; Newer PICs.
        endm
        INT_CREATE              ; Creates the interrupt processor .
    ENDASM
    
    @    INT_ENABLE   IOC_INT   ; Newer PICs.
    Old_Bits = PORTB & (%01100000)  ; RE uses B.6,B.5 - REa and REb.
    
    
    Main:   
      if PortB.4 = 0 then            ' Check if Encoder pushbutton was pushed.
      while PortB.4 = 0:wend         ' Wait for release.
      pause 50                       ' Debounce delay.
      serout2 PORTC.6,16468,[13,10,"ButtPush = 1, RE ",dec5 RotEnc1_val]
      endif
      
      if REdec or REinc = 1 then 
      serout2 PORTC.6,16468,[13,10,"RE_val ",dec5 RotEnc1_val]
      REdec = 0:REinc = 0           ' Reset the flags.  
      endif
      
    goto main                       ' endless loop waiting for INT. 
    
    
       
    '---[IOC - interrupt handler]---------------------------------------------------
    ' Don't forget 4 counts per detent (Quadrature).
    Rot_Encoder:
         New_Bits = PORTB & (%01100000)         ' Set port bits for Encoder's chosen A and B channels.
         IF (New_Bits & %01100000) = (Old_Bits & %01100000) then DoneRotEnc ' No change.
         RotEncDir = New_Bits.6 ^ Old_Bits.5    ' Bit XOR compare to get direction of rotation.
         if RotEncDir = 0 then                  ' CCW so decrement.
            if PORTB.6 and PORTB.5 = 1 then     ' Only when RE both pins high (convert quad counts to singles).
            RotEnc1_val = RotEnc1_val - 1       ' Decrement the count.
              if RotEnc1_val => 65530 then RotEnc1_val = 0  ' Limit the max.
              if RotEnc1_val <= 4 then RotEnc1_val = 0      ' Limit the min.
            REdec = 1                                       ' Flag the event.
            endif
         ELSE                                   ' RotEncDir = 1, CW so increment.
            if PORTB.6 and PORTB.5 = 1 then     ' Only when RE both pins high (convert quad counts to singles).
              RotEnc1_val = RotEnc1_val + 1     ' Increment the count.
              if RotEnc1_val >= MaxLimit then RotEnc1_val = MaxLimit ' Limit the count.
            REinc = 1                           ' Flag the event.
            endif                               
         ENDIF
    
    DoneRotEnc:
        Old_Bits = New_Bits
        INTCON.0 = 0        ; Clean up and exit - clear IOCIF.
        IOCBF = 0           ; Reset the flag.
    @ INT_RETURN
    
    end

  7. #7
    Join Date
    May 2013
    Location
    australia
    Posts
    2,702


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    if you look at the expected b5,b6 pin values at each interrupt
    for neg edge trigger only

    ints occur on orange lines
    Name:  re.jpg
Views: 1918
Size:  26.5 KB
    under ideal conditions you get for say cw rotation
    01,00,01,00,01............
    for ccw
    00,10,00,10,00............





    so for cw


    old = 01000000 new 00000000 or old = 00000000 new 01000000
    new.6 ^ old.5 =1 new.6 ^ old.5 = 0




    so for ccw


    old = 00100000 new 00000000 or old = 00000000 new 00100000
    new.6 ^ old.5 = 0 new.6 ^ old.5 = 1

    i don't see your logic decoding direction at all successfully
    Warning I'm not a teacher

Similar Threads

  1. Rotary encoder subroutine
    By Fanias in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 10th October 2018, 14:13
  2. Using an incremental rotary encoder?
    By keithv in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 12th January 2016, 23:23
  3. Instant Interrupts for rotary encoder
    By fnovau in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 15th August 2014, 09:24
  4. New approach to Rotary Encoder
    By Ioannis in forum Code Examples
    Replies: 90
    Last Post: - 11th July 2013, 22:05

Members who have read this thread : 2

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