Rotary encoder with DT interrupts


Closed Thread
Results 1 to 34 of 34
  1. #1

    Default Rotary encoder with DT interrupts

    Hi All,
    I'm struggling around rotary encoder with push button. I read the forum but not find any successfully solved example.
    Here is my code:
    Code:
    ; PIC16F1847                                 
    
    #CONFIG ; 16FF1847.
            __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _BOREN_OFF
            __config _CONFIG2, _PLLEN_OFF & _LVP_OFF
    #ENDCONFIG
    
    DEFINE OSC 32
    
    OSCCON = %11110000 ;32 MHz
     
    ANSELA = 0
    ANSELB = 0
    TRISA=%00000000
    TRISB=%00000011
    LATB = %00000011
    
    Include "modedefs.bas"
    INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
    INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts 
    
    INTCON=%10001000
    IOCBP=%00000000         
    IOCBN=%00000011         ;on change interrupt  NEGATIVE port RB.0, RB.1
    IOCBF=%00000011  
           
    wsave       VAR BYTE   $70 SYSTEM      ' alternate save location for W 
    
    enc_new     VAR BYTE   bank0
    enc_old     VAR BYTE   bank0
    enc_counter VAR word   bank0
    Flag        var BYTE   bank0
    
    asm
    INT_LIST  macro     ;IntSource,Label, Type, Resetflag?
            INT_Handler    IOC_INT, _enc,  asm,  yes
        endm
    INT_CREATE          ; Creates the interrupt processor
        ;================================================
    endasm
    ; Set variable value @ startup
    Flag =        0          
    enc_new =     0
    enc_old =     0
    enc_counter = 0           
    
    @ INT_ENABLE IOC_INT            ; enable external (INT) interrupts
    
    Main:
    if flag=1 then
    SEROUT portb.4,t9600,[#enc_counter,13]
    endif
     
    goto main
    
    enc:    
    asm    
        ;Read latest input from PORTB & put the value in _enc_new.
             MOVE?CB 1,_Flag
             movf    PORTB,W
             movwf  _enc_new
             ;Strip off all but the 2 MSBs in _enc_new.
             movlw    B'00000011'    ;Create bit mask (bits 1 & 0).
             andwf   _enc_new,F         ;Zero bits 5 thru 0.
             ;Determine the direction of the Rotary encoder.  
             rlf     _enc_old,F         ;left shift it into _enc_old to align bit 6 of 
                                    ;_enc_old with bit 7 of _enc_new.
             movf    _enc_new,W         ;Move the contents of _enc_new to W in order to XOR.
             xorwf   _enc_old,F        ;XOR previous inputs (in _enc_old) with latest
                                    ;inputs (in W) to determine CW or CCW.
     
             btfsc   _enc_old,0         ;Test bit 0 of result (in _enc_old).  Skip next line
                                 ;if it is 0 (direction is CCW).
             goto    Up            ;Bit is 1 (direction is CW).  Go around Down
                                 ;and increment counter.
    
    Down
             ;Decrements _enc_counter because the rotary encoder moved CCW.
        ;Decrements _enc_counter (16 bit value), sets Z on exit.
                  
            decf    _enc_counter,F      ; Decrement low byte
            incfsz  _enc_counter,W      ; Check for underflow
            incf    _enc_counter+1,F    ; Update
            decf    _enc_counter+1,F    ; Fixup
            movf    _enc_counter,W
            iorwf   _enc_counter+1,W    ; Set Z bit
            
        ;Add here code for the CCW LED if needed.
             
             goto    Continue          ;Branch around UP.
    Up
             ;Increments _enc_counter because the rotary encoder moved CW.
        ;Increments _enc_counter (16 bit value), sets Z on exit.
            incfsz  _enc_counter,W      ; Add one to low byte
            decf    _enc_counter+1,F    ; No carry (negates next step)
            incf    _enc_counter+1,F    ; Add one to high byte
            movwf   _enc_counter        ; Store updated low byte back.
            iorwf   _enc_counter+1,W    ; Set Z flag
            
        ;Add here code for the CW LED if needed.
        
    Continue 
             
             ;Assign the latest encoder inputs (in _enc_new) to _enc_old.
             movf     _enc_new,W
             movwf   _enc_old
             CHK?RP   IOCBF
             CLRF IOCBF
             INT_RETURN
        ;============ END OF THE ROTARY ENCODER CODE =====
    endasm
    The problem is, I can't get correct encoder reading. In serial monitor I can see the result but the values goes only to increment no matter if I rotate CW or CCW.
    The values increment randomly. I dont know, what is the problem.
    The encoder is wired with 10k pullups and debounce capacitors.
    I need quic response to rotation fot that I try to use this ASM and DT interrupts metod.

    Anyway If I tried another example with no ASM and Interrupts only for testing, the encoder works fine CW and CCW, increments, decrements by one just fine.

    Can someone check my code and correct me what Im doing wrong.
    Thanks.

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


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    for mechanical encoder with button i use something like this
    Attached Files Attached Files
    Warning I'm not a teacher

  3. #3


    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?

  4. #4
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    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

  5. #5


    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.

  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 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

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


    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

  8. #8
    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

  9. #9
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    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: 974
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

  10. #10
    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,

    I don't see where you're going with your comments, maybe I'm just thick.

    In any case the Int Handler does recognize CW and CCW correctly with every turn and RE_val does increment or decrement accordingly by 1 count per detent as needed - the only issue is these unwanted regular serial disturbances following RE action, including the push button. Speed of rotation isn't a factor with their appearance.

    Something else is going on also - if I insert a Clear statement as below the RE_val resets to 0 - as if the PIC is reinitializing following the RE action hence the "I'm Alive" serial traffic. Without the Clear the count remains as it was prior to the serial disturbance.

    Is there a chance you could breadboard a 16F1788 and confirm my findings?

    Thanks,
    Bill

    Code:
    '   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.
       
    clear                        ' Clear all vars.
     
      MaxLimit = 60             ' Menu value limit.  
    '  pause 100                 ' Let everything settle...
    
    serout2 PORTC.6,16468,[13,10,"I'm Alive",13,10,10]
    
    SAMPLE of terminal
    RE_val 00001
    RE_val 00002
    RE_val 00003
    ButtPush = 1, RE 00003
    RE_val 00004
    RE_val 00005
    RE_val 00006
    RE_val 00005
    RE_val 00000
    RE_val 00000
    ButtPush = 1, RE 00000
    RE_val 00001
    RE_val 00002
    RE_val 00003
    RE_val 00004
    RE_val 00005
    RE_val 00006
    RE_val 00007
    RE_val 00008
    RE_val 00009
    RE_val 00010
    RE_val 00011
    RE_val 00010
    RE_val 00009
    RE_val 00008
    RE_val 00007
    RE_val 00006
    RE_val 00005
    ButtPush = 1, RE 00005
    RE_val 00006
    RE_val 00007
    RE_val 00008
    I'm Alive
    
    
    RE_val 00001
    RE_val 00002
    RE_val 00003
    RE_val 00004

  11. #11
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Since the I'm alive output is outside of and before Main it looks to me as if the PIC is resetting and starting over. Try something like:
    Code:
    serout2 PORTC.6, 16468, [BIN8 STATUS, "  -  ", BIN8 PCON, 10,13]
    serout2 PORTC.6,16468,[13,10,"I'm Alive",13,10,10]
    What does it say when you power up and what does it say when you get that rouge output?

    /Henrik.

  12. #12
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    i breadboarded a 1788 and using the code as posted in reply 8 with one slight change in that serout2 is set to T9600 it
    1. fails to count properly as predicted
    2. shows no signs of resets occurring

    interestingly using an encoder with no filtering it gives the appearance of functioning
    curious , not sure what to think .

    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 = 000000       ' Set I/O.
        TRISB = 111111       ' Set I/O.
        TRISC = 000000       ' Set I/O.
    
    
    define  OSC  4
            OSCCON = 101010   ' 4Mhz (F1788).
    'define  OSC  32
    '        OSCCON = 110000   ; 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 = 110000        ; REa portb.6, REb portb.5  pos edge trigger
       IOCBN = 110000        ; REa portb.6, REb portb.5, REsw portb.4  neg edge trigger - falling edge only.
       IOCBF = 0                ; Reset the PortB flag.
       INTCON = 001000       ; 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,84,[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 & (100000)  ; 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,84,[13,10,"ButtPush = 1, RE ",dec5 RotEnc1_val]
      endif
      
      if REdec or REinc = 1 then 
      serout2 PORTC.6,84,[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 & (100000)         ' Set port bits for Encoder's chosen A and B channels.
         IF (New_Bits & 100000) = (Old_Bits & 100000) 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
    Last edited by richard; - 10th February 2021 at 01:22.
    Warning I'm not a teacher

  13. #13
    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 Henrik,

    Thanks for joining, your input is welcome.

    Inserting your code shows (terminal output):

    Code:
    00011001 - 01010100
    
    I'm Alive
    
    RE_val 00001
    RE_val 00002
    RE_val 00003
    RE_val 00004
    RE_val 00005
    RE_val 00006
    RE_val 00007
    RE_val 00008
    RE_val 00007
    RE_val 00006
    RE_val 00005
    ButtPush = 1, RE 00005
    RE_val 00006
    RE_val 00007
    RE_val 00008
    RE_val 00009
    00011001 - 01010100
    
    I'm Alive
    ... so no change from original states once the 'reset' occurs - if that is what it is (I'm still decyphering the data sheet).

    Any comments?

    Cheers,
    Bill

  14. #14
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    mine has been running for 4 hours now , nill resets
    Warning I'm not a teacher

  15. #15
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,793


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Try to disable the WDT and see if it resets.

    Ioannis

  16. #16
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    I was a little quick with that PCON thing, on startup set PCON = %00011111 then let the program run

    Code:
    serout2 PORTC.6, 16468, ["Power-on:", BIN8 STATUS, "  -  ", BIN8 PCON, 10,13]
    PCON = %00011111
    serout2 PORTC.6, 16468, ["Priming PCON:", BIN8 STATUS, "  -  ", BIN8 PCON, 10,13]
    serout2 PORTC.6,16468,[13,10,"I'm Alive",13,10,10]

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


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Thanks for your help guys,

    @ Ioannis
    Disabling the WDT was one of the first things I tried, no change.

    @ Henrik
    Please see terminal capture below after including your suggested debug code...


    Code:
    Power-on: 00011001  -  00010110
    Priming PCON: 00011001  -  00011111
    
    I'm Alive
    
    RE_val 00000
    RE_val 00001
    RE_val 00002Power-on: 00011001  -  01011111
    Priming PC9é 00011001  -  00011111
    
    I'm Alive
    
    RE_val 00001
    Bit 6 of PCON changed - WTF is a stack underflow? Masking the problem, I know - but I added '& _STVREN_OFF' to _CONFIG2 to see if there was a difference and the results are below.

    Code:
    Power-on: 00011001  -  00010110
    Priming PCON: 00011001  -  00011111
    
    I'm Alive
    
    RE_val 00001
    RE_val 00002
    RE_val 00003
    RE_val 00004
    RE_val 00005
    RE_val 00006
    RE_val 00007
    RE_val 00008
    RE_val 00009
    RE_val 00010Power-oîé 00011001  -  11011111
    Priming PCON: 00011001  -  11011111
    
    I'm Alive
    
    RE_val 00000
    RE_val 00000
    RE_val 00001
    RE_val 00002
    RE_val 00003Power-on: 00011001 €-  110111ˆR
    Primin?PCON: 00011001  -  11011111
    
    I'm Alive
    So it looks like there is now a Stack overflow and underflow if I'm reading the data sheet correctly - how can this happen with STVREN off? Or have I lost the plot?

    I'm floundering.

    Cheers,
    Bill

  18. #18
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    one thing you can eliminate is a code problem [assuming code as posted] mine is has run for 24 hours+ without resetting

    describe your setup including whether you leave the programmer attached when testing
    Warning I'm not a teacher

  19. #19
    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,

    I made a general purpose pcb a while ago for dil28 PICs that has breakouts for each pin and a 'shield' that sits over it for ease of changing displays (Nokia, 16x2, GLCD, etc). It has LED's via jumpers, +5 or +3v3 selection and a RE on there as well, I tried to make it as universal as possible and it's been a workhorse for a lot of testing in the past. There is also a slide switch that is program/run for ease of ICSP and isolation when done.

    To eliminate any possibility of the pcb being the problem I changed to a breadboard and used my other flying lead program/run slide switch arrangement to the breadboard. Same results. Only thing I haven't tried yet is a different 1788 which I know I have somewhere but it is eluding me but I'll look up the specs and see if there is a close family member I can use in the meantime. I don't have to use the 1788 so will also explore other dil28 chips I have to get a good end result.

    I'll get back to you when I have something.

    Cheers,
    Bill

  20. #20
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    the reason i ask is that if your programmer is still connected and the programmer is used to power your proto board .
    some leave the icspclk pin on the programmer as a high output , if your RE tries to drag B.6 low the power stability will suffer giving all sorts of problems
    imho using any of the icsp pins while prototyping makes life difficult
    Warning I'm not a teacher

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


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Well, I found and tried another (new) 1788 but no difference. Fully isolating the programming cable and interface also made no difference, the fault persists.

    I then went to a 16F886 and made appropriate changes - works without 'resets' (with programming cable and interface attached as normal) and only some rare serial corruption but maintaining its RE count still, both CW and CCW. This tells me my hardware test setup is not at fault and the code is basically correct. So is there an issue with 16F1788's? Richard's setup hasn't identified any so I'm mystified. Below is what current code is:

    Code:
    
    '****************************************************************************************************
    '*  Name    : RE test WJS.pbp                                                                       *                                      
    '*  Author  : WJ Sherwood                                                                           *
    '*  Notice  : Copyright (c) 2021  	                                                                *
    '*          : All Rights Reserved                                                                   *
    '*  Date    : 07/02/21                                                                              *
    '*  Device  : 16F1788  [tests using 16F886 (and appropriate Reg changes) works correctly.]          *
    '*  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 ;& _STVREN_OFF
    #ENDCONFIG
    
    '' What happens with a different PIC?
    '#CONFIG ; F886 
    '    __config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_ON & _LVP_OFF & _CP_OFF
    '#ENDCONFIG
    
    ' -----[ Initialization F1788]--------------------------------------------------------------------------------- 
        TRISA = %00000000       ' Set I/O.
    '    TRISB = %01111111       ' Set I/O.
        TRISB = %01110000       ' Set I/O.  Only RE bits set as inputs.
        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 
    ' -------------------------------------------------------------------------------------------------------------- 
    
    '' -----[ Initialization F866]----------------------------------------------------------------------------------------------- 
    '    CM1CON0 = 0         	' Comparators off.
    '    ANSEL = %00000000       ' Make PortA AN0-AN7 digital.
    ''    ANSEL = %00000011       ' All digital except An0 and An1.
    '    TRISA = %00000000       ' Set I/O.
    
    '    CM2CON0 = 0         	' Comparators off.
    '    ANSELH = 0              ' Make PortB AN8-AN13 digital.
    
    '' PortB Int-On-Change: 1 = Int enabled. 0 = Int disabled.
    '    IOCB.0 = 0              ' No.
    '    IOCB.4 = 1              ' Yes, encoder pushbutton.
    '    IOCB.5 = 1              ' Yes, encoder Channel A.
    '    IOCB.6 = 1              ' Yes, encoder Channel B.
    '    IOCB.7 = 0              ' No.
    
    '    TRISB = %01110000       ' 4-6 encoder inputs.
    '    CCP1CON = %00000000     '
    
    '    TRISC = %00000000       ' Set I/O.
        
    ''    ADCON0 = %11001000      ' Set A/D to Frc, Channel 3, On (F88).                   
    '    ADCON0 = 0              ' Disable A/D.
    '    ADCON1 = %00000110      ' All digital.
    ''    ADCON1 = %10000000      ' R justify (where the 6 MSB of ADRESH read as 0 i.e. 10 bit), Vdd for Vref.
    
    '	Define 	OSC    4        ' Set Operating Frequency
    '    OSCCON = %01100000      ' 4Mhz (F886).
    
    ''    Define 	OSC    8        ' 
    ''    OSCCON = %01110000      ' 8Mhz (F886).
    
    '    INTCON = %10001000      ' Port B int on change and global interrupt enable. 
    
    '    clear                           ' ****** Clear statement must be before the INC file.******
    
    'wsave   VAR BYTE $70    SYSTEM      ' alternate save location for W 
    '' -------------------------------------------------------------------------------------------------------------- 
    
    ' 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.
    
    'Temp        var byte        ' Used for Int clearing by reading PortB. F886
                        
        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.
    
    ' ----- F1788 -------------------------------------------------------------------------------------------------- 
    '   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.
    ' -------------------------------------------------------------------------------------------------------------- 
       
    clear                        ' Clear all vars.
       
      MaxLimit = 60           ' Menu value limit.  
    '  pause 100               ' Let everything settle...
    
    serout2 PORTC.6, 16468, ["Power-on: ",BIN8 STATUS, "  -  ",BIN8 PCON,10,13]   ' thanks to Henrik.
    PCON = %00011111
    serout2 PORTC.6,16468,["Priming PCON: ",BIN8 STATUS,"  -  ",BIN8 PCON,10,13]
    serout2 PORTC.6,16468,[13,10,"I'm Alive",13,10,10]
    
    ' ----- F1788 -------------------------------------------------------------------------------------------------- 
    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.
    ' -------------------------------------------------------------------------------------------------------------- 
    
    '' ----- F886 --------------------------------------------------------------------------------------------------- 
    'ASM
    'INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
    '        INT_Handler    RBC_INT,  _Rot_Encoder,   PBP,  yes
    '    endm
    '    INT_CREATE               ; Creates the interrupt processor
    'ENDASM
    
    '@    INT_ENABLE   RBC_INT     ; RB Port Change Interrupt
    '' -------------------------------------------------------------------------------------------------------------- 
    
    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]
    'serout2 PORTC.6,16468,[13,10,BIN8 STATUS," - ",BIN8 PCON,10,13]   ' thanks to Henrik.
      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. F1788
        IOCBF = 0           ; Reset the flag. F1788
    '    Temp = PORTB        ' Read PortB to clear the Int (F886).
    @ INT_RETURN
    
    end
    Next up I'm going to try a 16F1938 (and maybe some 18F's) but out of time now and it will have to wait for the weekend. While I can use the F886 for this project it gives me no confidence to use F1788's for Int duties in future until sorted.

    Cheers,
    Bill

  22. #22
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    A STACK Underflow condition is caused by more RETURNs than CALLs (GOSUBs). I have a suggestion; in your ISR Rot_Encoder: change
    Code:
    IF (New_Bits & 100000) = (Old_Bits & 100000) then DoneRotEnc ' No change.
    to
    Code:
    IF (New_Bits & 100000) = (Old_Bits & 100000) then 
    @ GOTO DoneRotEnc ; No change.
    ENDIF

  23. #23
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,793


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Mike, why your suggestion is not the same?

    Ioannis

  24. #24
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Louis stated there was a STACK Underflow flag set in the PCON Register. I looked over his/her posted code and the only place I could find where a CALL/RETURN mis-match could occur was in the posted line of code. By specifying a "GOTO" there, the Stack would not be modified with a RETURN PC Address. I suggested a test to eliminate the possibility of the STACK Underflow condition being caused by that line of code.

  25. #25
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,793


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    The
    Code:
    then DoneRotEnc
    is exactly the same as
    Code:
    then goto DoneRotEnc
    or
    Code:
    @ goto DoneRotEnc
    Or not?

    Ioannis

  26. #26
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    not to mention that mine ,same code same chip does not reboot
    Warning I'm not a teacher

  27. #27
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,793


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Then maybe a bad supply voltage, bad decoupling capacitors, bad breadboard connections...

    Ioannis

  28. #28
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    would seem that way , although his dt_ints may be altered.
    only changes i made

    latc.6 = 1 ' reversed polarity tty
    serout2 PORTC.6,84,[13,10,"I'm Alive",13,10,10]





    although code has a few weird things they don't cause the problems, if i use a nice clean optical re the code fails to count up or down as per reply 9
    a filtered mechanical re also miscounts , no filter gives a semblance of functionality. i will keep to my code



    OPTION_REG.6 = 0 ' INTEDG set to interrupt on falling edge. ?
    ' OPTION_REG.6 = 1 ' INTEDG set to interrupt on rising edge.

    IOCBN = %01110000 ; REa portb.6, REb portb.5, REsw portb.4 neg edge trigger - falling edge only.
    why set the sw to cause an interrupt
    Last edited by richard; - 12th February 2021 at 08:33.
    Warning I'm not a teacher

  29. #29
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,793


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    More responsive I suppose?

  30. #30
    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 All,

    Just had a chance to try Mike's suggestion, terminal result below, still no good.

    Code:
    Power-on: 00011001  -  00011101
    Priming PCON: 00011001  -  00011111
    
    I'm Alive
    
    RE_val 00001
    RE_val 00002
    RE_val 00003
    RE_val 00004
    RE_val 00005
    RE_val 00006
    RE_val 00007
    RE_val 00008
    RE_val 00009Power-on: 00011001  -  01011111
    Priming PCON: 00011001  -  00011111
    
    I'm Alive
    
    RE_val 00001
    @ Richard
    I take your point about using an Int for the REsw but this code is only a snippet of a much larger, intensive program and the normal scan of the switch may be delayed due other processes - hence my using an Int for the pushbutton. I have not run the full code with this problem, only what has been submitted for this very reason (isolation of where the problem lies). I have tried with and without the REsw bit, still no difference with the bug.

    @ Ioannis
    The test pcb I've been using all along (and a breadboard to confirm) runs very well when I switch to the 16F886, supply is from a well regulated 9v bench unit which then gets regulated on board to either 5v or 3v3 as needed. The RE and all peripheral components are hard soldered on the pcb.

    AFAIK I'm running the latest version of DTInts having found that out the hard way a number of weeks ago, identified by Richard (thanks again mate).

    Maybe it is time to give up on this and go with your preferred way of using a RE Richard... but I'd like to solve the mystery if possible else have that nagging doubt using 16F1788 chips with Ints.

    Cheers,
    Bill

  31. #31
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    your not trying to run chip at less than 5v ? decouple caps etc [i'm using none]
    reset is pulled high ?
    enc and sw pins are pulled high with suitable r

    i cannot get mine to fail no matter hard i try , no caps, pwr off pk4 , dupont leads on a breadboard [you can't get worse conditions]
    even using wpu is ok

    i will go out on a limb and say
    code cause 0%, isr cause 0% . other 100%

    also when breadboarding all unused pins set as i/p is a good thing
    Warning I'm not a teacher

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


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    No, 5v all the way unless the app calls for 3v3 (typically when I use a Nokia GLCD). In any case the PIC should be able to handle 3v3 at low speeds, surely?

    The pcb has bunches of decoupling caps, selectable 10k pullups (as used on the RE) and .1 caps to ground also to minimize and bounce at the source.

    Reset is pulled high via a 10k series diode combination for the ICSP requirements.

    I make unused pins output so don't need to worry about pullups as you would with inputs (else floating nightmares). I guess your wpu's take care of your inputs.

    Worse case I'll develop with the F886 (yet to try the F1938, hopefully tomorrow - I think you have one or two of these IIRC).

    What's next wise one?

    Regards,
    Grasshopper

  33. #33
    Join Date
    May 2013
    Location
    australia
    Posts
    2,379


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    no, 5v all the way unless the app calls for 3v3 (typically when I use a Nokia GLCD). In any case the PIC should be able to handle 3v3 at low speeds, surely?
    not sure , for the 16f1788 the microchip ipe with pk4 warns , 5.00 v recommended (not sure where the ldo comes into play)



    I make unused pins output so don't need to worry about pullups as you would with inputs (else floating nightmares). I guess your wpu's take care of your inputs.
    as i don't , i have never seen or heard of a pic having an adverse effect from an unused floating input. if your program is affected by an unused input then its incomplete.
    the only measurable effect is a slight increase in power consumption (you need a microamp meter to detect it). floating pin nightmares for pic chips are a myth based on other logic families with fixed i/p pin to o/p pin relationships where totem-pole outputs could be driven at prodigious rates unnecessarily to bad effect, pics are not like that.
    when breadboarding all unused pins set as i/p is a good thing, you won't damage anything with misplaced connections.
    Last edited by richard; - 12th February 2021 at 22:39.
    Warning I'm not a teacher

  34. #34


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    I just use regular polling instead of interrupts when using a pb rotary, and only increment/decrement the "true status" upon TWO successive state changes in the SAME "direction". This eliminates debouncing and does not require interrupt use and it's infallible.

    Picster

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 : 3

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